cw_storage_plus/indexes/
unique.rs

1// this module requires iterator to be useful at all
2#![cfg(feature = "iterator")]
3
4use std::marker::PhantomData;
5
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8
9use cosmwasm_std::{from_json, Binary, Order, Record, StdError, StdResult, Storage};
10
11use crate::bound::PrefixBound;
12use crate::de::KeyDeserialize;
13use crate::indexes::IndexPrefix;
14use crate::iter_helpers::deserialize_kv;
15use crate::map::Map;
16use crate::prefix::namespaced_prefix_range;
17use crate::{Bound, Index, Prefixer, PrimaryKey};
18
19/// UniqueRef stores Binary(Vec[u8]) representation of private key and index value
20#[derive(Deserialize, Serialize)]
21pub(crate) struct UniqueRef<T> {
22    // note, we collapse the pk - combining everything under the namespace - even if it is composite
23    pk: Binary,
24    value: T,
25}
26
27/// UniqueIndex stores (namespace, index_name, idx_value) -> {key, value}
28/// Allows one value per index (i.e. unique) and copies pk and data
29/// The PK type defines the type of Primary Key deserialization.
30pub struct UniqueIndex<'a, IK, T, PK> {
31    index: fn(&T) -> IK,
32    idx_map: Map<IK, UniqueRef<T>>,
33    idx_namespace: &'a [u8],
34    phantom: PhantomData<PK>,
35}
36
37impl<IK, T, PK> UniqueIndex<'_, IK, T, PK> {
38    /// Create a new UniqueIndex
39    ///
40    /// idx_fn - lambda creating index key from index value
41    /// idx_namespace - prefix for the index value
42    ///
43    /// ## Example:
44    ///
45    /// ```rust
46    /// use cw_storage_plus::UniqueIndex;
47    ///
48    /// struct Data {
49    ///     pub name: String,
50    ///     pub age: u32,
51    /// }
52    ///
53    /// UniqueIndex::<_, _, ()>::new(|d: &Data| d.age, "data__age");
54    /// ```
55    pub const fn new(idx_fn: fn(&T) -> IK, idx_namespace: &'static str) -> Self {
56        UniqueIndex {
57            index: idx_fn,
58            idx_map: Map::new(idx_namespace),
59            idx_namespace: idx_namespace.as_bytes(),
60            phantom: PhantomData,
61        }
62    }
63}
64
65impl<'a, IK, T, PK> Index<T> for UniqueIndex<'a, IK, T, PK>
66where
67    T: Serialize + DeserializeOwned + Clone,
68    IK: PrimaryKey<'a>,
69{
70    fn save(&self, store: &mut dyn Storage, pk: &[u8], data: &T) -> StdResult<()> {
71        let idx = (self.index)(data);
72        // error if this is already set
73        self.idx_map
74            .update(store, idx, |existing| -> StdResult<_> {
75                match existing {
76                    Some(_) => Err(StdError::msg("Violates unique constraint on index")),
77                    None => Ok(UniqueRef::<T> {
78                        pk: pk.into(),
79                        value: data.clone(),
80                    }),
81                }
82            })?;
83        Ok(())
84    }
85
86    fn remove(&self, store: &mut dyn Storage, _pk: &[u8], old_data: &T) -> StdResult<()> {
87        let idx = (self.index)(old_data);
88        self.idx_map.remove(store, idx);
89        Ok(())
90    }
91}
92
93fn deserialize_unique_v<T: DeserializeOwned>(kv: Record) -> StdResult<Record<T>> {
94    let (_, v) = kv;
95    let t = from_json::<UniqueRef<T>>(&v)?;
96    Ok((t.pk.into(), t.value))
97}
98
99fn deserialize_unique_kv<K: KeyDeserialize, T: DeserializeOwned>(
100    kv: Record,
101) -> StdResult<(K::Output, T)> {
102    let (_, v) = kv;
103    let t = from_json::<UniqueRef<T>>(&v)?;
104    Ok((K::from_vec(t.pk.into())?, t.value))
105}
106
107impl<'a, IK, T, PK> UniqueIndex<'a, IK, T, PK>
108where
109    T: Serialize + DeserializeOwned + Clone,
110    IK: PrimaryKey<'a>,
111{
112    pub fn index_key(&self, k: IK) -> Vec<u8> {
113        k.joined_key()
114    }
115
116    fn no_prefix_raw(&self) -> IndexPrefix<Vec<u8>, T, IK> {
117        IndexPrefix::with_deserialization_functions(
118            self.idx_namespace,
119            &[],
120            &[],
121            |_, _, kv| deserialize_unique_v(kv),
122            |_, _, kv| deserialize_unique_v(kv),
123        )
124    }
125
126    /// returns all items that match this secondary index, always by pk Ascending
127    pub fn item(&self, store: &dyn Storage, idx: IK) -> StdResult<Option<Record<T>>> {
128        let data = self
129            .idx_map
130            .may_load(store, idx)?
131            .map(|i| (i.pk.into(), i.value));
132        Ok(data)
133    }
134}
135
136// short-cut for simple keys, rather than .prefix(()).range_raw(...)
137impl<'a, IK, T, PK> UniqueIndex<'a, IK, T, PK>
138where
139    T: Serialize + DeserializeOwned + Clone,
140    IK: PrimaryKey<'a>,
141{
142    // I would prefer not to copy code from Prefix, but no other way
143    // with lifetimes (create Prefix inside function and return ref = no no)
144    pub fn range_raw<'c>(
145        &self,
146        store: &'c dyn Storage,
147        min: Option<Bound<'a, IK>>,
148        max: Option<Bound<'a, IK>>,
149        order: Order,
150    ) -> Box<dyn Iterator<Item = StdResult<Record<T>>> + 'c>
151    where
152        T: 'c,
153    {
154        self.no_prefix_raw().range_raw(store, min, max, order)
155    }
156
157    pub fn keys_raw<'c>(
158        &self,
159        store: &'c dyn Storage,
160        min: Option<Bound<'a, IK>>,
161        max: Option<Bound<'a, IK>>,
162        order: Order,
163    ) -> Box<dyn Iterator<Item = Vec<u8>> + 'c> {
164        self.no_prefix_raw().keys_raw(store, min, max, order)
165    }
166}
167
168#[cfg(feature = "iterator")]
169impl<'a, IK, T, PK> UniqueIndex<'a, IK, T, PK>
170where
171    PK: PrimaryKey<'a> + KeyDeserialize,
172    T: Serialize + DeserializeOwned + Clone,
173    IK: PrimaryKey<'a>,
174{
175    /// While `range` over a `prefix` fixes the prefix to one element and iterates over the
176    /// remaining, `prefix_range` accepts bounds for the lowest and highest elements of the
177    /// `Prefix` itself, and iterates over those (inclusively or exclusively, depending on
178    /// `PrefixBound`).
179    /// There are some issues that distinguish these two, and blindly casting to `Vec<u8>` doesn't
180    /// solve them.
181    pub fn prefix_range<'c>(
182        &self,
183        store: &'c dyn Storage,
184        min: Option<PrefixBound<'a, IK::Prefix>>,
185        max: Option<PrefixBound<'a, IK::Prefix>>,
186        order: Order,
187    ) -> Box<dyn Iterator<Item = StdResult<(PK::Output, T)>> + 'c>
188    where
189        T: 'c,
190        'a: 'c,
191        IK: 'c,
192        PK: 'c,
193        PK::Output: 'static,
194    {
195        let mapped = namespaced_prefix_range(store, self.idx_namespace, min, max, order)
196            .map(deserialize_kv::<PK, T>);
197        Box::new(mapped)
198    }
199
200    pub fn range<'c>(
201        &self,
202        store: &'c dyn Storage,
203        min: Option<Bound<'a, IK>>,
204        max: Option<Bound<'a, IK>>,
205        order: Order,
206    ) -> Box<dyn Iterator<Item = StdResult<(PK::Output, T)>> + 'c>
207    where
208        T: 'c,
209        PK::Output: 'static,
210    {
211        self.no_prefix().range(store, min, max, order)
212    }
213
214    pub fn keys<'c>(
215        &self,
216        store: &'c dyn Storage,
217        min: Option<Bound<'a, IK>>,
218        max: Option<Bound<'a, IK>>,
219        order: Order,
220    ) -> Box<dyn Iterator<Item = StdResult<PK::Output>> + 'c>
221    where
222        T: 'c,
223        PK::Output: 'static,
224    {
225        self.no_prefix().keys(store, min, max, order)
226    }
227
228    pub fn prefix(&self, p: IK::Prefix) -> IndexPrefix<PK, T, IK::Suffix> {
229        IndexPrefix::with_deserialization_functions(
230            self.idx_namespace,
231            &p.prefix(),
232            &[],
233            |_, _, kv| deserialize_unique_kv::<PK, _>(kv),
234            |_, _, kv| deserialize_unique_v(kv),
235        )
236    }
237
238    pub fn sub_prefix(&self, p: IK::SubPrefix) -> IndexPrefix<PK, T, IK::SuperSuffix> {
239        IndexPrefix::with_deserialization_functions(
240            self.idx_namespace,
241            &p.prefix(),
242            &[],
243            |_, _, kv| deserialize_unique_kv::<PK, _>(kv),
244            |_, _, kv| deserialize_unique_v(kv),
245        )
246    }
247
248    fn no_prefix(&self) -> IndexPrefix<PK, T, IK> {
249        IndexPrefix::with_deserialization_functions(
250            self.idx_namespace,
251            &[],
252            &[],
253            |_, _, kv| deserialize_unique_kv::<PK, _>(kv),
254            |_, _, kv| deserialize_unique_v(kv),
255        )
256    }
257}