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

implemented contains_prefix for StorageDoubleMap and StorageNMap #13232

Merged
merged 5 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions frame/support/src/storage/generator/double_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ where
.into()
}

fn contains_prefix<KArg1>(k1: KArg1) -> bool
where
KArg1: EncodeLike<K1>,
{
unhashed::contains_prefixed_key(Self::storage_double_map_final_key1(k1).as_ref())
}

fn iter_prefix_values<KArg1>(k1: KArg1) -> storage::PrefixIterator<V>
where
KArg1: ?Sized + EncodeLike<K1>,
Expand Down
7 changes: 7 additions & 0 deletions frame/support/src/storage/generator/nmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,13 @@ where
)
}

fn contains_prefix<KP>(partial_key: KP) -> bool
where
K: HasKeyPrefix<KP>,
{
unhashed::contains_prefixed_key(&Self::storage_n_map_partial_key(partial_key))
}

fn iter_prefix_values<KP>(partial_key: KP) -> PrefixIterator<V>
where
K: HasKeyPrefix<KP>,
Expand Down
27 changes: 27 additions & 0 deletions frame/support/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,12 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
where
KArg1: ?Sized + EncodeLike<K1>;

/// Does any value under the first key `k1` (explicitly) exist in storage?
/// Might have unexpected behaviour with empty keys, e.g. `[]`.
ggwpez marked this conversation as resolved.
Show resolved Hide resolved
fn contains_prefix<KArg1>(k1: KArg1) -> bool
where
KArg1: EncodeLike<K1>;

/// Iterate over values that share the first key.
fn iter_prefix_values<KArg1>(k1: KArg1) -> PrefixIterator<V>
where
Expand Down Expand Up @@ -733,6 +739,12 @@ pub trait StorageNMap<K: KeyGenerator, V: FullCodec> {
where
K: HasKeyPrefix<KP>;

/// Does any value under a `partial_key` prefix (explicitly) exist in storage?
/// Might have unexpected behaviour with empty keys, e.g. `[]`.
fn contains_prefix<KP>(partial_key: KP) -> bool
where
K: HasKeyPrefix<KP>;

/// Iterate over values that share the partial prefix key.
fn iter_prefix_values<KP>(partial_key: KP) -> PrefixIterator<V>
where
Expand Down Expand Up @@ -1775,6 +1787,21 @@ mod test {
type FooDoubleMap =
StorageDoubleMap<Prefix, Twox128, u32, Twox128, u32, BoundedVec<u32, ConstU32<7>>>;

#[test]
fn contains_prefix_works() {
TestExternalities::default().execute_with(|| {
assert!(FooDoubleMap::iter_prefix_values(0).next().is_none());
assert_eq!(FooDoubleMap::contains_prefix(0), false);

assert_ok!(FooDoubleMap::try_append(1, 1, 4));
assert_ok!(FooDoubleMap::try_append(2, 1, 4));
assert!(FooDoubleMap::iter_prefix_values(1).next().is_some());
assert!(FooDoubleMap::contains_prefix(1));
FooDoubleMap::remove(1, 1);
assert_eq!(FooDoubleMap::contains_prefix(1), false);
});
}

#[test]
fn try_append_works() {
TestExternalities::default().execute_with(|| {
Expand Down
10 changes: 10 additions & 0 deletions frame/support/src/storage/unhashed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,16 @@ pub fn clear_prefix(
MultiRemovalResults { maybe_cursor, backend: i, unique: i, loops: i }
}

/// Returns `true` if the storage contains any key, which starts with a certain prefix,
/// and is longer than said prefix.
/// This means that a key which equals the prefix will not be counted.
pub fn contains_prefixed_key(prefix: &[u8]) -> bool {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cheme I hope this is fine now

Copy link
Contributor

@cheme cheme Jan 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 (I am not really good at getting to the right api but looks fine, would have prefer a more explicit name as I never read the doc at first, but that's me :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for some context, @shawntabrizi approved the api and doc 😺

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, if you look above, you will see a bunch of APIs for acting on one key, like clear_prefix, which use the same term and parameter.

match sp_io::storage::next_key(prefix) {
Some(key) => key.starts_with(prefix),
None => false,
}
}

/// Get a Vec of bytes from storage.
pub fn get_raw(key: &[u8]) -> Option<Vec<u8>> {
sp_io::storage::get(key).map(|value| value.to_vec())
Expand Down