Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Add methods to PrefixIterator to support iterating from a specific key (
Browse files Browse the repository at this point in the history
#9313)

* Add methods to PrefixIterator to support iterating from a specific key

* Expose the decode functions used in iterators for storage maps

* Use associated decode function in tests

* Revert "Expose the decode functions used in iterators for storage maps"

This reverts commit 34f57d9.

* Fix documentation for next_key

* Add API for iterating from a specified key for all storage map types

* Enhance pagination test

* Add API methods to storage map types

* Rename next_key to last_key

* Rename last_key to last_raw_key

* Specify that iteration starts after starting_raw_key

* Update documentation on iteration ordering

* Rename next_key to previous_key

* Enhance pagination unit test

* Create unit tests for all kinds of iter_from methods

* Define iter_from in terms of iter rather than vice versa

* Cargo fmt
  • Loading branch information
KiChjang committed Jul 27, 2021
1 parent d94bf34 commit 54c0a30
Show file tree
Hide file tree
Showing 9 changed files with 535 additions and 46 deletions.
2 changes: 1 addition & 1 deletion frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ macro_rules! generate_storage_alias {
>;
}
};
($pallet:ident, $name:ident => NMap<$(($key:ty, $hasher:ty),)+ $value:ty>) => {
($pallet:ident, $name:ident => NMap<Key<$(($key:ty, $hasher:ty)),+>, $value:ty>) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
type $name = $crate::storage::types::StorageNMap<
Expand Down
66 changes: 66 additions & 0 deletions frame/support/src/storage/generator/double_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,15 @@ where
}
}

fn iter_prefix_from(
k1: impl EncodeLike<K1>,
starting_raw_key: Vec<u8>,
) -> Self::PrefixIterator {
let mut iter = Self::iter_prefix(k1);
iter.set_last_raw_key(starting_raw_key);
iter
}

fn iter_key_prefix(k1: impl EncodeLike<K1>) -> Self::PartialKeyIterator {
let prefix = G::storage_double_map_final_key1(k1);
Self::PartialKeyIterator {
Expand All @@ -382,6 +391,15 @@ where
}
}

fn iter_key_prefix_from(
k1: impl EncodeLike<K1>,
starting_raw_key: Vec<u8>,
) -> Self::PartialKeyIterator {
let mut iter = Self::iter_key_prefix(k1);
iter.set_last_raw_key(starting_raw_key);
iter
}

fn drain_prefix(k1: impl EncodeLike<K1>) -> Self::PrefixIterator {
let mut iterator = Self::iter_prefix(k1);
iterator.drain = true;
Expand All @@ -404,6 +422,12 @@ where
}
}

fn iter_from(starting_raw_key: Vec<u8>) -> Self::Iterator {
let mut iter = Self::iter();
iter.set_last_raw_key(starting_raw_key);
iter
}

fn iter_keys() -> Self::FullKeyIterator {
let prefix = G::prefix_hash();
Self::FullKeyIterator {
Expand All @@ -420,6 +444,12 @@ where
}
}

fn iter_keys_from(starting_raw_key: Vec<u8>) -> Self::FullKeyIterator {
let mut iter = Self::iter_keys();
iter.set_last_raw_key(starting_raw_key);
iter
}

fn drain() -> Self::Iterator {
let mut iterator = Self::iter();
iterator.drain = true;
Expand Down Expand Up @@ -509,6 +539,42 @@ mod test_iterators {
prefix
}

#[test]
fn double_map_iter_from() {
sp_io::TestExternalities::default().execute_with(|| {
use crate::hash::Identity;
crate::generate_storage_alias!(
MyModule,
MyDoubleMap => DoubleMap<(u64, Identity), (u64, Identity), u64>
);

MyDoubleMap::insert(1, 10, 100);
MyDoubleMap::insert(1, 21, 201);
MyDoubleMap::insert(1, 31, 301);
MyDoubleMap::insert(1, 41, 401);
MyDoubleMap::insert(2, 20, 200);
MyDoubleMap::insert(3, 30, 300);
MyDoubleMap::insert(4, 40, 400);
MyDoubleMap::insert(5, 50, 500);

let starting_raw_key = MyDoubleMap::storage_double_map_final_key(1, 21);
let iter = MyDoubleMap::iter_key_prefix_from(1, starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![31, 41]);

let starting_raw_key = MyDoubleMap::storage_double_map_final_key(1, 31);
let iter = MyDoubleMap::iter_prefix_from(1, starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(41, 401)]);

let starting_raw_key = MyDoubleMap::storage_double_map_final_key(2, 20);
let iter = MyDoubleMap::iter_keys_from(starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(3, 30), (4, 40), (5, 50)]);

let starting_raw_key = MyDoubleMap::storage_double_map_final_key(3, 30);
let iter = MyDoubleMap::iter_from(starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(4, 40, 400), (5, 50, 500)]);
});
}

#[test]
fn double_map_reversible_reversible_iteration() {
sp_io::TestExternalities::default().execute_with(|| {
Expand Down
36 changes: 36 additions & 0 deletions frame/support/src/storage/generator/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,13 @@ where
}
}

/// Enumerate all elements in the map after a given key.
fn iter_from(starting_raw_key: Vec<u8>) -> Self::Iterator {
let mut iter = Self::iter();
iter.set_last_raw_key(starting_raw_key);
iter
}

/// Enumerate all keys in the map.
fn iter_keys() -> Self::KeyIterator {
let prefix = G::prefix_hash();
Expand All @@ -167,6 +174,13 @@ where
}
}

/// Enumerate all keys in the map after a given key.
fn iter_keys_from(starting_raw_key: Vec<u8>) -> Self::KeyIterator {
let mut iter = Self::iter_keys();
iter.set_last_raw_key(starting_raw_key);
iter
}

