1#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
2
3use cosmwasm_std::{Deps, Order, StdResult};
4
5#[allow(unused_imports)]
6use cw_storage_plus::{Bound, Bounder, KeyDeserialize, Map, SnapshotMap, Strategy};
7
8pub fn paginate_map<'a, 'b, K, V, R: 'static>(
11 deps: Deps,
12 map: &Map<'a, K, V>,
13 start_after: Option<K>,
14 limit: Option<u32>,
15 order: Order,
16) -> StdResult<Vec<(R, V)>>
17where
18 K: Bounder<'a> + KeyDeserialize<Output = R> + 'b,
19 V: serde::de::DeserializeOwned + serde::Serialize,
20{
21 let (range_min, range_max) = match order {
22 Order::Ascending => (start_after.map(Bound::exclusive), None),
23 Order::Descending => (None, start_after.map(Bound::exclusive)),
24 };
25
26 let items = map.range(deps.storage, range_min, range_max, order);
27 match limit {
28 Some(limit) => Ok(items
29 .take(limit.try_into().unwrap())
30 .collect::<StdResult<_>>()?),
31 None => Ok(items.collect::<StdResult<_>>()?),
32 }
33}
34
35pub fn paginate_map_keys<'a, 'b, K, V, R: 'static>(
37 deps: Deps,
38 map: &Map<'a, K, V>,
39 start_after: Option<K>,
40 limit: Option<u32>,
41 order: Order,
42) -> StdResult<Vec<R>>
43where
44 K: Bounder<'a> + KeyDeserialize<Output = R> + 'b,
45 V: serde::de::DeserializeOwned + serde::Serialize,
46{
47 let (range_min, range_max) = match order {
48 Order::Ascending => (start_after.map(Bound::exclusive), None),
49 Order::Descending => (None, start_after.map(Bound::exclusive)),
50 };
51
52 let items = map.keys(deps.storage, range_min, range_max, order);
53 match limit {
54 Some(limit) => Ok(items
55 .take(limit.try_into().unwrap())
56 .collect::<StdResult<_>>()?),
57 None => Ok(items.collect::<StdResult<_>>()?),
58 }
59}
60
61pub fn paginate_snapshot_map<'a, 'b, K, V, R: 'static>(
63 deps: Deps,
64 map: &SnapshotMap<'a, K, V>,
65 start_after: Option<K>,
66 limit: Option<u32>,
67 order: Order,
68) -> StdResult<Vec<(R, V)>>
69where
70 K: Bounder<'a> + KeyDeserialize<Output = R> + 'b,
71 V: serde::de::DeserializeOwned + serde::Serialize,
72{
73 let (range_min, range_max) = match order {
74 Order::Ascending => (start_after.map(Bound::exclusive), None),
75 Order::Descending => (None, start_after.map(Bound::exclusive)),
76 };
77
78 let items = map.range(deps.storage, range_min, range_max, order);
79 match limit {
80 Some(limit) => Ok(items
81 .take(limit.try_into().unwrap())
82 .collect::<StdResult<_>>()?),
83 None => Ok(items.collect::<StdResult<_>>()?),
84 }
85}
86
87pub fn paginate_map_values<'a, K, V>(
89 deps: Deps,
90 map: &Map<'a, K, V>,
91 start_after: Option<K>,
92 limit: Option<u32>,
93 order: Order,
94) -> StdResult<Vec<V>>
95where
96 K: Bounder<'a> + KeyDeserialize<Output = K> + 'static,
97 V: serde::de::DeserializeOwned + serde::Serialize,
98{
99 let (range_min, range_max) = match order {
100 Order::Ascending => (start_after.map(Bound::exclusive), None),
101 Order::Descending => (None, start_after.map(Bound::exclusive)),
102 };
103
104 let items = map
105 .range(deps.storage, range_min, range_max, order)
106 .map(|kv| Ok(kv?.1));
107
108 match limit {
109 Some(limit) => Ok(items
110 .take(limit.try_into().unwrap())
111 .collect::<StdResult<_>>()?),
112 None => Ok(items.collect::<StdResult<_>>()?),
113 }
114}
115
116pub fn paginate_snapshot_map_keys<'a, 'b, K, V, R: 'static>(
119 deps: Deps,
120 map: &SnapshotMap<'a, K, V>,
121 start_after: Option<K>,
122 limit: Option<u32>,
123 order: Order,
124) -> StdResult<Vec<R>>
125where
126 K: Bounder<'a> + KeyDeserialize<Output = R> + 'b,
127 V: serde::de::DeserializeOwned + serde::Serialize,
128{
129 let (range_min, range_max) = match order {
130 Order::Ascending => (start_after.map(Bound::exclusive), None),
131 Order::Descending => (None, start_after.map(Bound::exclusive)),
132 };
133
134 let items = map.keys(deps.storage, range_min, range_max, order);
135 match limit {
136 Some(limit) => Ok(items
137 .take(limit.try_into().unwrap())
138 .collect::<StdResult<_>>()?),
139 None => Ok(items.collect::<StdResult<_>>()?),
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use cosmwasm_std::testing::{mock_dependencies, mock_env};
147 use cosmwasm_std::{Addr, Uint128};
148
149 #[test]
150 fn pagination() {
151 let mut deps = mock_dependencies();
152 let map: Map<String, String> = Map::new("items");
153
154 for num in 1..3 {
155 map.save(&mut deps.storage, num.to_string(), &(num * 2).to_string())
156 .unwrap();
157 }
158
159 let items = paginate_map(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
160 assert_eq!(
161 items,
162 vec![
163 ("2".to_string(), "4".to_string()),
164 ("1".to_string(), "2".to_string())
165 ]
166 );
167
168 let items = paginate_map(deps.as_ref(), &map, None, None, Order::Ascending).unwrap();
169 assert_eq!(
170 items,
171 vec![
172 ("1".to_string(), "2".to_string()),
173 ("2".to_string(), "4".to_string())
174 ]
175 );
176
177 let items = paginate_map(
178 deps.as_ref(),
179 &map,
180 Some("1".to_string()),
181 None,
182 Order::Ascending,
183 )
184 .unwrap();
185 assert_eq!(items, vec![("2".to_string(), "4".to_string())]);
186
187 let items = paginate_map(deps.as_ref(), &map, None, Some(1), Order::Ascending).unwrap();
188 assert_eq!(items, vec![("1".to_string(), "2".to_string())]);
189 }
190
191 #[test]
192 fn key_pagination() {
193 let mut deps = mock_dependencies();
194 let map: Map<String, String> = Map::new("items");
195
196 for num in 1..3 {
197 map.save(&mut deps.storage, num.to_string(), &(num * 2).to_string())
198 .unwrap();
199 }
200
201 let items = paginate_map_keys(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
202 assert_eq!(items, vec!["2".to_string(), "1".to_string()]);
203
204 let items = paginate_map_keys(deps.as_ref(), &map, None, None, Order::Ascending).unwrap();
205 assert_eq!(items, vec!["1".to_string(), "2".to_string()]);
206
207 let items = paginate_map_keys(
208 deps.as_ref(),
209 &map,
210 Some("1".to_string()),
211 None,
212 Order::Ascending,
213 )
214 .unwrap();
215 assert_eq!(items, vec!["2"]);
216
217 let items =
218 paginate_map_keys(deps.as_ref(), &map, None, Some(1), Order::Ascending).unwrap();
219 assert_eq!(items, vec!["1".to_string()]);
220 }
221
222 #[test]
224 fn key_pagination_test2() {
225 let mut deps = mock_dependencies();
226 let map: Map<u32, String> = Map::new("items");
227
228 for num in 1u32..=10 {
229 map.save(&mut deps.storage, num, &(num * 2).to_string())
230 .unwrap();
231 }
232
233 let items = paginate_map_keys(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
234 assert_eq!(items, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
235
236 let items = paginate_map_keys(deps.as_ref(), &map, None, None, Order::Ascending).unwrap();
237 assert_eq!(items, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
238
239 let items =
240 paginate_map_keys(deps.as_ref(), &map, Some(3), Some(3), Order::Ascending).unwrap();
241 assert_eq!(items, vec![4, 5, 6]);
242
243 let items =
244 paginate_map_keys(deps.as_ref(), &map, Some(7), Some(4), Order::Descending).unwrap();
245 assert_eq!(items, vec![6, 5, 4, 3]);
246 }
247
248 #[test]
249 fn snapshot_pagination() {
250 let mut deps = mock_dependencies();
251 let env = mock_env();
252
253 let map: SnapshotMap<&Addr, Uint128> = SnapshotMap::new(
254 "items",
255 "items__checkpoints",
256 "items__changelog",
257 Strategy::EveryBlock,
258 );
259
260 for ctr in 1..100 {
261 let addr = Addr::unchecked(format!("test_addr{:0>3}", ctr.clone()));
262 map.save(
263 &mut deps.storage,
264 &addr,
265 &Uint128::new(ctr),
266 env.block.height,
267 )
268 .unwrap();
269 }
270
271 let items =
273 paginate_snapshot_map(deps.as_ref(), &map, None, Some(10), Order::Ascending).unwrap();
274
275 assert_eq!(items.len(), 10);
276
277 let mut test_vec: Vec<(Addr, Uint128)> = vec![];
278 for ctr in 1..=10 {
279 let addr = Addr::unchecked(format!("test_addr{:0>3}", ctr.clone()));
280
281 test_vec.push((addr, Uint128::new(ctr)));
282 }
283 assert_eq!(items, test_vec);
284
285 let items = paginate_snapshot_map(
287 deps.as_ref(),
288 &map,
289 Some(&items[items.len() - 1].0),
290 Some(10),
291 Order::Ascending,
292 )
293 .unwrap();
294
295 assert_eq!(items[0].0, Addr::unchecked("test_addr011".to_string()));
297 assert_eq!(items[0].1, Uint128::new(11));
298
299 let items =
300 paginate_snapshot_map(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
301
302 assert_eq!(items[19].0, Addr::unchecked("test_addr080".to_string()));
304 assert_eq!(items[19].1, Uint128::new(80));
305 }
306
307 #[test]
309 fn snapshot_pagination_keys_new_generic() {
310 let mut deps = mock_dependencies();
311 let env = mock_env();
312
313 let map: SnapshotMap<&Addr, Uint128> = SnapshotMap::new(
314 "items",
315 "items__checkpoints",
316 "items__changelog",
317 Strategy::EveryBlock,
318 );
319
320 for ctr in 1..100 {
321 let addr = Addr::unchecked(format!("test_addr{:0>3}", ctr.clone()));
322 map.save(
323 &mut deps.storage,
324 &addr,
325 &Uint128::new(ctr),
326 env.block.height,
327 )
328 .unwrap();
329 }
330
331 let items =
333 paginate_snapshot_map_keys(deps.as_ref(), &map, None, Some(10), Order::Ascending)
334 .unwrap();
335
336 assert_eq!(items.len(), 10);
337
338 let mut test_vec: Vec<Addr> = vec![];
339 for ctr in 1..=10 {
340 let addr = Addr::unchecked(format!("test_addr{:0>3}", ctr.clone()));
341
342 test_vec.push(addr);
343 }
344 assert_eq!(items, test_vec);
345
346 let items = paginate_snapshot_map_keys(
348 deps.as_ref(),
349 &map,
350 Some(&items[items.len() - 1]),
351 None,
352 Order::Descending,
353 )
354 .unwrap();
355
356 assert_eq!(items[3], Addr::unchecked("test_addr006".to_string()));
358
359 let items =
360 paginate_snapshot_map_keys(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
361
362 assert_eq!(items[19], Addr::unchecked("test_addr080".to_string()));
364 }
365
366 #[test]
367 fn snapshot_pagination_keys() {
368 let mut deps = mock_dependencies();
369 let env = mock_env();
370
371 let map: SnapshotMap<u32, Uint128> = SnapshotMap::new(
372 "items",
373 "items__checkpoints",
374 "items__changelog",
375 Strategy::EveryBlock,
376 );
377
378 for ctr in 1..=100 {
379 map.save(
380 &mut deps.storage,
381 ctr,
382 &Uint128::new(<u32 as std::convert::Into<u128>>::into(ctr)),
383 env.block.height,
384 )
385 .unwrap();
386 }
387
388 let items =
390 paginate_snapshot_map_keys(deps.as_ref(), &map, None, Some(10), Order::Ascending)
391 .unwrap();
392
393 assert_eq!(items.len(), 10);
394 assert_eq!(items, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
395
396 let items =
397 paginate_snapshot_map_keys(deps.as_ref(), &map, Some(50), Some(10), Order::Ascending)
398 .unwrap();
399
400 assert_eq!(items, vec![51, 52, 53, 54, 55, 56, 57, 58, 59, 60]);
401
402 let items =
403 paginate_snapshot_map_keys(deps.as_ref(), &map, Some(50), Some(10), Order::Descending)
404 .unwrap();
405
406 assert_eq!(items, vec![49, 48, 47, 46, 45, 44, 43, 42, 41, 40]);
407 }
408
409 #[test]
410 fn pagination_order_desc_tests() {
411 let mut deps = mock_dependencies();
412 let map: Map<u32, u32> = Map::new("items");
413
414 map.save(&mut deps.storage, 1, &40).unwrap();
415 map.save(&mut deps.storage, 2, &22).unwrap();
416 map.save(&mut deps.storage, 3, &77).unwrap();
417 map.save(&mut deps.storage, 4, &66).unwrap();
418 map.save(&mut deps.storage, 5, &0).unwrap();
419
420 let items = paginate_map(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
421 assert_eq!(items, vec![(5, 0), (4, 66), (3, 77), (2, 22), (1, 40)]);
422
423 let items = paginate_map(deps.as_ref(), &map, Some(3), None, Order::Descending).unwrap();
424 assert_eq!(items, vec![(2, 22), (1, 40)]);
425
426 let items = paginate_map(deps.as_ref(), &map, Some(1), None, Order::Descending).unwrap();
427 assert_eq!(items, vec![]);
428 }
429
430 #[test]
434 fn pagination_keys_refs() {
435 let mut deps = mock_dependencies();
436 let map: Map<&Addr, u32> = Map::new("items");
437
438 map.save(
439 &mut deps.storage,
440 &Addr::unchecked(format!("test_addr{:0>3}", 1)),
441 &40,
442 )
443 .unwrap();
444 map.save(
445 &mut deps.storage,
446 &Addr::unchecked(format!("test_addr{:0>3}", 2)),
447 &22,
448 )
449 .unwrap();
450 map.save(
451 &mut deps.storage,
452 &Addr::unchecked(format!("test_addr{:0>3}", 3)),
453 &77,
454 )
455 .unwrap();
456 map.save(
457 &mut deps.storage,
458 &Addr::unchecked(format!("test_addr{:0>3}", 4)),
459 &66,
460 )
461 .unwrap();
462 map.save(
463 &mut deps.storage,
464 &Addr::unchecked(format!("test_addr{:0>3}", 5)),
465 &0,
466 )
467 .unwrap();
468
469 let items = paginate_map_keys(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
470 assert_eq!(items[1], Addr::unchecked(format!("test_addr{:0>3}", 4)));
471 assert_eq!(items[4], Addr::unchecked(format!("test_addr{:0>3}", 1)));
472
473 let addr: Addr = Addr::unchecked(format!("test_addr{:0>3}", 3));
474 let items =
475 paginate_map_keys(deps.as_ref(), &map, Some(&addr), None, Order::Ascending).unwrap();
476 assert_eq!(items[0], Addr::unchecked(format!("test_addr{:0>3}", 4)));
477 }
478
479 #[test]
483 fn pagination_refs() {
484 let mut deps = mock_dependencies();
485 let map: Map<&Addr, u32> = Map::new("items");
486
487 map.save(
488 &mut deps.storage,
489 &Addr::unchecked(format!("test_addr{:0>3}", 1)),
490 &0,
491 )
492 .unwrap();
493 map.save(
494 &mut deps.storage,
495 &Addr::unchecked(format!("test_addr{:0>3}", 2)),
496 &22,
497 )
498 .unwrap();
499 map.save(
500 &mut deps.storage,
501 &Addr::unchecked(format!("test_addr{:0>3}", 3)),
502 &77,
503 )
504 .unwrap();
505 map.save(
506 &mut deps.storage,
507 &Addr::unchecked(format!("test_addr{:0>3}", 4)),
508 &66,
509 )
510 .unwrap();
511 map.save(
512 &mut deps.storage,
513 &Addr::unchecked(format!("test_addr{:0>3}", 6)),
514 &0,
515 )
516 .unwrap();
517
518 let items = paginate_map(deps.as_ref(), &map, None, None, Order::Descending).unwrap();
519 assert_eq!(
520 items[1],
521 (Addr::unchecked(format!("test_addr{:0>3}", 4)), 66)
522 );
523 assert_eq!(
524 items[4],
525 (Addr::unchecked(format!("test_addr{:0>3}", 1)), 0)
526 );
527
528 let addr: Addr = Addr::unchecked(format!("test_addr{:0>3}", 3));
529 let items =
530 paginate_map(deps.as_ref(), &map, Some(&addr), Some(2), Order::Ascending).unwrap();
531 let test_vec: Vec<(Addr, u32)> = vec![
532 (Addr::unchecked(format!("test_addr{:0>3}", 4)), 66),
533 (Addr::unchecked(format!("test_addr{:0>3}", 6)), 0),
534 ];
535 assert_eq!(items, test_vec);
536 }
537}