-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add docs on how to upgrade the schema of stable structures (#146)
Adds a short doc on how attributes can be added to a stable structure. Closes #109
- Loading branch information
Showing
2 changed files
with
70 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Schema Upgrades | ||
|
||
Stable structures store data directly in stable memory and do not require upgrade hooks. | ||
Since these structures are designed to persist throughout the lifetime of the canister, it's nearly inevitable that developers would want to make modifications to the data's schema as the canister evolves. | ||
|
||
Let's say you are storing assets in your canister. The declaration of it can look something like this: | ||
|
||
```rust | ||
#[derive(Serialize, Deserialize, CandidType)] | ||
struct Asset { | ||
// The contents of the asset. | ||
contents: Vec<u8>, | ||
} | ||
|
||
impl Storable for Asset { | ||
fn to_bytes(&self) -> std::borrow::Cow<[u8]> { | ||
let mut bytes = vec![]; | ||
ciborium::ser::into_writer(&self, &mut bytes).unwrap(); | ||
Cow::Owned(bytes) | ||
} | ||
|
||
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { | ||
ciborium::de::from_reader(&*bytes).expect("deserialization must succeed.") | ||
} | ||
|
||
const BOUND: Bound = Bound::Unbounded; | ||
} | ||
``` | ||
|
||
> **Note:** Stables structures do not enforce a specific data format. | ||
It's up to the developer to use the data format that fits their use-case. | ||
In this example, CBOR is used for encoding `Asset`. | ||
|
||
|
||
## Adding an attribute | ||
|
||
Adding a new field can be as simple as adding the field, like this: | ||
|
||
```rust | ||
#[derive(Serialize, Deserialize)] | ||
struct Asset { | ||
// The contents of the asset. | ||
contents: Vec<u8>, | ||
|
||
// The timestamp the asset was created at. | ||
#[serde(default)] | ||
created_at: u64, | ||
} | ||
``` | ||
|
||
If the new attribute being added doesn't have a sensible default value, consider wrapping it in an `Option`: | ||
|
||
```rust | ||
#[derive(Serialize, Deserialize, CandidType)] | ||
struct Asset { | ||
// The contents of the asset. | ||
contents: Vec<u8>, | ||
|
||
// The timestamp the asset was created at. | ||
#[serde(default)] | ||
created_at: u64, | ||
|
||
// The username of the uploader. | ||
uploaded_by: Option<String>, | ||
} | ||
``` |