/// Enumerate all elements in the map.
fn drain() -> Self::Iterator {
let mut iterator = Self::iter();
Expand Down Expand Up @@ -382,6 +396,28 @@ mod test_iterators {
prefix
}

#[test]
fn map_iter_from() {
sp_io::TestExternalities::default().execute_with(|| {
use crate::hash::Identity;
crate::generate_storage_alias!(MyModule, MyMap => Map<(u64, Identity), u64>);

MyMap::insert(1, 10);
MyMap::insert(2, 20);
MyMap::insert(3, 30);
MyMap::insert(4, 40);
MyMap::insert(5, 50);

let starting_raw_key = MyMap::storage_map_final_key(3);
let iter = MyMap::iter_from(starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(4, 40), (5, 50)]);

let starting_raw_key = MyMap::storage_map_final_key(2);
let iter = MyMap::iter_keys_from(starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![3, 4, 5]);
});
}

#[test]
fn map_reversible_reversible_iteration() {
sp_io::TestExternalities::default().execute_with(|| {
Expand Down
2 changes: 1 addition & 1 deletion frame/support/src/storage/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
//! This is internal api and is subject to change.

mod double_map;
mod map;
pub(crate) mod map;
mod nmap;
mod value;

Expand Down
80 changes: 76 additions & 4 deletions frame/support/src/storage/generator/nmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,18 @@ impl<K: ReversibleKeyGenerator, V: FullCodec, G: StorageNMap<K, V>>
}
}

fn iter_prefix_from<KP>(
kp: KP,
starting_raw_key: Vec<u8>,
) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
where
K: HasReversibleKeyPrefix<KP>,
{
let mut iter = Self::iter_prefix(kp);
iter.set_last_raw_key(starting_raw_key);
iter
}

fn iter_key_prefix<KP>(kp: KP) -> KeyPrefixIterator<<K as HasKeyPrefix<KP>>::Suffix>
where
K: HasReversibleKeyPrefix<KP>,
Expand All @@ -342,6 +354,18 @@ impl<K: ReversibleKeyGenerator, V: FullCodec, G: StorageNMap<K, V>>
}
}

fn iter_key_prefix_from<KP>(
kp: KP,
starting_raw_key: Vec<u8>,
) -> KeyPrefixIterator<<K as HasKeyPrefix<KP>>::Suffix>
where
K: HasReversibleKeyPrefix<KP>,
{
let mut iter = Self::iter_key_prefix(kp);
iter.set_last_raw_key(starting_raw_key);
iter
}

fn drain_prefix<KP>(kp: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
where
K: HasReversibleKeyPrefix<KP>,
Expand All @@ -352,10 +376,14 @@ impl<K: ReversibleKeyGenerator, V: FullCodec, G: StorageNMap<K, V>>
}

fn iter() -> Self::Iterator {
Self::iter_from(G::prefix_hash())
}

fn iter_from(starting_raw_key: Vec<u8>) -> Self::Iterator {
let prefix = G::prefix_hash();
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
prefix,
previous_key: starting_raw_key,
drain: false,
closure: |raw_key_without_prefix, mut raw_value| {
let (final_key, _) = K::decode_final_key(raw_key_without_prefix)?;
Expand All @@ -365,10 +393,14 @@ impl<K: ReversibleKeyGenerator, V: FullCodec, G: StorageNMap<K, V>>
}

fn iter_keys() -> Self::KeyIterator {
Self::iter_keys_from(G::prefix_hash())
}

fn iter_keys_from(starting_raw_key: Vec<u8>) -> Self::KeyIterator {
let prefix = G::prefix_hash();
Self::KeyIterator {
prefix: prefix.clone(),
previous_key: prefix,
prefix,
previous_key: starting_raw_key,
drain: false,
closure: |raw_key_without_prefix| {
let (final_key, _) = K::decode_final_key(raw_key_without_prefix)?;
Expand Down Expand Up @@ -457,6 +489,46 @@ mod test_iterators {
prefix
}

#[test]
fn n_map_iter_from() {
sp_io::TestExternalities::default().execute_with(|| {
use crate::{hash::Identity, storage::Key as NMapKey};
crate::generate_storage_alias!(
MyModule,
MyNMap => NMap<Key<(u64, Identity), (u64, Identity), (u64, Identity)>, u64>
);

MyNMap::insert((1, 1, 1), 11);
MyNMap::insert((1, 1, 2), 21);
MyNMap::insert((1, 1, 3), 31);
MyNMap::insert((1, 2, 1), 12);
MyNMap::insert((1, 2, 2), 22);
MyNMap::insert((1, 2, 3), 32);
MyNMap::insert((1, 3, 1), 13);
MyNMap::insert((1, 3, 2), 23);
MyNMap::insert((1, 3, 3), 33);
MyNMap::insert((2, 0, 0), 200);

type Key = (NMapKey<Identity, u64>, NMapKey<Identity, u64>, NMapKey<Identity, u64>);

let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 2, 2));
let iter = MyNMap::iter_key_prefix_from((1,), starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(2, 3), (3, 1), (3, 2), (3, 3)]);

let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 3, 1));
let iter = MyNMap::iter_prefix_from((1, 3), starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(2, 23), (3, 33)]);

let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 3, 2));
let iter = MyNMap::iter_keys_from(starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![(1, 3, 3), (2, 0, 0)]);

let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 3, 3));
let iter = MyNMap::iter_from(starting_raw_key);
assert_eq!(iter.collect::<Vec<_>>(), vec![((2, 0, 0), 200)]);
});
}

#[test]
fn n_map_double_map_identical_key() {
sp_io::TestExternalities::default().execute_with(|| {
Expand Down
Loading

0 comments on commit 54c0a30

Please sign in to comment.