Skip to content

Commit 38a8787

Browse files
committed
storage-plus: Map docs
1 parent 56ff8b9 commit 38a8787

File tree

3 files changed

+148
-4
lines changed

3 files changed

+148
-4
lines changed

docs-test-gen/templates/storage.tpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ mod imports {
44
pub use cosmwasm_schema::cw_serde;
55
}
66

7+
#[allow(unused_imports)]
78
use imports::*;
89

910
#[test]
1011
fn doctest() {
12+
#[allow(unused_mut)]
1113
let mut storage = cosmwasm_std::testing::MockStorage::new();
1214
{{code}}
1315
}

src/pages/cw-storage-plus/containers/item.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ if deserialization fails, but produce an `Ok(None)` if it is empty.
1919
More information can be found in the
2020
[API docs](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Item.html).
2121

22-
## Usage
22+
## Usage examples
2323

2424
### Saving an admin address
2525

Lines changed: 145 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,152 @@
1+
import { Callout } from "nextra/components";
2+
13
# `Map`
24

5+
A `Map` is a key-value store. Unlike the raw storage backend, the keys and
6+
values of a map are typed.
7+
8+
## Keys
9+
10+
The key type has to implement the
11+
[`PrimaryKey`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/trait.PrimaryKey.html)
12+
trait. Most commonly, the key is simply a `String` or
13+
[`Addr`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Addr.html).
14+
Other types include binary strings (`Vec<u8>`, `[u8; N]`, `&[u8]`), numerical
15+
types, or even tuples, which can be used to create composite keys.
16+
17+
## Values
18+
19+
The values, as usual, are serialized as JSON and must implement the
20+
[`Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) and
21+
[`Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html) traits.
22+
23+
## Operations
24+
25+
Similar to an [`Item`](./item), a `Map` defines methods like `load`, `save`, and
26+
`may_load`. The difference is that `Map`'s methods take a key as an argument.
27+
28+
Most _CosmWasm_-enabled chains will enable iteration. If they do, it is possible
29+
to iterate over the entries in a map using methods like
30+
[`keys`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Map.html#method.keys)
31+
or
32+
[`range`](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Map.html#method.range).
33+
334
More information can be found in the
435
[API docs](https://docs.rs/cw-storage-plus/latest/cw_storage_plus/struct.Map.html).
536

6-
## Overview
7-
8-
## Examples
37+
## Usage examples
938

1039
### Keeping users' balances
40+
41+
#### Checking a user's balance
42+
43+
```rust template="storage"
44+
use cw_storage_plus::Map;
45+
46+
let balances: Map<String, u128> = Map::new("balances");
47+
48+
let alice_balance = balances
49+
.may_load(&storage, "alice".to_string())
50+
.unwrap()
51+
.unwrap_or(0); // if the entry does not exist yet, assume the balance is 0
52+
53+
assert_eq!(alice_balance, 0);
54+
```
55+
56+
#### Updating a user's balance
57+
58+
```rust template="storage"
59+
use cw_storage_plus::Map;
60+
61+
let balances: Map<String, u128> = Map::new("balances");
62+
63+
let mut alice_balance = balances
64+
.may_load(&storage, "alice".to_string())
65+
.unwrap()
66+
.unwrap_or(0); // if the entry does not exist yet, assume the balance is 0
67+
68+
alice_balance += 100;
69+
70+
balances.save(&mut storage, "alice".to_string(), &alice_balance).unwrap();
71+
assert_eq!(balances.load(&storage, "alice".to_string()).unwrap(), 100);
72+
```
73+
74+
### Keeping users' balances with a composite key
75+
76+
#### Basic use
77+
78+
```rust template="storage"
79+
use cw_storage_plus::Map;
80+
81+
// The first string is the user's address, the second is the denomination
82+
let balances: Map<(String, String), u128> = Map::new("balances");
83+
84+
let mut alice_balance = balances
85+
.may_load(&storage, ("alice".to_string(), "uusd".to_string()))
86+
.unwrap()
87+
.unwrap_or(0); // if the entry does not exist yet, assume the balance is 0
88+
89+
alice_balance += 100;
90+
91+
balances
92+
.save(&mut storage, ("alice".to_string(), "uusd".to_string()), &alice_balance)
93+
.unwrap();
94+
95+
assert_eq!(
96+
balances
97+
.load(&storage, ("alice".to_string(), "uusd".to_string()))
98+
.unwrap(),
99+
100
100+
);
101+
```
102+
103+
#### Iterating over composite keys
104+
105+
```rust template="storage"
106+
use cw_storage_plus::Map;
107+
108+
let balances: Map<(String, String), u128> = Map::new("balances");
109+
110+
balances.save(&mut storage, ("alice".to_string(), "uusd".to_string()), &100).unwrap();
111+
balances.save(&mut storage, ("alice".to_string(), "osmo".to_string()), &200).unwrap();
112+
balances.save(&mut storage, ("bob".to_string(), "uusd".to_string()), &300).unwrap();
113+
114+
let all_balances: Vec<_> = balances
115+
.range(&storage, None, None, Order::Ascending)
116+
.collect::<Result<_, _>>()
117+
.unwrap();
118+
119+
assert_eq!(
120+
all_balances,
121+
vec![
122+
(("bob".to_string(), "uusd".to_string()), 300),
123+
(("alice".to_string(), "osmo".to_string()), 200),
124+
(("alice".to_string(), "uusd".to_string()), 100),
125+
]
126+
);
127+
128+
let alices_balances: Vec<_> = balances
129+
.prefix("alice".to_string())
130+
.range(&storage, None, None, Order::Ascending)
131+
.collect::<Result<_, _>>()
132+
.unwrap();
133+
134+
assert_eq!(alices_balances, vec![("osmo".to_string(), 200), ("uusd".to_string(), 100)]);
135+
```
136+
137+
<Callout type="warning">
138+
139+
As seen here, the order of keys isn't always lexicographic. If you need things
140+
ordered, the safe thing to do is to collect them in a vector and `sort` it.
141+
142+
If you'd rather avoid that, here's how things work: under the hood, every
143+
component of a composite key is length-prefixed except for the last one. If
144+
you're only iterating over the last component, you can expect things to be
145+
ordered lexicographically. For non-final components, shorter strings will always
146+
come before longer ones.
147+
148+
In the example, note how "bob" (a non-last component) comes before `"alice"`.
149+
Also note how once we lock the first component to `"alice"`, entries are ordered
150+
lexicographically by the second component.
151+
152+
</Callout>

0 commit comments

Comments
 (0)