Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Links, paths, and anchors #453

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .cspell/custom-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Kleppmann
NixOS
nixpkgs
pkgs
pubkey
QUIC
rustc
rustflags
Expand Down
2 changes: 2 additions & 0 deletions src/pages/_data/navigation/mainNav.json5
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
},
{ title: "Build", url: "/build/", children: [
{ title: "Working with Data", url: "/build/working-with-data/", children: [
{ title: "Identifiers", url: "/build/identifiers/" },
{ title: "Entries", url: "/build/entries/" },
{ title: "Links, Paths, and Anchors", url: "/build/links-paths-and-anchors/" },
]},
]
},
Expand Down
42 changes: 23 additions & 19 deletions src/pages/build/entries.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ An entry is always paired with an **entry creation action** that tells you who a

The pairing of an entry and the action that created it is called a **record**, which is the basic unit of data in a Holochain application.

## Scaffold an entry type and CRUD API

The Holochain dev tool command `hc scaffold entry-type <entry_type>` generates the code for a simple entry type and a CRUD API. It presents an interface that lets you define a struct and its fields, then asks you to choose whether to implement update and delete functions for it along with the default create and read functions.

## Define an entry type

Each entry has a **type**, which your application code uses to make sense of the entry's bytes. Our [HDI library](https://docs.rs/hdi/latest/hdi/) gives you macros to automatically define, serialize, and deserialize entry types to and from any Rust struct or enum that [`serde`](https://docs.rs/serde/latest/serde/) can handle.
Each entry has a **type**. This lets your application make sense of what would otherwise be a blob of arbitrary bytes. Our [HDI library](https://docs.rs/hdi/latest/hdi/) gives you macros to automatically define, serialize, and deserialize typed entries to and from any Rust struct or enum that [`serde`](https://docs.rs/serde/latest/serde/) can handle.

Entry types are defined in an [**integrity zome**](/resources/glossary/#integrity-zome). To define an [`EntryType`](https://docs.rs/hdi/latest/hdi/prelude/enum.EntryType.html), use the [`hdi::prelude::hdk_entry_helper`](https://docs.rs/hdi/latest/hdi/prelude/attr.hdk_entry_helper.html) macro on your Rust type:

Expand All @@ -27,7 +31,7 @@ use hdi::prelude::*;
#[hdk_entry_helper]
pub struct Movie {
title: String,
director: String,
director_hash: EntryHash,
imdb_id: Option<String>,
release_date: Timestamp,
box_office_revenue: u128,
Expand All @@ -42,13 +46,18 @@ In order to dispatch validation to the proper integrity zome, Holochain needs to
use hdi::prelude::*;

#[hdk_entry_defs]
#[unit_enum(UnitEntryTypes)]
enum EntryTypes {
Movie(Movie),
// other types...
}
```

### Configuring an entry type
This also gives you an enum that you can use later when you're storing app data. This is important because, under the hood, an entry type consists of two bytes --- an integrity zome index and an entry def index. These are required whenever you want to write an entry. Instead of having to remember those values every time you store something, your coordinator zome can just import and use this enum, which already knows how to convert each entry type to the right IDs.

The code sample above also uses a macro called `unit_enum`, which will generate an enum of all the entry types' names _without_ places to store values.

### Configure an entry type

Each variant in the enum should hold the Rust type that corresponds to it, and is implicitly marked with an `entry_def` proc macro which, if you specify it explicitly, lets you configure the given entry type further:

Expand All @@ -59,6 +68,7 @@ Each variant in the enum should hold the Rust type that corresponds to it, and i
use hdi::prelude::*;

#[hdk_entry_defs]
#[unit_enum(UnitEntryTypes)]
enum EntryTypes {
#[entry_def(required_validations = 7, )]
Movie(Movie),
Expand All @@ -72,13 +82,11 @@ enum EntryTypes {
}
```

This also gives you an enum that you can use later when you're storing app data. This is important because, under the hood, an entry type consists of two bytes -- an integrity zome index and an entry def index. These are required whenever you want to write an entry. Instead of having to remember those values every time you store something, your coordinator zome can just import and use this enum, which already knows how to convert each entry type to the right IDs.

## Create an entry

Most of the time you'll want to define your create, read, update, and delete (CRUD) functions in a [**coordinator zome**](/resources/glossary/#coordinator-zome) rather than the integrity zome that defines it. This is because a coordinator zome is easier to update in the wild than an integrity zome.

Create an entry by calling [`hdk::prelude::create_entry`](https://docs.rs/hdk/latest/hdk/prelude/fn.create_entry.html). If you used `hdk_entry_helper` and `hdk_entry_defs` macro in your integrity zome (see [Define an entry type](#define-an-entry-type)), you can use the entry types enum you defined, and the entry will be serialized and have the correct integrity zome and entry type indexes added to it.
Create an entry by calling [`hdk::prelude::create_entry`](https://docs.rs/hdk/latest/hdk/entry/fn.create_entry.html). If you used `hdk_entry_helper` and `hdk_entry_defs` macro in your integrity zome (see [Define an entry type](#define-an-entry-type)), you can use the entry types enum you defined, and the entry will be serialized and have the correct integrity zome and entry type indexes added to it.

```rust
use hdk::prelude::*;
Expand All @@ -88,7 +96,7 @@ use movie_integrity::*;

let movie = Movie {
title: "The Good, the Bad, and the Ugly",
director: "Sergio Leone"
director_hash: EntryHash::from_raw_36(vec![ /* hash of 'Sergio Leone' entry */ ]),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be useful to also show how to get /* hash of 'Sergio Leone' entry */, or is this covered elsewhere in the guide?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, there's a section on it elsewhere, although it's a bit long-winded. I might make it into its own article.

imdb_id: Some("tt0060196"),
release_date: Timestamp::from(Date::Utc("1966-12-23")),
box_office_revenue: 389_000_000,
Expand Down Expand Up @@ -222,7 +230,7 @@ let delete_action_hash: ActionHash = delete_entry(
)?;
```

As with an update, this does _not_ actually remove data from the source chain or the DHT. Instead, a [`Delete` action](https://docs.rs/holochain_integrity_types/latest/holochain_integrity_types/action/struct.Delete.html) is authored, which attaches to the entry creation action and marks it as 'dead'. An entry itself is only considered dead when all entry creation actions that created it are marked dead, and it can become live again in the future if a _new_ entry creation action writes it. Dead data can still be retrieved with [`hdk::prelude::get_details`](https://docs.rs/hdk/latest/hdk/prelude/fn.get_details.html) (see below).
As with an update, this does _not_ actually remove data from the source chain or the DHT. Instead, a [`Delete` action](https://docs.rs/holochain_integrity_types/latest/holochain_integrity_types/action/struct.Delete.html) is authored, which attaches to the entry creation action and marks it as deleted. An entry itself is only considered deleted when _all_ entry creation actions that created it are marked deleted, and it can become live again in the future if a _new_ entry creation action writes it. Deleted data can still be retrieved with [`hdk::prelude::get_details`](https://docs.rs/hdk/latest/hdk/prelude/fn.get_details.html) (see below).

In the future we plan to include a 'purge' functionality. This will give agents permission to actually erase an entry from their DHT store, but not its associated entry creation action.

Expand Down Expand Up @@ -374,26 +382,22 @@ match maybe_details {
}
```

## Scaffolding an entry type and CRUD API

The Holochain dev tool command `hc scaffold entry-type <entry_type>` generates the code for a simple entry type and a CRUD API. It presents an interface that lets you define a struct and its fields, then asks you to choose whether to implement update and delete functions for it along with the default create and read functions.

## Community CRUD libraries

If the scaffolder doesn't support your desired functionality, or is too low-level, there are some community-maintained libraries that offer opinionated and high-level ways to work with entries. Some of them also offer permissions management.
There are some community-maintained libraries that offer opinionated and high-level ways to work with entries. Some of them also offer permissions management.

* [rust-hc-crud-caps](https://github.com/spartan-holochain-counsel/rust-hc-crud-caps)
* [hdk_crud](https://github.com/lightningrodlabs/hdk_crud)
* [hc-cooperative-content](https://github.com/mjbrisebois/hc-cooperative-content)

## Reference

* [hdi::prelude::hdk_entry_helper](https://docs.rs/hdi/latest/hdi/attr.hdk_entry_helper.html)
* [hdi::prelude::hdk_entry_defs](https://docs.rs/hdi/latest/hdi/prelude/attr.hdk_entry_defs.html)
* [hdi::prelude::entry_def](https://docs.rs/hdi/latest/hdi/prelude/entry_def/index.html)
* [hdk::prelude::create_entry](https://docs.rs/hdk/latest/hdk/entry/fn.create_entry.html)
* [hdk::prelude::update_entry](https://docs.rs/hdk/latest/hdk/entry/fn.update_entry.html)
* [hdi::prelude::delete_entry](https://docs.rs/hdk/latest/hdk/entry/fn.delete_entry.html)
* [`hdi::prelude::hdk_entry_helper`](https://docs.rs/hdi/latest/hdi/attr.hdk_entry_helper.html)
* [`hdi::prelude::hdk_entry_defs`](https://docs.rs/hdi/latest/hdi/prelude/attr.hdk_entry_defs.html)
* [`hdi::prelude::entry_def`](https://docs.rs/hdi/latest/hdi/prelude/entry_def/index.html)
* [`hdk::prelude::create_entry`](https://docs.rs/hdk/latest/hdk/entry/fn.create_entry.html)
* [`hdk::prelude::update_entry`](https://docs.rs/hdk/latest/hdk/entry/fn.update_entry.html)
* [`hdi::prelude::delete_entry`](https://docs.rs/hdk/latest/hdk/entry/fn.delete_entry.html)

## Further reading

Expand Down
Loading
Loading