{"id":13566115,"url":"https://github.com/CosmWasm/cw-storage-plus","last_synced_at":"2025-04-03T23:31:06.413Z","repository":{"id":61681354,"uuid":"552928286","full_name":"CosmWasm/cw-storage-plus","owner":"CosmWasm","description":"Storage abstractions for CosmWasm smart contracts","archived":false,"fork":false,"pushed_at":"2025-03-15T18:26:19.000Z","size":1209,"stargazers_count":38,"open_issues_count":26,"forks_count":29,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-25T09:08:12.289Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CosmWasm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-17T12:54:05.000Z","updated_at":"2025-03-15T18:26:21.000Z","dependencies_parsed_at":"2024-06-19T12:10:36.502Z","dependency_job_id":"84a82829-29bc-470a-8fe5-d19e5efd9f84","html_url":"https://github.com/CosmWasm/cw-storage-plus","commit_stats":{"total_commits":832,"total_committers":24,"mean_commits":"34.666666666666664","dds":0.5372596153846154,"last_synced_commit":"738d10c505918e1de3e9b6c2b5424fc7ae67885b"},"previous_names":[],"tags_count":65,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fcw-storage-plus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fcw-storage-plus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fcw-storage-plus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fcw-storage-plus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CosmWasm","download_url":"https://codeload.github.com/CosmWasm/cw-storage-plus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246479789,"owners_count":20784386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T13:02:02.414Z","updated_at":"2025-04-03T23:31:04.838Z","avatar_url":"https://github.com/CosmWasm.png","language":"Rust","funding_links":[],"categories":["CosmWasm Framework","Rust"],"sub_categories":[],"readme":"# `cw-storage-plus`: Storage abstractions for CosmWasm\n\nThis has been heavily used in many production-quality contracts.\nThe code has demonstrated itself to be stable and powerful.\nIt has not been audited, and Confio assumes no liability, but we consider it mature enough\nto be the **standard storage layer** for your contracts.\n\n## Usage Overview\n\nWe introduce two main classes to provide a productive abstraction\non top of `cosmwasm_std::Storage`. They are `Item`, which is\na typed wrapper around one database key, providing some helper functions\nfor interacting with it without dealing with raw bytes. And `Map`,\nwhich allows you to store multiple unique typed objects under a prefix,\nindexed by a simple or compound (eg. `(\u0026[u8], \u0026[u8])`) primary key.\n\n## Item\n\nThe usage of an [`Item`](./src/item.rs) is pretty straight-forward.\nYou must simply provide the proper type, as well as a database key not\nused by any other item. Then it will provide you with a nice interface\nto interact with such data.\n\nIf you are coming from using `Singleton`, the biggest change is that\nwe no longer store `Storage` inside, meaning we don't need read and write\nvariants of the object, just one type. Furthermore, we use `const fn`\nto create the `Item`, allowing it to be defined as a global compile-time\nconstant rather than a function that must be constructed each time,\nwhich saves gas as well as typing.\n\nExample Usage:\n\n```rust\n#[derive(Serialize, Deserialize, PartialEq, Debug)]\nstruct Config {\n    pub owner: String,\n    pub max_tokens: i32,\n}\n\n// note const constructor rather than 2 functions with Singleton\nconst CONFIG: Item\u003cConfig\u003e = Item::new(\"config\");\n\nfn demo() -\u003e StdResult\u003c()\u003e {\n    let mut store = MockStorage::new();\n\n    // may_load returns Option\u003cT\u003e, so None if data is missing\n    // load returns T and Err(StdError::NotFound{}) if data is missing\n    let empty = CONFIG.may_load(\u0026store)?;\n    assert_eq!(None, empty);\n    let cfg = Config {\n        owner: \"admin\".to_string(),\n        max_tokens: 1234,\n    };\n    CONFIG.save(\u0026mut store, \u0026cfg)?;\n    let loaded = CONFIG.load(\u0026store)?;\n    assert_eq!(cfg, loaded);\n\n    // update an item with a closure (includes read and write)\n    // returns the newly saved value\n    let output = CONFIG.update(\u0026mut store, |mut c| -\u003e StdResult\u003c_\u003e {\n        c.max_tokens *= 2;\n        Ok(c)\n    })?;\n    assert_eq!(2468, output.max_tokens);\n\n    // you can error in an update and nothing is saved\n    let failed = CONFIG.update(\u0026mut store, |_| -\u003e StdResult\u003c_\u003e {\n        Err(StdError::generic_err(\"failure mode\"))\n    });\n    assert!(failed.is_err());\n\n    // loading data will show the first update was saved\n    let loaded = CONFIG.load(\u0026store)?;\n    let expected = Config {\n        owner: \"admin\".to_string(),\n        max_tokens: 2468,\n    };\n    assert_eq!(expected, loaded);\n\n    // we can remove data as well\n    CONFIG.remove(\u0026mut store);\n    let empty = CONFIG.may_load(\u0026store)?;\n    assert_eq!(None, empty);\n\n    Ok(())\n}\n```\n\n## Map\n\nThe usage of a [`Map`](./src/map.rs) is a little more complex, but\nis still pretty straight-forward. You can imagine it as a storage-backed\n`BTreeMap`, allowing key-value lookups with typed values. In addition,\nwe support not only simple binary keys (like `\u0026[u8]`), but tuples, which are\ncombined. This allows us by example to store allowances as composite keys,\ni.e. `(owner, spender)` to look up the balance.\n\nBeyond direct lookups, we have a super-power not found in Ethereum -\niteration. That's right, you can list all items in a `Map`, or only\npart of them. We can efficiently allow pagination over these items as\nwell, starting at the point the last query ended, with low gas costs.\nThis requires the `iterator` feature to be enabled in `cw-storage-plus`\n(which automatically enables it in `cosmwasm-std` as well, and which is\nenabled by default).\n\nIf you are coming from using `Bucket`, the biggest change is that\nwe no longer store `Storage` inside, meaning we don't need read and write\nvariants of the object, just one type. Furthermore, we use `const fn`\nto create the `Bucket`, allowing it to be defined as a global compile-time\nconstant rather than a function that must be constructed each time,\nwhich saves gas as well as typing. In addition, the composite indexes\n(tuples) are more ergonomic and expressive of intention, and the range\ninterface has been improved.\n\nHere is an example with normal (simple) keys:\n\n```rust\n#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]\nstruct Data {\n    pub name: String,\n    pub age: i32,\n}\n\nconst PEOPLE: Map\u003c\u0026str, Data\u003e = Map::new(\"people\");\n\nfn demo() -\u003e StdResult\u003c()\u003e {\n    let mut store = MockStorage::new();\n    let data = Data {\n        name: \"John\".to_string(),\n        age: 32,\n    };\n\n    // load and save with extra key argument\n    let empty = PEOPLE.may_load(\u0026store, \"john\")?;\n    assert_eq!(None, empty);\n    PEOPLE.save(\u0026mut store, \"john\", \u0026data)?;\n    let loaded = PEOPLE.load(\u0026store, \"john\")?;\n    assert_eq!(data, loaded);\n\n    // nothing on another key\n    let missing = PEOPLE.may_load(\u0026store, \"jack\")?;\n    assert_eq!(None, missing);\n\n    // update function for new or existing keys\n    let birthday = |d: Option\u003cData\u003e| -\u003e StdResult\u003cData\u003e {\n        match d {\n            Some(one) =\u003e Ok(Data {\n                name: one.name,\n                age: one.age + 1,\n            }),\n            None =\u003e Ok(Data {\n                name: \"Newborn\".to_string(),\n                age: 0,\n            }),\n        }\n    };\n\n    let old_john = PEOPLE.update(\u0026mut store, \"john\", birthday)?;\n    assert_eq!(33, old_john.age);\n    assert_eq!(\"John\", old_john.name.as_str());\n\n    let new_jack = PEOPLE.update(\u0026mut store, \"jack\", birthday)?;\n    assert_eq!(0, new_jack.age);\n    assert_eq!(\"Newborn\", new_jack.name.as_str());\n\n    // update also changes the store\n    assert_eq!(old_john, PEOPLE.load(\u0026store, \"john\")?);\n    assert_eq!(new_jack, PEOPLE.load(\u0026store, \"jack\")?);\n\n    // removing leaves us empty\n    PEOPLE.remove(\u0026mut store, \"john\");\n    let empty = PEOPLE.may_load(\u0026store, \"john\")?;\n    assert_eq!(None, empty);\n\n    Ok(())\n}\n```\n\n### Key types\n\nA `Map` key can be anything that implements the `PrimaryKey` trait. There are a series of implementations of\n`PrimaryKey` already provided (see [keys.rs](./src/keys.rs)):\n\n- `impl\u003c'a\u003e PrimaryKey\u003c'a\u003e for \u0026'a [u8]`\n- `impl\u003c'a\u003e PrimaryKey\u003c'a\u003e for \u0026'a str`\n- `impl\u003c'a\u003e PrimaryKey\u003c'a\u003e for Vec\u003cu8\u003e`\n- `impl\u003c'a\u003e PrimaryKey\u003c'a\u003e for String`\n- `impl\u003c'a\u003e PrimaryKey\u003c'a\u003e for Addr`\n- `impl\u003c'a, const N: usize\u003e PrimaryKey\u003c'a\u003e for [u8; N]`\n- `impl\u003c'a, T: Prefixer\u003c'a\u003e\u003e Prefixer\u003c'a\u003e for \u0026'a T`\n- `impl\u003c'a, T: PrimaryKey\u003c'a\u003e + Prefixer\u003c'a\u003e, U: PrimaryKey\u003c'a\u003e\u003e PrimaryKey\u003c'a\u003e for (T, U)`\n- `impl\u003c'a, T: PrimaryKey\u003c'a\u003e + Prefixer\u003c'a\u003e, U: PrimaryKey\u003c'a\u003e + Prefixer\u003c'a\u003e, V: PrimaryKey\u003c'a\u003e\u003e PrimaryKey\u003c'a\u003e for (T, U, V)`\n- `PrimaryKey` implemented for unsigned integers up to `u128`\n- `PrimaryKey` implemented for signed integers up to `i128`\n\nThat means that byte and string slices, byte vectors, and strings, can be conveniently used as keys.\nMoreover, some other types can be used as well, like addresses and address references, pairs, triples, and\ninteger types.\n\nIf the key represents an address, we suggest using `\u0026Addr` for keys in storage, instead of `String` or string slices.\nThis implies doing address validation through `addr_validate` on any address passed in via a message, to ensure it's a\nlegitimate address, and not random text which will fail later.\n`pub fn addr_validate(\u0026self, \u0026str) -\u003e Addr` in `deps.api` can be used for address validation, and the returned `Addr`\ncan then be conveniently used as key in a `Map` or similar structure.\n\nIt's also convenient to use references (i.e. borrowed values) instead of values for keys (i.e. `\u0026Addr` instead of `Addr`),\nas that will typically save some cloning during key reading / writing.\n\n### Composite Keys\n\nThere are times when we want to use multiple items as a key. For example, when\nstoring allowances based on account owner and spender. We could try to manually\nconcatenate them before calling, but that can lead to overlap, and is a bit\nlow-level for us. Also, by explicitly separating the keys, we can easily provide\nhelpers to do range queries over a prefix, such as \"show me all allowances for\none owner\" (first part of the composite key). Just like you'd expect from your\nfavorite database.\n\nHere's how we use it with composite keys. Just define a tuple as a key and use that\neverywhere you used a single key above.\n\n```rust\n// Note the tuple for primary key. We support one slice, or a 2 or 3-tuple.\n// Adding longer tuples is possible, but unlikely to be needed.\nconst ALLOWANCE: Map\u003c(\u0026str, \u0026str), u64\u003e = Map::new(\"allow\");\n\nfn demo() -\u003e StdResult\u003c()\u003e {\n    let mut store = MockStorage::new();\n\n    // save and load on a composite key\n    let empty = ALLOWANCE.may_load(\u0026store, (\"owner\", \"spender\"))?;\n    assert_eq!(None, empty);\n    ALLOWANCE.save(\u0026mut store, (\"owner\", \"spender\"), \u0026777)?;\n    let loaded = ALLOWANCE.load(\u0026store, (\"owner\", \"spender\"))?;\n    assert_eq!(777, loaded);\n\n    // doesn't appear under other key (even if a concat would be the same)\n    let different = ALLOWANCE.may_load(\u0026store, (\"owners\", \"pender\")).unwrap();\n    assert_eq!(None, different);\n\n    // simple update\n    ALLOWANCE.update(\u0026mut store, (\"owner\", \"spender\"), |v| {\n        Ok(v.unwrap_or_default() + 222)\n    })?;\n    let loaded = ALLOWANCE.load(\u0026store, (\"owner\", \"spender\"))?;\n    assert_eq!(999, loaded);\n\n    Ok(())\n}\n```\n\n### Path\n\nUnder the scenes, we create a `Path` from the `Map` when accessing a key.\n`PEOPLE.load(\u0026store, \"jack\") == PEOPLE.key(\"jack\").load()`.\n`Map.key()` returns a `Path`, which has the same interface as `Item`,\nre-using the calculated path to this key.\n\nFor simple keys, this is just a bit less typing and a bit less gas if you\nuse the same key for many calls. However, for composite keys, like\n`(\"owner\", \"spender\")` it is **much** less typing. And highly recommended anywhere\nyou will use a composite key even twice:\n\n```rust\n#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]\nstruct Data {\n    pub name: String,\n    pub age: i32,\n}\n\nconst PEOPLE: Map\u003c\u0026str, Data\u003e = Map::new(\"people\");\nconst ALLOWANCE: Map\u003c(\u0026str, \u0026str), u64\u003e = Map::new(\"allow\");\n\nfn demo() -\u003e StdResult\u003c()\u003e {\n    let mut store = MockStorage::new();\n    let data = Data {\n        name: \"John\".to_string(),\n        age: 32,\n    };\n\n    // create a Path one time to use below\n    let john = PEOPLE.key(\"john\");\n\n    // Use this just like an Item above\n    let empty = john.may_load(\u0026store)?;\n    assert_eq!(None, empty);\n    john.save(\u0026mut store, \u0026data)?;\n    let loaded = john.load(\u0026store)?;\n    assert_eq!(data, loaded);\n    john.remove(\u0026mut store);\n    let empty = john.may_load(\u0026store)?;\n    assert_eq!(None, empty);\n\n    // Same for composite keys, just use both parts in `key()`.\n    // Notice how much less verbose than the above example.\n    let allow = ALLOWANCE.key((\"owner\", \"spender\"));\n    allow.save(\u0026mut store, \u00261234)?;\n    let loaded = allow.load(\u0026store)?;\n    assert_eq!(1234, loaded);\n    allow.update(\u0026mut store, |x| Ok(x.unwrap_or_default() * 2))?;\n    let loaded = allow.load(\u0026store)?;\n    assert_eq!(2468, loaded);\n\n    Ok(())\n}\n```\n\n### Prefix\n\nIn addition to getting one particular item out of a map, we can iterate over the map\n(or a subset of the map). This let us answer questions like \"show me all tokens\",\nand we provide some nice [`Bound`](#bound) helpers to easily allow pagination or custom ranges.\n\nThe general format is to get a `Prefix` by calling `map.prefix(k)`, where `k` is exactly\none less item than the normal key (If `map.key()` took `(\u0026[u8], \u0026[u8])`, then `map.prefix()` takes `\u0026[u8]`.\nIf `map.key()` took `\u0026[u8]`, `map.prefix()` takes `()`). Once we have a prefix space, we can iterate\nover all items with `range(store, min, max, order)`. It supports `Order::Ascending` or `Order::Descending`.\n`min` is the lower bound and `max` is the higher bound.\n\nIf the `min` and `max` bounds are `None`, `range` will return all items under the prefix. You can use `.take(n)` to\nlimit the results to `n` items and start doing pagination. You can also set the `min` bound to\neg. `Bound::exclusive(last_value)` to start iterating over all items _after_ the last value. Combined with\n`take`, we easily have pagination support. You can also use `Bound::inclusive(x)` when you want to include any\nperfect matches.\n\n### Bound\n\n`Bound` is a helper to build type-safe bounds on the keys or sub-keys you want to iterate over.\nIt also supports a raw (`Vec\u003cu8\u003e`) bounds specification, for the cases you don't want or can't use typed bounds.\n\n```rust\n#[derive(Clone, Debug)]\npub enum Bound\u003c'a, K: PrimaryKey\u003c'a\u003e\u003e {\n  Inclusive((K, PhantomData\u003c\u0026'a bool\u003e)),\n  Exclusive((K, PhantomData\u003c\u0026'a bool\u003e)),\n  InclusiveRaw(Vec\u003cu8\u003e),\n  ExclusiveRaw(Vec\u003cu8\u003e),\n}\n```\n\nTo better understand the API, please check the following example:\n\n```rust\n#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]\nstruct Data {\n    pub name: String,\n    pub age: i32,\n}\n\nconst PEOPLE: Map\u003c\u0026str, Data\u003e = Map::new(\"people\");\nconst ALLOWANCE: Map\u003c(\u0026str, \u0026str), u64\u003e = Map::new(\"allow\");\n\nfn demo() -\u003e StdResult\u003c()\u003e {\n    let mut store = MockStorage::new();\n\n    // save and load on two keys\n    let data = Data { name: \"John\".to_string(), age: 32 };\n    PEOPLE.save(\u0026mut store, \"john\", \u0026data)?;\n    let data2 = Data { name: \"Jim\".to_string(), age: 44 };\n    PEOPLE.save(\u0026mut store, \"jim\", \u0026data2)?;\n\n    // iterate over them all\n    let all: StdResult\u003cVec\u003c_\u003e\u003e = PEOPLE\n        .range(\u0026store, None, None, Order::Ascending)\n        .collect();\n    assert_eq!(\n        all?,\n        vec![(\"jim\".to_vec(), data2), (\"john\".to_vec(), data.clone())]\n    );\n\n    // or just show what is after jim\n    let all: StdResult\u003cVec\u003c_\u003e\u003e = PEOPLE\n        .range(\n            \u0026store,\n            Some(Bound::exclusive(\"jim\")),\n            None,\n            Order::Ascending,\n        )\n        .collect();\n    assert_eq!(all?, vec![(\"john\".to_vec(), data)]);\n\n    // save and load on three keys, one under different owner\n    ALLOWANCE.save(\u0026mut store, (\"owner\", \"spender\"), \u00261000)?;\n    ALLOWANCE.save(\u0026mut store, (\"owner\", \"spender2\"), \u00263000)?;\n    ALLOWANCE.save(\u0026mut store, (\"owner2\", \"spender\"), \u00265000)?;\n\n    // get all under one key\n    let all: StdResult\u003cVec\u003c_\u003e\u003e = ALLOWANCE\n        .prefix(\"owner\")\n        .range(\u0026store, None, None, Order::Ascending)\n        .collect();\n    assert_eq!(\n        all?,\n        vec![(\"spender\".to_vec(), 1000), (\"spender2\".to_vec(), 3000)]\n    );\n\n    // Or ranges between two items (even reverse)\n    let all: StdResult\u003cVec\u003c_\u003e\u003e = ALLOWANCE\n        .prefix(\"owner\")\n        .range(\n            \u0026store,\n            Some(Bound::exclusive(\"spender\")),\n            Some(Bound::inclusive(\"spender2\")),\n            Order::Descending,\n        )\n        .collect();\n    assert_eq!(all?, vec![(\"spender2\".to_vec(), 3000)]);\n\n    Ok(())\n}\n```\n\n**NB**: For properly defining and using type-safe bounds over a `MultiIndex`, see [Type-safe bounds over `MultiIndex`](#type-safe-bounds-over-multiindex),\nbelow.\n\n## IndexedMap\n\nLet's see one example of `IndexedMap` definition and usage, originally taken from the `cw721-base` contract.\n\n### Definition\n\n```rust\npub struct TokenIndexes\u003c'a\u003e {\n  pub owner: MultiIndex\u003c'a, Addr, TokenInfo, String\u003e,\n}\n\nimpl\u003c'a\u003e IndexList\u003cTokenInfo\u003e for TokenIndexes\u003c'a\u003e {\n  fn get_indexes(\u0026'_ self) -\u003e Box\u003cdyn Iterator\u003cItem = \u0026'_ dyn Index\u003cTokenInfo\u003e\u003e + '_\u003e {\n    let v: Vec\u003c\u0026dyn Index\u003cTokenInfo\u003e\u003e = vec![\u0026self.owner];\n    Box::new(v.into_iter())\n  }\n}\n\npub fn tokens\u003c'a\u003e() -\u003e IndexedMap\u003c'a, \u0026'a str, TokenInfo, TokenIndexes\u003c'a\u003e\u003e {\n  let indexes = TokenIndexes {\n    owner: MultiIndex::new(\n      |d: \u0026TokenInfo| d.owner.clone(),\n      \"tokens\",\n      \"tokens__owner\",\n    ),\n  };\n  IndexedMap::new(\"tokens\", indexes)\n}\n```\n\nLet's discuss this piece by piece:\n\n```rust\npub struct TokenIndexes\u003c'a\u003e {\n  pub owner: MultiIndex\u003c'a, Addr, TokenInfo, String\u003e,\n}\n```\n\nThese are the index definitions. Here there's only one index, called `owner`. There could be more, as public\nmembers of the `TokenIndexes` struct.\nWe see that the `owner` index is a `MultiIndex`. A multi-index can have repeated values as keys. The primary key is\nused internally as the last element of the multi-index key, to disambiguate repeated index values.\nLike the name implies, this is an index over tokens, by owner. Given that an owner can have multiple tokens,\nwe need a `MultiIndex` to be able to list / iterate over all the tokens he has.\n\nThe `TokenInfo` data will originally be stored by `token_id` (which is a string value).\nYou can see this in the token creation code:\n\n```rust\n    tokens().update(deps.storage, \u0026msg.token_id, |old| match old {\n        Some(_) =\u003e Err(ContractError::Claimed {}),\n        None =\u003e Ok(token),\n    })?;\n```\n\n(Incidentally, this is using `update` instead of `save`, to avoid overwriting an already existing token).\n\nGiven that `token_id` is a string value, we specify `String` as the last argument of the `MultiIndex` definition.\nThat way, the deserialization of the primary key will be done to the right type (an owned string).\n\n**NB**: In the particular case of a `MultiIndex`, and with the latest implementation of type-safe bounds, the definition of\nthis last type parameter is crucial, for properly using type-safe bounds.\nSee [Type-safe bounds over `MultiIndex`](#type-safe-bounds-over-multiindex), below.\n\nThen, this `TokenInfo` data will be indexed by token `owner` (which is an `Addr`). So that we can list all the tokens\nan owner has. That's why the `owner` index key is `Addr`.\n\nOther important thing here is that the key (and its components, in the case of a composite key) must implement\nthe `PrimaryKey` trait. You can see that `Addr` does implement `PrimaryKey`:\n\n```rust\nimpl\u003c'a\u003e PrimaryKey\u003c'a\u003e for Addr {\n  type Prefix = ();\n  type SubPrefix = ();\n  type Suffix = Self;\n  type SuperSuffix = Self;\n\n  fn key(\u0026self) -\u003e Vec\u003cKey\u003e {\n    // this is simple, we don't add more prefixes\n    vec![Key::Ref(self.as_bytes())]\n  }\n}\n```\n\n---\n\nWe can now see how it all works, taking a look at the remaining code:\n\n```rust\nimpl\u003c'a\u003e IndexList\u003cTokenInfo\u003e for TokenIndexes\u003c'a\u003e {\n    fn get_indexes(\u0026'_ self) -\u003e Box\u003cdyn Iterator\u003cItem = \u0026'_ dyn Index\u003cTokenInfo\u003e\u003e + '_\u003e {\n        let v: Vec\u003c\u0026dyn Index\u003cTokenInfo\u003e\u003e = vec![\u0026self.owner];\n        Box::new(v.into_iter())\n    }\n}\n```\n\nThis implements the `IndexList` trait for `TokenIndexes`.\n\n**NB**: this code is more or less boiler-plate, and needed for the internals. Do not try to customize this;\njust return a list of all indexes.\nImplementing this trait serves two purposes (which are really one and the same): it allows the indexes\nto be queried through `get_indexes`, and, it allows `TokenIndexes` to be treated as an `IndexList`. So that\nit can be passed as a parameter during `IndexedMap` construction, below:\n\n```rust\npub fn tokens\u003c'a\u003e() -\u003e IndexedMap\u003c'a, \u0026'a str, TokenInfo, TokenIndexes\u003c'a\u003e\u003e {\n    let indexes = TokenIndexes {\n        owner: MultiIndex::new(\n            |d: \u0026TokenInfo| d.owner.clone(),\n            \"tokens\",\n            \"tokens__owner\",\n        ),\n    };\n    IndexedMap::new(\"tokens\", indexes)\n}\n```\n\nHere `tokens()` is just a helper function, that simplifies the `IndexedMap` construction for us. First the\nindex (es) is (are) created, and then, the `IndexedMap` is created and returned.\n\nDuring index creation, we must supply an index function per index\n\n```rust\n        owner: MultiIndex::new(|d: \u0026TokenInfo| d.owner.clone(),\n```\n\nwhich is the one that will take the value of the original map and create the index key from it.\nOf course, this requires that the elements required for the index key are present in the value.\nBesides the index function, we must also supply the namespace of the pk, and the one for the new index.\n\n---\n\nAfter that, we just create and return the `IndexedMap`:\n\n```rust\n    IndexedMap::new(\"tokens\", indexes)\n```\n\nHere of course, the namespace of the pk must match the one used during index(es) creation. And, we pass our\n`TokenIndexes` (as an `IndexList`-type parameter) as second argument. Connecting in this way the underlying `Map`\nfor the pk, with the defined indexes.\n\nSo, `IndexedMap` (and the other `Indexed*` types) is just a wrapper / extension around `Map`, that provides\na number of index functions and namespaces to create indexes over the original `Map` data. It also implements\ncalling these index functions during value storage / update / removal, so that you can forget about it,\nand just use the indexed data.\n\n### Usage\n\nAn example of use, where `owner` is a `String` value passed as a parameter, and `start_after` and `limit` optionally\ndefine the pagination range:\n\nNotice this uses `prefix()`, explained above in the `Map` section.\n\n```rust\n    let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize;\n    let start = start_after.map(Bound::exclusive);\n    let owner_addr = deps.api.addr_validate(\u0026owner)?;\n\n    let res: Result\u003cVec\u003c_\u003e, _\u003e = tokens()\n        .idx\n        .owner\n        .prefix(owner_addr)\n        .range(deps.storage, start, None, Order::Ascending)\n        .take(limit)\n        .collect();\n    let tokens = res?;\n```\n\nNow `tokens` contains `(token_id, TokenInfo)` pairs for the given `owner`.\nThe pk values are `Vec\u003cu8\u003e` in the case of `range_raw()`, but will be deserialized to the proper type using\n`range()`; provided that the pk deserialization type (`String`, in this case) is correctly specified\nin the `MultiIndex` definition (see [Index keys deserialization](#index-keys-deserialization),\nbelow).\n\nAnother example that is similar, but returning only the (raw) `token_id`s, using the `keys_raw()` method:\n\n```rust\n    let pks: Vec\u003c_\u003e = tokens()\n        .idx\n        .owner\n        .prefix(owner_addr)\n        .keys_raw(\n            deps.storage,\n            start,\n            None,\n            Order::Ascending,\n        )\n        .take(limit)\n        .collect();\n```\n\nNow `pks` contains `token_id` values (as raw `Vec\u003cu8\u003e`s) for the given `owner`. By using `keys` instead,\na deserialized key can be obtained, as detailed in the next section.\n\n### Index keys deserialization\n\nFor `UniqueIndex` and `MultiIndex`, the primary key (`PK`) type needs to be specified, in order to deserialize\nthe primary key to it.\nThis `PK` type specification is also important for `MultiIndex` type-safe bounds, as the primary key\nis part of the multi-index key. See next section, [Type-safe bounds over MultiIndex](#type-safe-bounds-over-multiindex).\n\n**NB**: This specification is still a manual (and therefore error-prone) process / setup, that will (if possible)\nbe automated in the future (https://github.com/CosmWasm/cw-plus/issues/531).\n\n### Type-safe bounds over MultiIndex\n\nIn the particular case of `MultiIndex`, the primary key (`PK`) type parameter also defines the type of the (partial) bounds over\nthe index key (the part that corresponds to the primary key, that is).\nSo, to correctly use type-safe bounds over multi-indexes ranges, it is fundamental for this `PK` type\nto be correctly defined, so that it matches the primary key type, or its (typically owned) deserialization variant.\n\n## Deque\n\nThe usage of a [`Deque`](./src/deque.rs) is pretty straight-forward.\nConceptually it works like a storage-backed version of Rust std's `Deque` and can be used as a queue or stack.\nIt allows you to push and pop elements on both ends and also read the first or last element without mutating the deque.\nYou can also read a specific index directly.\n\nExample Usage:\n\n```rust\n#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]\nstruct Data {\n    pub name: String,\n    pub age: i32,\n}\n\nconst DATA: Deque\u003cData\u003e = Deque::new(\"data\");\n\nfn demo() -\u003e StdResult\u003c()\u003e {\n    let mut store = MockStorage::new();\n\n    // read methods return a wrapped Option\u003cT\u003e, so None if the deque is empty\n    let empty = DATA.front(\u0026store)?;\n    assert_eq!(None, empty);\n\n    // some example entries\n    let p1 = Data {\n        name: \"admin\".to_string(),\n        age: 1234,\n    };\n    let p2 = Data {\n        name: \"user\".to_string(),\n        age: 123,\n    };\n\n    // use it like a queue by pushing and popping at opposite ends\n    DATA.push_back(\u0026mut store, \u0026p1)?;\n    DATA.push_back(\u0026mut store, \u0026p2)?;\n\n    let admin = DATA.pop_front(\u0026mut store)?;\n    assert_eq!(admin.as_ref(), Some(\u0026p1));\n    let user = DATA.pop_front(\u0026mut store)?;\n    assert_eq!(user.as_ref(), Some(\u0026p2));\n\n    // or push and pop at the same end to use it as a stack\n    DATA.push_back(\u0026mut store, \u0026p1)?;\n    DATA.push_back(\u0026mut store, \u0026p2)?;\n\n    let user = DATA.pop_back(\u0026mut store)?;\n    assert_eq!(user.as_ref(), Some(\u0026p2));\n    let admin = DATA.pop_back(\u0026mut store)?;\n    assert_eq!(admin.as_ref(), Some(\u0026p1));\n\n    // you can also iterate over it\n    DATA.push_front(\u0026mut store, \u0026p1)?;\n    DATA.push_front(\u0026mut store, \u0026p2)?;\n\n    let all: StdResult\u003cVec\u003c_\u003e\u003e = DATA.iter(\u0026store)?.collect();\n    assert_eq!(all?, [p2, p1]);\n\n    // or access an index directly\n    assert_eq!(DATA.get(\u0026store, 0)?, Some(p2));\n    assert_eq!(DATA.get(\u0026store, 1)?, Some(p1));\n    assert_eq!(DATA.get(\u0026store, 3)?, None);\n\n    Ok(())\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCosmWasm%2Fcw-storage-plus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCosmWasm%2Fcw-storage-plus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCosmWasm%2Fcw-storage-plus/lists"}