1use crate::{
22 storage::{
23 types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder},
24 KeyLenOf, StorageAppend, StorageDecodeLength, StoragePrefixedMap, StorageTryAppend,
25 },
26 traits::{Get, GetDefault, StorageInfo, StorageInstance},
27 StorageHasher, Twox128,
28};
29use alloc::{vec, vec::Vec};
30use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen};
31use frame_support::storage::StorageDecodeNonDedupLength;
32use sp_arithmetic::traits::SaturatedConversion;
33use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR};
34
35#[doc = docify::embed!("src/storage/types/double_map.rs", example_double_map_partial_operations)]
95pub struct StorageDoubleMap<
96 Prefix,
97 Hasher1,
98 Key1,
99 Hasher2,
100 Key2,
101 Value,
102 QueryKind = OptionQuery,
103 OnEmpty = GetDefault,
104 MaxValues = GetDefault,
105>(
106 core::marker::PhantomData<(
107 Prefix,
108 Hasher1,
109 Key1,
110 Hasher2,
111 Key2,
112 Value,
113 QueryKind,
114 OnEmpty,
115 MaxValues,
116 )>,
117);
118
119impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues> Get<u32>
120 for KeyLenOf<
121 StorageDoubleMap<
122 Prefix,
123 Hasher1,
124 Key1,
125 Hasher2,
126 Key2,
127 Value,
128 QueryKind,
129 OnEmpty,
130 MaxValues,
131 >,
132 >
133where
134 Prefix: StorageInstance,
135 Hasher1: crate::hash::StorageHasher,
136 Hasher2: crate::hash::StorageHasher,
137 Key1: MaxEncodedLen,
138 Key2: MaxEncodedLen,
139{
140 fn get() -> u32 {
141 let z =
144 Hasher1::max_len::<Key1>() + Hasher2::max_len::<Key2>() + Twox128::max_len::<()>() * 2;
145 z as u32
146 }
147}
148
149impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
150 crate::storage::generator::StorageDoubleMap<Key1, Key2, Value>
151 for StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
152where
153 Prefix: StorageInstance,
154 Hasher1: crate::hash::StorageHasher,
155 Hasher2: crate::hash::StorageHasher,
156 Key1: FullCodec,
157 Key2: FullCodec,
158 Value: FullCodec,
159 QueryKind: QueryKindTrait<Value, OnEmpty>,
160 OnEmpty: Get<QueryKind::Query> + 'static,
161 MaxValues: Get<Option<u32>>,
162{
163 type Query = QueryKind::Query;
164 type Hasher1 = Hasher1;
165 type Hasher2 = Hasher2;
166 fn pallet_prefix() -> &'static [u8] {
167 Prefix::pallet_prefix().as_bytes()
168 }
169
170 fn storage_prefix() -> &'static [u8] {
171 Prefix::STORAGE_PREFIX.as_bytes()
172 }
173 fn prefix_hash() -> [u8; 32] {
174 Prefix::prefix_hash()
175 }
176
177 fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
178 QueryKind::from_optional_value_to_query(v)
179 }
180 fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
181 QueryKind::from_query_to_optional_value(v)
182 }
183}
184
185impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
186 StoragePrefixedMap<Value>
187 for StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
188where
189 Prefix: StorageInstance,
190 Hasher1: crate::hash::StorageHasher,
191 Hasher2: crate::hash::StorageHasher,
192 Key1: FullCodec,
193 Key2: FullCodec,
194 Value: FullCodec,
195 QueryKind: QueryKindTrait<Value, OnEmpty>,
196 OnEmpty: Get<QueryKind::Query> + 'static,
197 MaxValues: Get<Option<u32>>,
198{
199 fn pallet_prefix() -> &'static [u8] {
200 <Self as crate::storage::generator::StorageDoubleMap<Key1, Key2, Value>>::pallet_prefix()
201 }
202 fn storage_prefix() -> &'static [u8] {
203 <Self as crate::storage::generator::StorageDoubleMap<Key1, Key2, Value>>::storage_prefix()
204 }
205}
206
207impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
208 StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
209where
210 Prefix: StorageInstance,
211 Hasher1: crate::hash::StorageHasher,
212 Hasher2: crate::hash::StorageHasher,
213 Key1: FullCodec,
214 Key2: FullCodec,
215 Value: FullCodec,
216 QueryKind: QueryKindTrait<Value, OnEmpty>,
217 OnEmpty: Get<QueryKind::Query> + 'static,
218 MaxValues: Get<Option<u32>>,
219{
220 pub fn hashed_key_for<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
222 where
223 KArg1: EncodeLike<Key1>,
224 KArg2: EncodeLike<Key2>,
225 {
226 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::hashed_key_for(k1, k2)
227 }
228
229 pub fn contains_key<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> bool
231 where
232 KArg1: EncodeLike<Key1>,
233 KArg2: EncodeLike<Key2>,
234 {
235 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::contains_key(k1, k2)
236 }
237
238 pub fn get<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> QueryKind::Query
240 where
241 KArg1: EncodeLike<Key1>,
242 KArg2: EncodeLike<Key2>,
243 {
244 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::get(k1, k2)
245 }
246
247 pub fn try_get<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Result<Value, ()>
251 where
252 KArg1: EncodeLike<Key1>,
253 KArg2: EncodeLike<Key2>,
254 {
255 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::try_get(k1, k2)
256 }
257
258 pub fn set<KArg1: EncodeLike<Key1>, KArg2: EncodeLike<Key2>>(
260 k1: KArg1,
261 k2: KArg2,
262 q: QueryKind::Query,
263 ) {
264 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::set(k1, k2, q)
265 }
266
267 pub fn take<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> QueryKind::Query
269 where
270 KArg1: EncodeLike<Key1>,
271 KArg2: EncodeLike<Key2>,
272 {
273 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::take(k1, k2)
274 }
275
276 pub fn swap<XKArg1, XKArg2, YKArg1, YKArg2>(
278 x_k1: XKArg1,
279 x_k2: XKArg2,
280 y_k1: YKArg1,
281 y_k2: YKArg2,
282 ) where
283 XKArg1: EncodeLike<Key1>,
284 XKArg2: EncodeLike<Key2>,
285 YKArg1: EncodeLike<Key1>,
286 YKArg2: EncodeLike<Key2>,
287 {
288 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::swap(x_k1, x_k2, y_k1, y_k2)
289 }
290
291 pub fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg)
293 where
294 KArg1: EncodeLike<Key1>,
295 KArg2: EncodeLike<Key2>,
296 VArg: EncodeLike<Value>,
297 {
298 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::insert(k1, k2, val)
299 }
300
301 pub fn remove<KArg1, KArg2>(k1: KArg1, k2: KArg2)
303 where
304 KArg1: EncodeLike<Key1>,
305 KArg2: EncodeLike<Key2>,
306 {
307 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::remove(k1, k2)
308 }
309
310 #[deprecated = "Use `clear_prefix` instead"]
323 pub fn remove_prefix<KArg1>(k1: KArg1, limit: Option<u32>) -> sp_io::KillStorageResult
324 where
325 KArg1: ?Sized + EncodeLike<Key1>,
326 {
327 #[allow(deprecated)]
328 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::remove_prefix(k1, limit)
329 }
330
331 pub fn clear_prefix<KArg1>(
355 first_key: KArg1,
356 limit: u32,
357 maybe_cursor: Option<&[u8]>,
358 ) -> sp_io::MultiRemovalResults
359 where
360 KArg1: ?Sized + EncodeLike<Key1>,
361 {
362 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::clear_prefix(
363 first_key,
364 limit,
365 maybe_cursor,
366 )
367 }
368
369 pub fn iter_prefix_values<KArg1>(k1: KArg1) -> crate::storage::PrefixIterator<Value>
371 where
372 KArg1: ?Sized + EncodeLike<Key1>,
373 {
374 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::iter_prefix_values(k1)
375 }
376
377 pub fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
379 where
380 KArg1: EncodeLike<Key1>,
381 KArg2: EncodeLike<Key2>,
382 F: FnOnce(&mut QueryKind::Query) -> R,
383 {
384 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::mutate(k1, k2, f)
385 }
386
387 pub fn try_mutate<KArg1, KArg2, R, E, F>(k1: KArg1, k2: KArg2, f: F) -> Result<R, E>
389 where
390 KArg1: EncodeLike<Key1>,
391 KArg2: EncodeLike<Key2>,
392 F: FnOnce(&mut QueryKind::Query) -> Result<R, E>,
393 {
394 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::try_mutate(k1, k2, f)
395 }
396
397 pub fn mutate_exists<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
399 where
400 KArg1: EncodeLike<Key1>,
401 KArg2: EncodeLike<Key2>,
402 F: FnOnce(&mut Option<Value>) -> R,
403 {
404 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::mutate_exists(k1, k2, f)
405 }
406
407 pub fn try_mutate_exists<KArg1, KArg2, R, E, F>(k1: KArg1, k2: KArg2, f: F) -> Result<R, E>
411 where
412 KArg1: EncodeLike<Key1>,
413 KArg2: EncodeLike<Key2>,
414 F: FnOnce(&mut Option<Value>) -> Result<R, E>,
415 {
416 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::try_mutate_exists(k1, k2, f)
417 }
418
419 pub fn append<Item, EncodeLikeItem, KArg1, KArg2>(k1: KArg1, k2: KArg2, item: EncodeLikeItem)
429 where
430 KArg1: EncodeLike<Key1>,
431 KArg2: EncodeLike<Key2>,
432 Item: Encode,
433 EncodeLikeItem: EncodeLike<Item>,
434 Value: StorageAppend<Item>,
435 {
436 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::append(k1, k2, item)
437 }
438
439 pub fn decode_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Option<usize>
452 where
453 KArg1: EncodeLike<Key1>,
454 KArg2: EncodeLike<Key2>,
455 Value: StorageDecodeLength,
456 {
457 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::decode_len(key1, key2)
458 }
459
460 pub fn decode_non_dedup_len<KArg1, KArg2>(key1: KArg1, key2: KArg2) -> Option<usize>
476 where
477 KArg1: EncodeLike<Key1>,
478 KArg2: EncodeLike<Key2>,
479 Value: StorageDecodeNonDedupLength,
480 {
481 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::decode_non_dedup_len(
482 key1, key2,
483 )
484 }
485
486 pub fn migrate_keys<
491 OldHasher1: crate::StorageHasher,
492 OldHasher2: crate::StorageHasher,
493 KeyArg1: EncodeLike<Key1>,
494 KeyArg2: EncodeLike<Key2>,
495 >(
496 key1: KeyArg1,
497 key2: KeyArg2,
498 ) -> Option<Value> {
499 <Self as crate::storage::StorageDoubleMap<Key1, Key2, Value>>::migrate_keys::<
500 OldHasher1,
501 OldHasher2,
502 _,
503 _,
504 >(key1, key2)
505 }
506
507 #[deprecated = "Use `clear` instead"]
519 pub fn remove_all(limit: Option<u32>) -> sp_io::KillStorageResult {
520 #[allow(deprecated)]
521 <Self as crate::storage::StoragePrefixedMap<Value>>::remove_all(limit)
522 }
523
524 pub fn clear(limit: u32, maybe_cursor: Option<&[u8]>) -> sp_io::MultiRemovalResults {
548 <Self as crate::storage::StoragePrefixedMap<Value>>::clear(limit, maybe_cursor)
549 }
550
551 pub fn iter_values() -> crate::storage::PrefixIterator<Value> {
555 <Self as crate::storage::StoragePrefixedMap<Value>>::iter_values()
556 }
557
558 pub fn translate_values<OldValue: Decode, F: FnMut(OldValue) -> Option<Value>>(f: F) {
572 <Self as crate::storage::StoragePrefixedMap<Value>>::translate_values(f)
573 }
574
575 pub fn try_append<KArg1, KArg2, Item, EncodeLikeItem>(
579 key1: KArg1,
580 key2: KArg2,
581 item: EncodeLikeItem,
582 ) -> Result<(), ()>
583 where
584 KArg1: EncodeLike<Key1> + Clone,
585 KArg2: EncodeLike<Key2> + Clone,
586 Item: Encode,
587 EncodeLikeItem: EncodeLike<Item>,
588 Value: StorageTryAppend<Item>,
589 {
590 <Self as crate::storage::TryAppendDoubleMap<Key1, Key2, Value, Item>>::try_append(
591 key1, key2, item,
592 )
593 }
594}
595
596impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
597 StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
598where
599 Prefix: StorageInstance,
600 Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher,
601 Hasher2: crate::hash::StorageHasher + crate::ReversibleStorageHasher,
602 Key1: FullCodec,
603 Key2: FullCodec,
604 Value: FullCodec,
605 QueryKind: QueryKindTrait<Value, OnEmpty>,
606 OnEmpty: Get<QueryKind::Query> + 'static,
607 MaxValues: Get<Option<u32>>,
608{
609 pub fn iter_prefix(k1: impl EncodeLike<Key1>) -> crate::storage::PrefixIterator<(Key2, Value)> {
614 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_prefix(k1)
615 }
616
617 pub fn iter_prefix_from(
623 k1: impl EncodeLike<Key1>,
624 starting_raw_key: Vec<u8>,
625 ) -> crate::storage::PrefixIterator<(Key2, Value)> {
626 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_prefix_from(
627 k1,
628 starting_raw_key,
629 )
630 }
631
632 pub fn iter_key_prefix(k1: impl EncodeLike<Key1>) -> crate::storage::KeyPrefixIterator<Key2> {
638 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_key_prefix(k1)
639 }
640
641 pub fn iter_key_prefix_from(
647 k1: impl EncodeLike<Key1>,
648 starting_raw_key: Vec<u8>,
649 ) -> crate::storage::KeyPrefixIterator<Key2> {
650 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_key_prefix_from(
651 k1,
652 starting_raw_key,
653 )
654 }
655
656 pub fn drain_prefix(
662 k1: impl EncodeLike<Key1>,
663 ) -> crate::storage::PrefixIterator<(Key2, Value)> {
664 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::drain_prefix(k1)
665 }
666
667 pub fn iter() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> {
671 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter()
672 }
673
674 pub fn iter_from(
679 starting_raw_key: Vec<u8>,
680 ) -> crate::storage::PrefixIterator<(Key1, Key2, Value)> {
681 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_from(
682 starting_raw_key,
683 )
684 }
685
686 pub fn iter_keys() -> crate::storage::KeyPrefixIterator<(Key1, Key2)> {
690 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_keys()
691 }
692
693 pub fn iter_keys_from(
698 starting_raw_key: Vec<u8>,
699 ) -> crate::storage::KeyPrefixIterator<(Key1, Key2)> {
700 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::iter_keys_from(
701 starting_raw_key,
702 )
703 }
704
705 pub fn drain() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> {
709 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::drain()
710 }
711
712 pub fn translate<O: Decode, F: FnMut(Key1, Key2, O) -> Option<Value>>(f: F) {
718 <Self as crate::storage::IterableStorageDoubleMap<Key1, Key2, Value>>::translate(f)
719 }
720}
721
722impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty, MaxValues>
723 StorageEntryMetadataBuilder
724 for StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
725where
726 Prefix: StorageInstance,
727 Hasher1: crate::hash::StorageHasher,
728 Hasher2: crate::hash::StorageHasher,
729 Key1: FullCodec + scale_info::StaticTypeInfo,
730 Key2: FullCodec + scale_info::StaticTypeInfo,
731 Value: FullCodec + scale_info::StaticTypeInfo,
732 QueryKind: QueryKindTrait<Value, OnEmpty>,
733 OnEmpty: Get<QueryKind::Query> + 'static,
734 MaxValues: Get<Option<u32>>,
735{
736 fn build_metadata(
737 deprecation_status: sp_metadata_ir::ItemDeprecationInfoIR,
738 docs: Vec<&'static str>,
739 entries: &mut Vec<StorageEntryMetadataIR>,
740 ) {
741 let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs };
742
743 let entry = StorageEntryMetadataIR {
744 name: Prefix::STORAGE_PREFIX,
745 modifier: QueryKind::METADATA,
746 ty: StorageEntryTypeIR::Map {
747 hashers: vec![Hasher1::METADATA, Hasher2::METADATA],
748 key: scale_info::meta_type::<(Key1, Key2)>(),
749 value: scale_info::meta_type::<Value>(),
750 },
751 default: OnEmpty::get().encode(),
752 docs,
753 deprecation_info: deprecation_status,
754 };
755
756 entries.push(entry);
757 }
758}
759
760impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty, MaxValues>
761 crate::traits::StorageInfoTrait
762 for StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
763where
764 Prefix: StorageInstance,
765 Hasher1: crate::hash::StorageHasher,
766 Hasher2: crate::hash::StorageHasher,
767 Key1: FullCodec + MaxEncodedLen,
768 Key2: FullCodec + MaxEncodedLen,
769 Value: FullCodec + MaxEncodedLen,
770 QueryKind: QueryKindTrait<Value, OnEmpty>,
771 OnEmpty: Get<QueryKind::Query> + 'static,
772 MaxValues: Get<Option<u32>>,
773{
774 fn storage_info() -> Vec<StorageInfo> {
775 vec![StorageInfo {
776 pallet_name: Self::pallet_prefix().to_vec(),
777 storage_name: Self::storage_prefix().to_vec(),
778 prefix: Self::final_prefix().to_vec(),
779 max_values: MaxValues::get(),
780 max_size: Some(
781 Hasher1::max_len::<Key1>()
782 .saturating_add(Hasher2::max_len::<Key2>())
783 .saturating_add(Value::max_encoded_len())
784 .saturated_into(),
785 ),
786 }]
787 }
788}
789
790impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty, MaxValues>
792 crate::traits::PartialStorageInfoTrait
793 for StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
794where
795 Prefix: StorageInstance,
796 Hasher1: crate::hash::StorageHasher,
797 Hasher2: crate::hash::StorageHasher,
798 Key1: FullCodec,
799 Key2: FullCodec,
800 Value: FullCodec,
801 QueryKind: QueryKindTrait<Value, OnEmpty>,
802 OnEmpty: Get<QueryKind::Query> + 'static,
803 MaxValues: Get<Option<u32>>,
804{
805 fn partial_storage_info() -> Vec<StorageInfo> {
806 vec![StorageInfo {
807 pallet_name: Self::pallet_prefix().to_vec(),
808 storage_name: Self::storage_prefix().to_vec(),
809 prefix: Self::final_prefix().to_vec(),
810 max_values: MaxValues::get(),
811 max_size: None,
812 }]
813 }
814}
815
816#[cfg(test)]
817mod test {
818 use super::*;
819 use crate::{hash::*, storage::types::ValueQuery};
820 use sp_io::{hashing::twox_128, TestExternalities};
821 use sp_metadata_ir::{StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR};
822 use std::collections::BTreeSet;
823
824 struct Prefix;
825 impl StorageInstance for Prefix {
826 fn pallet_prefix() -> &'static str {
827 "test"
828 }
829 const STORAGE_PREFIX: &'static str = "foo";
830 }
831
832 struct ADefault;
833 impl crate::traits::Get<u32> for ADefault {
834 fn get() -> u32 {
835 97
836 }
837 }
838
839 #[test]
840 fn keylenof_works() {
841 type A = StorageDoubleMap<Prefix, Blake2_128Concat, u64, Twox64Concat, u32, u32>;
843 let size = 16 * 2 + 16 + 8 + 8 + 4; assert_eq!(KeyLenOf::<A>::get(), size);
847 }
848
849 #[test]
850 fn test() {
851 type A =
852 StorageDoubleMap<Prefix, Blake2_128Concat, u16, Twox64Concat, u8, u32, OptionQuery>;
853 type AValueQueryWithAnOnEmpty = StorageDoubleMap<
854 Prefix,
855 Blake2_128Concat,
856 u16,
857 Twox64Concat,
858 u8,
859 u32,
860 ValueQuery,
861 ADefault,
862 >;
863 type B = StorageDoubleMap<Prefix, Blake2_256, u16, Twox128, u8, u32, ValueQuery>;
864 type C = StorageDoubleMap<Prefix, Blake2_128Concat, u16, Twox64Concat, u8, u8, ValueQuery>;
865 type WithLen = StorageDoubleMap<Prefix, Blake2_128Concat, u16, Twox64Concat, u8, Vec<u32>>;
866
867 TestExternalities::default().execute_with(|| {
868 let mut k: Vec<u8> = vec![];
869 k.extend(&twox_128(b"test"));
870 k.extend(&twox_128(b"foo"));
871 k.extend(&3u16.blake2_128_concat());
872 k.extend(&30u8.twox_64_concat());
873 assert_eq!(A::hashed_key_for(3, 30).to_vec(), k);
874
875 assert_eq!(A::contains_key(3, 30), false);
876 assert_eq!(A::get(3, 30), None);
877 assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97);
878
879 A::insert(3, 30, 10);
880 assert_eq!(A::contains_key(3, 30), true);
881 assert_eq!(A::get(3, 30), Some(10));
882 assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 10);
883
884 A::swap(3, 30, 2, 20);
885 assert_eq!(A::contains_key(3, 30), false);
886 assert_eq!(A::contains_key(2, 20), true);
887 assert_eq!(A::get(3, 30), None);
888 assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97);
889 assert_eq!(A::get(2, 20), Some(10));
890 assert_eq!(AValueQueryWithAnOnEmpty::get(2, 20), 10);
891
892 A::remove(2, 20);
893 assert_eq!(A::contains_key(2, 20), false);
894 assert_eq!(A::get(2, 20), None);
895
896 AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2);
897 AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2);
898 assert_eq!(A::contains_key(2, 20), true);
899 assert_eq!(A::get(2, 20), Some(97 * 4));
900
901 A::remove(2, 20);
902 let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| {
903 *v = *v * 2;
904 Ok(())
905 });
906 let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| {
907 *v = *v * 2;
908 Ok(())
909 });
910 assert_eq!(A::contains_key(2, 20), true);
911 assert_eq!(A::get(2, 20), Some(97 * 4));
912
913 A::remove(2, 20);
914 let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| {
915 *v = *v * 2;
916 Err(())
917 });
918 assert_eq!(A::contains_key(2, 20), false);
919
920 A::remove(2, 20);
921 AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| {
922 assert!(v.is_none());
923 *v = Some(10);
924 });
925 assert_eq!(A::contains_key(2, 20), true);
926 assert_eq!(A::get(2, 20), Some(10));
927 AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| {
928 *v = Some(v.unwrap() * 10);
929 });
930 assert_eq!(A::contains_key(2, 20), true);
931 assert_eq!(A::get(2, 20), Some(100));
932
933 A::remove(2, 20);
934 let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| {
935 assert!(v.is_none());
936 *v = Some(10);
937 Ok(())
938 });
939 assert_eq!(A::contains_key(2, 20), true);
940 assert_eq!(A::get(2, 20), Some(10));
941 let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| {
942 *v = Some(v.unwrap() * 10);
943 Ok(())
944 });
945 assert_eq!(A::contains_key(2, 20), true);
946 assert_eq!(A::get(2, 20), Some(100));
947 assert_eq!(A::try_get(2, 20), Ok(100));
948 let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| {
949 *v = Some(v.unwrap() * 10);
950 Err(())
951 });
952 assert_eq!(A::contains_key(2, 20), true);
953 assert_eq!(A::get(2, 20), Some(100));
954
955 A::insert(2, 20, 10);
956 assert_eq!(A::take(2, 20), Some(10));
957 assert_eq!(A::contains_key(2, 20), false);
958 assert_eq!(AValueQueryWithAnOnEmpty::take(2, 20), 97);
959 assert_eq!(A::contains_key(2, 20), false);
960 assert_eq!(A::try_get(2, 20), Err(()));
961
962 B::insert(2, 20, 10);
963 assert_eq!(A::migrate_keys::<Blake2_256, Twox128, _, _>(2, 20), Some(10));
964 assert_eq!(A::contains_key(2, 20), true);
965 assert_eq!(A::get(2, 20), Some(10));
966
967 A::insert(3, 30, 10);
968 A::insert(4, 40, 10);
969 let _ = A::clear(u32::max_value(), None);
970 assert_eq!(A::contains_key(3, 30), false);
971 assert_eq!(A::contains_key(4, 40), false);
972
973 A::insert(3, 30, 10);
974 A::insert(4, 40, 10);
975 assert_eq!(A::iter_values().collect::<Vec<_>>(), vec![10, 10]);
976
977 C::insert(3, 30, 10);
978 C::insert(4, 40, 10);
979 A::translate_values::<u8, _>(|v| Some((v * 2).into()));
980 assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 40, 20), (3, 30, 20)]);
981
982 A::insert(3, 30, 10);
983 A::insert(4, 40, 10);
984 assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 40, 10), (3, 30, 10)]);
985 assert_eq!(A::drain().collect::<Vec<_>>(), vec![(4, 40, 10), (3, 30, 10)]);
986 assert_eq!(A::iter().collect::<Vec<_>>(), vec![]);
987
988 C::insert(3, 30, 10);
989 C::insert(4, 40, 10);
990 A::translate::<u8, _>(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into()));
991 assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 40, 1600), (3, 30, 900)]);
992
993 let mut entries = vec![];
994 A::build_metadata(
995 sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
996 vec![],
997 &mut entries,
998 );
999 AValueQueryWithAnOnEmpty::build_metadata(
1000 sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
1001 vec![],
1002 &mut entries,
1003 );
1004 assert_eq!(
1005 entries,
1006 vec![
1007 StorageEntryMetadataIR {
1008 name: "foo",
1009 modifier: StorageEntryModifierIR::Optional,
1010 ty: StorageEntryTypeIR::Map {
1011 hashers: vec![
1012 StorageHasherIR::Blake2_128Concat,
1013 StorageHasherIR::Twox64Concat
1014 ],
1015 key: scale_info::meta_type::<(u16, u8)>(),
1016 value: scale_info::meta_type::<u32>(),
1017 },
1018 default: Option::<u32>::None.encode(),
1019 docs: vec![],
1020 deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated
1021 },
1022 StorageEntryMetadataIR {
1023 name: "foo",
1024 modifier: StorageEntryModifierIR::Default,
1025 ty: StorageEntryTypeIR::Map {
1026 hashers: vec![
1027 StorageHasherIR::Blake2_128Concat,
1028 StorageHasherIR::Twox64Concat
1029 ],
1030 key: scale_info::meta_type::<(u16, u8)>(),
1031 value: scale_info::meta_type::<u32>(),
1032 },
1033 default: 97u32.encode(),
1034 docs: vec![],
1035 deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated
1036 }
1037 ]
1038 );
1039
1040 let _ = WithLen::clear(u32::max_value(), None);
1041 assert_eq!(WithLen::decode_len(3, 30), None);
1042 WithLen::append(0, 100, 10);
1043 assert_eq!(WithLen::decode_len(0, 100), Some(1));
1044
1045 A::insert(3, 30, 11);
1046 A::insert(3, 31, 12);
1047 A::insert(4, 40, 13);
1048 A::insert(4, 41, 14);
1049 assert_eq!(A::iter_prefix_values(3).collect::<Vec<_>>(), vec![12, 11]);
1050 assert_eq!(A::iter_prefix(3).collect::<Vec<_>>(), vec![(31, 12), (30, 11)]);
1051 assert_eq!(A::iter_prefix_values(4).collect::<Vec<_>>(), vec![13, 14]);
1052 assert_eq!(A::iter_prefix(4).collect::<Vec<_>>(), vec![(40, 13), (41, 14)]);
1053
1054 let _ = A::clear_prefix(3, u32::max_value(), None);
1055 assert_eq!(A::iter_prefix(3).collect::<Vec<_>>(), vec![]);
1056 assert_eq!(A::iter_prefix(4).collect::<Vec<_>>(), vec![(40, 13), (41, 14)]);
1057
1058 assert_eq!(A::drain_prefix(4).collect::<Vec<_>>(), vec![(40, 13), (41, 14)]);
1059 assert_eq!(A::iter_prefix(4).collect::<Vec<_>>(), vec![]);
1060 assert_eq!(A::drain_prefix(4).collect::<Vec<_>>(), vec![]);
1061 })
1062 }
1063
1064 #[docify::export]
1065 #[test]
1066 fn example_double_map_partial_operations() {
1067 type FooDoubleMap =
1068 StorageDoubleMap<Prefix, Blake2_128Concat, u32, Blake2_128Concat, u32, u32, ValueQuery>;
1069
1070 TestExternalities::default().execute_with(|| {
1071 FooDoubleMap::insert(0, 0, 42);
1072 FooDoubleMap::insert(0, 1, 43);
1073 FooDoubleMap::insert(1, 0, 314);
1074
1075 let collected_k2_keys: BTreeSet<_> = FooDoubleMap::iter_key_prefix(0).collect();
1077 assert_eq!(collected_k2_keys, [0, 1].iter().copied().collect::<BTreeSet<_>>());
1078
1079 let collected_k2_values: BTreeSet<_> = FooDoubleMap::iter_prefix_values(0).collect();
1081 assert_eq!(collected_k2_values, [42, 43].iter().copied().collect::<BTreeSet<_>>());
1082
1083 let _ = FooDoubleMap::clear_prefix(0, u32::max_value(), None);
1085 assert_eq!(FooDoubleMap::iter_prefix(0).collect::<Vec<_>>(), vec![]);
1087 });
1088 }
1089}