Model your data
Task: store a piece of your app’s data in a field of #[app::state], and
read and write it from a method.
Every field of your state is a CRDT from calimero_storage::collections. Pick
the one whose merge behaviour matches the data — that single choice decides how
concurrent edits on different nodes converge.
Pick a collection
Section titled “Pick a collection”| You have… | Use | Import |
|---|---|---|
| A keyed map of values | UnorderedMap<K, V> | calimero_storage::collections::UnorderedMap |
| A growable list | Vector<V> | calimero_storage::collections::Vector |
| A map you iterate in key order / by range | SortedMap<K, V> | calimero_storage::collections::SortedMap |
| A count many nodes bump | Counter (grow-only) / PNCounter (also decrements) | calimero_storage::collections::Counter |
| A single value, last-writer-wins | LwwRegister<T> | calimero_storage::collections::LwwRegister |
See Collections for the full list and the exact merge rule of each.
Read and write it
Section titled “Read and write it”This is apps/kv-store — an UnorderedMap whose values are LwwRegister<String>:
use calimero_sdk::app;use calimero_storage::collections::{LwwRegister, UnorderedMap};
#[app::state]pub struct KvStore { items: UnorderedMap<String, LwwRegister<String>>,}
#[app::logic]impl KvStore { #[app::init] pub fn init() -> KvStore { KvStore { items: UnorderedMap::new() } }
// write: `value.into()` builds the LwwRegister<String> pub fn set(&mut self, key: String, value: String) -> app::Result<()> { self.items.insert(key, value.into())?; Ok(()) }
// read: `get` returns a read-only ValueRef; clone out the inner value #[app::view] pub fn get(&self, key: String) -> app::Result<Option<String>> { Ok(self.items.get(&key)?.map(|v| v.get().clone())) }}Key things the snippet shows:
- Construct fields with
::new()inside#[app::init]. - Every accessor returns a
Result— collection reads and writes can fail, so use?. gethands back a read-only reference;.get().clone()pulls the value out of theLwwRegister. To mutate in place, useget_mut.
Exercise it
Section titled “Exercise it”meroctl --node node1 call set \ --context <context-id> --args '{"key": "hello", "value": "world"}'
meroctl --node node1 call get \ --context <context-id> --args '{"key": "hello"}'Next steps
Section titled “Next steps” Collections reference Every collection type and its exact merge rule.
Storage performance & Big-O What each collection costs as your state grows.
Access-controlled storage Limit who is allowed to write a field.