forked from holochain-immersive/holochain-lesson-2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
666 lines (558 loc) · 28.1 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<meta name="Description" content="Put your description here." />
<base href="/" />
<style>
html,
body {
margin: 0;
padding: 0;
font-family: sans-serif;
background-color: #ededed;
--r-main-font-size: 24px;
--r-heading-margin: 20px 0 12px 0;
}
.slides {
width: 75% !important;
}
.container {
top: 0 !important;
display: flex !important;
flex-direction: row !important;
}
.column {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
}
ul {
width: 100%;
}
section {
text-align: left;
}
.popover {
position: absolute;
background-color: #4d4d4d;
padding: 1rem 2rem;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
border-radius: 10px;
width: auto;
transform: translate(16px, -15px);
max-width: 600px;
white-space: break-spaces;
}
.popover:after {
content: "";
position: absolute;
top: 6px;
left: -8px;
border-style: solid;
border-width: 18px 12px 0;
border-color: #4d4d4d transparent;
display: block;
width: 0;
z-index: 1;
transform: translate(-50%, 50%) rotate(90deg);
}
.popover .hljs-meta,
.popover .hljs-class,
.popover .hljs-keyword,
.popover .hljs-symbol,
.popover .hljs-string,
.popover .hljs-title {
color: rgb(221, 221, 221) !important;
font-weight: normal;
}
.hljs-keyword {
color: #817eed !important;
}
.hljs-literal {
color: #ff90b8 !important;
}
.reveal pre code {
max-height: 800px !important;
}
.dna {
background-color: green;
}
.zome {
background-color: blue;
}
.coordinator-zomes {
background-color: lightblue;
}
.dna,
.cell,
.zome,
.coordinator-zomes,
.source-chain,
.happ-bundle,
.box,
.dna-bundle,
.dht-shard,
.conductor,
.happ {
display: flex;
align-items: center;
justify-content: center;
padding: 12px;
border-width: 3px;
border-color: rgb(209, 209, 209);
border-style: solid;
}
</style>
<link rel="stylesheet" href="/node_modules/reveal.js/dist/reveal.css" />
<link
rel="stylesheet"
href="/node_modules/reveal.js/dist/theme/black.css"
/>
<link
rel="stylesheet"
href="/node_modules/reveal.js/plugin/highlight/monokai.css"
/>
<title>Holochain Lesson 2</title>
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>HDK: basic functions</h1>
</section>
<section language="markdown" animate="by-line with-ancestry">
### HDK & HDI
- Holochain Development Kit (HDK)
- To create a coordinator zome, create a rust crate that depends on the HDK and compile it
- Allows to define zome functions that can be called from outside the
zome
- Docs at https://docs.rs/hdk
- Holochain Deterministic Integrity (HDI)
- Subset of the HDK to build integrity zomes
- Only types that deal with validation rules and entry definitions
- Docs at https://docs.rs/hdi
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Defining Zome Functions: Exposure
</fragment>
<fragment animate="balanced separate-comments by-line with-ancestry">
<pre
class="fragment fade-in"
><code class="rust" data-noescape>
use hdk::prelude::*;
#[hdk_extern] <span class="fragment fade-in-then-out popover"><li class="fragment fade-in-then-semi-out">Comes from hdk::prelude::*</li><li class="fragment fade-in-then-semi-out">Exposes a function to be callable</li><li class="fragment fade-in-then-semi-out">Zome function name must be unique in this zome</li></span> // Exposes a function to be callable from the outside
fn zome_function_hello(name: String<span class="fragment fade-in-then-out popover">Zome functions can only accept one parameter</span>) -> ExternResult<String><span class="fragment fade-in-then-out popover">Must return an "ExternResult<T>"</span> {
Ok(format!("hello {}!", name))
}
#[hdk_extern]
fn zome_function_hello_world(_: ()<span class="fragment fade-in-then-out popover">To indicate disregard for input parameter, we use the Unit type</span>) -> ExternResult<String> { // () denotes no input params
Ok(format!("hello world!"))
}
</code
></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Defining Zome Functions: Custom Inputs
</fragment>
<fragment animate="balanced separate-comments by-line with-ancestry">
<pre
class="fragment fade-in"
><code class="rust" data-noescape>
use hdk::prelude::*;
// We can define custom input parameter structs
#[derive(Serialize, Deserialize, Debug)]<span class="fragment fade-in-then-out popover">Input parameters must derive "Serialize", "Deserialize" and "Debug"</span>
struct CustomInputStruct {
name: String
}
#[hdk_extern]
fn zome_function_with_custom_input(input: CustomInputStruct) -> ExternResult<String> { // Ok
Ok(format!("hello {}!", input.name))
}
struct BrokenInputStruct {<span class="fragment fade-in-then-out popover">This input struct wont work, because it doesn't derive the right traits</span>
name: String
}
#[hdk_extern]
fn zome_function_with_broken_custom_input(<span class="fragment strike">input: BrokenInputStruct</span><span class="fragment fade-in-then-out popover">Input parameters must derive "Serialize", "Deserialize" and "Debug"</span>) -> ExternResult<String> {
// Err! Doesn't derive "Serialize", "Deserialize" and "Debug"
Ok(format!("hello {}!", input.name))
}
</code
></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Defining Zome Functions: Capturing Debugging Data
- You'll need to use the `wasm_error!()` macro to return errors.
- You'll need to use `.map_err(|err| wasm_error!(err))` for some HDK function calls.
- You can use `error!()` or `warn!()` in your zome functions to log to the terminal console.
</fragment>
<fragment animate="balanced separate-comments by-line with-ancestry">
<pre
class="fragment fade-in"
><code class="rust" data-noescape>
use hdk::prelude::*;
#[hdk_extern]
fn returning_errors(_: ()) -> ExternResult<()> {
Err(wasm_error!(WasmErrorInner::Guest(<span class="fragment fade-in-then-out popover">Captures debugging information (eg. line numbers)</span>String::from("This function returns an error")))) // Captures debug info
}
#[derive(Serialize, Deserialize, Debug)]
struct DebuggingInput {
some_field_name: String
}
#[hdk_extern]
fn debugging(input: DebuggingInput) -> ExternResult<()> {
error!("This is an error log that functions just like println");
warn!("This is a warn log that functions just like println");
Ok(())
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Retrieving Static Cell Information
</fragment>
<fragment animate="balanced separate-comments by-line with-ancestry">
<pre
class="fragment fade-in"
><code class="rust" data-noescape>
use hdk::prelude::*;
#[hdk_extern]
fn get_my_pub_key(_: ()) -> ExternResult<AgentPubKey><span class="fragment fade-in-then-out popover">Acts as the "agent ID"</span> {
let my_agent_info = agent_info()?;<span class="fragment fade-in-then-out popover">Will return a different value depending on which cell is executing the function</span> // Depends on which cell is executing this function
let my_pub_key: AgentPubKey = my_agent_info.agent_initial_pubkey;<span class="fragment fade-in-then-out popover">"agent_initial_pubkey": In the future the public key of a cell may change </span>
Ok(my_pub_key)
}
#[hdk_extern]
fn get_zome_name(_: ()) -> ExternResult<ZomeName><span class="fragment fade-in-then-out popover">A simple struct wrapping a String</span> {
let my_zome_info = zome_info()?;<span class="fragment fade-in-then-out popover">Will return a different value depending on which zome this function is defined within, but will return the same for all agents</span> // Depends on which zome is the function defined
let zome_name: ZomeName = my_zome_info.name;<span class="fragment fade-in-then-out popover">Human readable name, defined in the DNA manifest</span> // Human readable name
let zome_id: ZomeId = my_zome_info.id;<span class="fragment fade-in-then-out popover">Zome index in the DNA that Holochain uses to identify the zome </span> // Zome index (integer)
Ok(zome_name)
}
#[hdk_extern]
fn get_dna_hash(_: ()) -> ExternResult<DnaHash> {
let my_dna_info = dna_info()?;<span class="fragment fade-in-then-out popover">Will return the same value for all agents and zomes in the same DNA</span> // Will return the same value for all agents and zomes in the same DNA
let dna_name: String = my_dna_info.name;<span class="fragment fade-in-then-out popover">Human readable name, defined in the DNA manifest</span> // Human readable name
let dna_hash: DnaHash = my_dna_info.hash;<span class="fragment fade-in-then-out popover">Hash of source code, Network Seed and properties </span> // Hash of source code, UID and properties
let dna_properties = my_dna_info.properties;<span class="fragment fade-in-then-out popover">Properties: configuration that the DNA can read to modify it's behaviour </span> // Properties of the DNA
let admin_pub_key = AgentPubKey::try_from(dna_properties<span class="fragment fade-in-then-out popover">'dna_properties' is of type 'SerializedBytes', so it can serialize to any rust type that derives 'Serialize' and 'Deserialize'</span>)?; // Decoding the properties
Ok(dna_hash)
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Defining An Entry Type
- Defines the format for a particular type of entry
- Can only be done in an integrity zome
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>// zomes/integrity/lib.rs
use hdi::prelude::*;
#[hdk_entry_helper]<span class="fragment popover fade-in-then-out">Adds necessary trait implementations</span> // Adds necessary trait implementations
struct Comment {
comment: String
}
#[hdk_entry_helper]
struct Post {
title: String,
content: String
}
#[hdk_entry_defs]<span class="fragment popover fade-in-then-out"><li class="fragment fade-in-then-semi-out">Defines all the entries for this zome</li><li class="fragment fade-in-then-semi-out">Must be the only "#[hdk_entry_def]" in the zome</li><li class="fragment fade-in-then-semi-out">Can only be defined in integrity zomes</li></span> // Defines all the entries for the zome
#[unit_enum(UnitEntryTypes)]<span class="fragment popover fade-in-then-out">Defines a "UnitEntryTypes" enum that's a copy of "EntryTypes" but with the converted variants to unit variants (no payload) </span> // Redefines the "EntryTypes" enum but with unit variants
enum EntryTypes { // Enum with each entry type as a variant
#[entry_def<span class="fragment popover fade-in-then-out">Configure entry behaviour</span>(name = "comment", visibility = "private"<span class="fragment fade-in-then-out popover"><li class="fragment fade-in-then-semi-out">Comments won't be published to the DHT</li><li class="fragment fade-in">Only stored privately in the source chain</li></span>)] // Configure entry behaviour
Comment(Comment),<span class="fragment fade-in-then-out popover">#[entry_def] can be omitted, but defaults to the struct name in snake_case and visibility "public"</span>// defaults to name = "post", visibility = "public"
Post(Post),
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Actions
#### Overview
- These are actions you can take on your Holochain app's state machine, stored in the app's DHT
- Includes actions like create, update, delete
- Can be done in an integrity zome or in a coordinator zome
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Actions
#### create_entry()
- Issues a notice to the DHT to record the creation of a new entry node for some given type
- Records both the details of the entry itself, and a create action, which describes a claim to having "created" that entry
- In the merkle tree, a create action branches directly from an entry itself
- If the submitted entry already can already be found in the DHT, then only the create action is added (since there can be no duplicates in a content-addressed DHT)
- There can be any number of create actions added to the DHT, all claiming to have created the same entry
- The create actions may contradict one another (for example, by claiming different authors of the entry)
- It's up to the application code to interpret the full set of discoverable actions, and determine a single, well-believed world state
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Actions
#### create_entry()
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn basic_comment_creation(comment: Comment) -> ExternResult<()> {
create_entry(<span class="fragment fade-in-then-out popover">Comes from hdk::prelude::*;</span>EntryTypes::Comment(comment)<span class="fragment fade-in-then-out popover">Input must be an instance of the entry types enumerable</span>)?; // Input must be an instance of the entry types enum
Ok(())
}
#[hdk_extern]
fn create_comment_and_return_action_hash(comment: Comment) -> ExternResult<ActionHash> {
let action_hash = create_entry(EntryTypes::Comment(comment))?;<span class="fragment fade-in-then-out popover">create_entry() returns the hash of the action that has just been inserted into the agent's source chain</span> // Returns the hash of the resulting action
Ok(action_hash)
}
</code
></pre>
</fragment>
</section>
<section >
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Actions
#### update_entry()
- Records a modification submitted on an entry, downstream of that entry's initial create action
- An update action must be issued as a child of some other action
- Can be the child of either a create action, or of another pre-existing update action
- After adding an update, The original entry will still exist in the DHT
- And so will all of that entry's downstream create and update actions
- One create or update action may have any number of child update actions added under it
- In this way, a set of update actions can form a merkle chain of compatible updates to one entry
- Furthermore, a set of update actions might branch to form a tree of incompatible update chains
- It's up to the application code to interpret the full set of discoverable actions, and determine a single well-believed world state
- An update action cannot branch directly from an entry itself
- This is because, for any given entry, there may be several valid create and update actions all descended from that one entry
- Attempting to attach an update directly to an entry would require deciding which of the valid action chains you wanted to append the new update action to
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Actions
#### update_entry()
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[derive(Serialize, Deserialize, Debug)]
pub struct UpdateCommentInput {
original_action_hash: ActionHash,
new_comment: Comment
}
#[hdk_extern]
fn update_comment(input: UpdateCommentInput) -> ExternResult<ActionHash> {
let action_hash = update_entry(input.original_action_hash<span class="fragment popover fade-in-then-out">The original comment action can be a create or an update</span>, input.new_comment<span class="fragment popover fade-in-then-out">Entry must be of the same type</span>)?;
Ok(action_hash)
}
</code
></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Actions</h3>
#### delete_entry()
- Must be scoped to an action, not an entry
- Deleted entry and action will still exist in the DHT after deleting
- We are just marking them as "deleted"
- One action may be deleted multiple times
- It's up to the application to interpret what "deleting an action" means
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn delete_comment(comment_action_hash: ActionHash) -> ExternResult<()> {
let action_hash =<span class="fragment popover fade-in-then-out">Deleting an entry is also its own action</span> delete_entry(comment_action_hash<span class="fragment popover fade-in-then-out">The original comment action can be a create or an update</span>)?; // Deleted action hash must be a create or an update action
Ok(())
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Retrievals
#### Overview
- Read requests issued to the DHT
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Retrievals
#### get()
- Given an entry hash or an action hash, return the "Record" that hashes to that hash
- Record is the union of the action and optionally its accompanying entry
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre>
<code class="rust" data-noescape>
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_comment(comment_action_hash: ActionHash) -> ExternResult<Option<Record>> {
let comment_record: Option<Record> = get(comment_action_hash<span class="fragment popover fade-in-then-out">Accepts an "ActionHash" or an "EntryHash"</span>, GetOptions::default()<span class="fragment fade-in-then-out popover">Cache control, by default return cached records</span>)?;
Ok(comment_record)
}
</code
>
</pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Entry Retrievals
#### get_details()
- Given an entry hash, return the entry and all the actions that have created, updated or deleted any action pointing to that entry
- Given an action hash, return the entry, the action and all the actions that have updated or deleted that action
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_comment_action_details(comment_action_hash: ActionHash) -> ExternResult<Record> {
let record_details: Option<Details> = get_details(comment_action_hash<span class="fragment popover fade-in-then-out">Accepts an "ActionHash" or an "EntryHash"</span>, GetOptions::default()<span class="fragment fade-in-then-out popover">Same options as "get()"</span>)?;
match record_details {
Some(Details::Record(RecordDetails { record, deletes, updates, .. })) => Ok(record),
_ => Err(wasm_error!(WasmErrorInner::Guest(String::from("Error trying to get the details of this action"))))
}
}
#[hdk_extern]
fn get_comment_entry_details(comment_entry_hash: EntryHash) -> ExternResult<Entry> {
let entry_details: Option<Details> = get_details(comment_entry_hash<span class="fragment popover fade-in-then-out">Accepts an "ActionHash" or an "EntryHash"</span>, GetOptions::default()<span class="fragment fade-in-then-out popover">Same options as "get()"</span>)?;
match entry_details {
Some(Details::Entry(EntryDetails { entry, actions, deletes, updates, .. })) => Ok(entry),
_ => Err(wasm_error!(WasmErrorInner::Guest(String::from("Error trying to get the details of this action"))))
}
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Links
- Linking from one hash to another, with some optional metadata
- Link components:
- Base hash: can be public key, entry hash, action hash or
external hash (the hash doesn't exist in this DHT)
- Target hash: can be of the same types as the base hash
- Type: app defined link type
- Tag: app defined arbitrary metadata
- Neither the base nor the target hash need to exist as actions or entries in the DHT
- Defining link types
- Only in integrity zomes
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>// zomes/integrity/lib.rs
use hdi::prelude::*;
// Defining link types
#[hdk_link_types]<span class="fragment popover fade-in-then-out"><li class="fragment fade-in-then-semi-out">Defines all the link types for this zome</li><li class="fragment fade-in-then-semi-out">Must be the only "#[hdk_link_types]" in the zome</li><li class="fragment fade-in-then-semi-out">Can only be defined in integrity zomes</li></span> // Defines all the link types for the zome
enum LinkTypes { // Enum with each entry type as a variant
AuthorToComment,<span class="fragment fade-in-then-out popover">Must be a Unit variant (without any payload) </span>
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Link Actions
#### create_link()
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>
// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{LinkTypes, EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn create_comment(comment: Comment) -> ExternResult<ActionHash> {
let comment_action_hash = create_entry(EntryTypes::Comment(comment))?; // Create comment as always
let my_pub_key: AgentPubKey = agent_info()?.agent_initial_pubkey; <span class="fragment fade-in-then-out popover">The author of the comment is the agent executing this function call</span>
let create_link_action_hash: ActionHash<span class="fragment fade-in-then-out popover">Creating a link is an action in itself</span> = create_link(
my_pub_key, <span class="fragment fade-in-then-out popover">Base hash: my agent pub key</span>// Base hash
comment_action_hash, <span class="fragment fade-in-then-out popover">Target hash: the action hash that has just been created</span>// Target hash
LinkTypes::AuthorToComment, <span class="fragment fade-in-then-out popover">LinkType: one of the variants defined in the integrity zome</span>// Link Type
()<span class="fragment fade-in-then-out popover">Link tag, can be any struct that derives 'Serialized' and 'Deserialized'</span> // Link tag
)?;
Ok(comment_action_hash)
}
</code></pre>
</fragment>
</section>
<section>
<fragment language="markdown" animate="by-line with-ancestry">
### Link Retrievals
#### get_links()
- Links are attached to the base hash
- You can retrieve all the links attached to a given hash as a base
</fragment>
<fragment animate="by-line with-ancestry balanced separate-comments">
<pre><code class="rust" data-noescape>// zomes/coordinator/lib.rs
use hdk::prelude::*;
use integrity_zome::{LinkTypes, EntryTypes, Comment}; // Import the types defined in our integrity zome
#[hdk_extern]
fn get_all_comments_by_agent(author: AgentPubKey) -> ExternResult<Vec<Record>> {
let links: Vec<Link> = get_links(
author, <span class="fragment fade-in-then-out popover">Base hash: the given agent pub key</span> // Base hash
LinkTypes::AuthorToComment, <span class="fragment fade-in-then-out popover">LinkType: one of the variants defined in the integrity zome</span> // Link Type
None, <span class="fragment fade-in-then-out popover">"Option<LinkTag>": prefix filter on link tag, if this has some tag starts with the given tag as their prefix will be returned </span> // Filter on link tag prefix
)?;
let mut comments: Vec<Record> = vec![];
for link in links {
let maybe_record = get(ActionHash::from<span class="fragment fade-in-then-out popover">Conversion is important to specify the type of hash we are retrieving for</span>(link.target)<span class="fragment fade-in-then-out popover">Will be the action hash for each of the comments that the agent has created</span>, GetOptions::default())?;
if let Some(record) = maybe_record {
comments.push(record);
}
}
Ok(comments)
}
</code></pre>
</fragment>
</section>
</div>
</div>
<script type="module">
import Reveal from "reveal.js";
import Markdown from "reveal.js/plugin/markdown/markdown.esm.js";
import RevealHighlight from "reveal.js/plugin/highlight/highlight.esm.js";
import RevealNotes from "reveal.js/plugin/notes/notes.esm.js";
import RevealAnimateFragments from "reveal.js-animate-fragments";
import RevealEliminateEmptyLines from "reveal.js-eliminate-empty-lines";
let deck = new Reveal({
transition: "none",
plugins: [
Markdown,
RevealHighlight,
RevealNotes,
RevealEliminateEmptyLines,
RevealAnimateFragments
],
});
deck.initialize();
</script>
</body>
</html>