@aztec/kv-store 0.66.0 → 0.67.1-devnet
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/indexeddb/array.d.ts +21 -0
- package/dest/indexeddb/array.d.ts.map +1 -0
- package/dest/indexeddb/array.js +96 -0
- package/dest/indexeddb/index.d.ts +7 -0
- package/dest/indexeddb/index.d.ts.map +1 -0
- package/dest/indexeddb/index.js +22 -0
- package/dest/indexeddb/map.d.ts +26 -0
- package/dest/indexeddb/map.d.ts.map +1 -0
- package/dest/indexeddb/map.js +104 -0
- package/dest/indexeddb/set.d.ts +17 -0
- package/dest/indexeddb/set.d.ts.map +1 -0
- package/dest/indexeddb/set.js +25 -0
- package/dest/indexeddb/singleton.d.ts +16 -0
- package/dest/indexeddb/singleton.d.ts.map +1 -0
- package/dest/indexeddb/singleton.js +42 -0
- package/dest/indexeddb/store.d.ts +100 -0
- package/dest/indexeddb/store.d.ts.map +1 -0
- package/dest/indexeddb/store.js +157 -0
- package/dest/interfaces/array.d.ts +43 -11
- package/dest/interfaces/array.d.ts.map +1 -1
- package/dest/interfaces/array_test_suite.d.ts +3 -0
- package/dest/interfaces/array_test_suite.d.ts.map +1 -0
- package/dest/interfaces/array_test_suite.js +100 -0
- package/dest/interfaces/counter.d.ts +21 -1
- package/dest/interfaces/counter.d.ts.map +1 -1
- package/dest/interfaces/map.d.ts +80 -12
- package/dest/interfaces/map.d.ts.map +1 -1
- package/dest/interfaces/map_test_suite.d.ts +3 -0
- package/dest/interfaces/map_test_suite.d.ts.map +1 -0
- package/dest/interfaces/map_test_suite.js +117 -0
- package/dest/interfaces/set.d.ts +23 -7
- package/dest/interfaces/set.d.ts.map +1 -1
- package/dest/interfaces/set_test_suite.d.ts +3 -0
- package/dest/interfaces/set_test_suite.d.ts.map +1 -0
- package/dest/interfaces/set_test_suite.js +59 -0
- package/dest/interfaces/singleton.d.ts +14 -5
- package/dest/interfaces/singleton.d.ts.map +1 -1
- package/dest/interfaces/singleton_test_suite.d.ts +3 -0
- package/dest/interfaces/singleton_test_suite.d.ts.map +1 -0
- package/dest/interfaces/singleton_test_suite.js +33 -0
- package/dest/interfaces/store.d.ts +83 -8
- package/dest/interfaces/store.d.ts.map +1 -1
- package/dest/interfaces/store_test_suite.d.ts +3 -0
- package/dest/interfaces/store_test_suite.d.ts.map +1 -0
- package/dest/interfaces/store_test_suite.js +40 -0
- package/dest/interfaces/utils.d.ts +16 -0
- package/dest/interfaces/utils.d.ts.map +1 -0
- package/dest/interfaces/utils.js +19 -0
- package/dest/lmdb/array.d.ts +7 -2
- package/dest/lmdb/array.d.ts.map +1 -1
- package/dest/lmdb/array.js +20 -1
- package/dest/lmdb/counter.d.ts +5 -2
- package/dest/lmdb/counter.d.ts.map +1 -1
- package/dest/lmdb/counter.js +10 -1
- package/dest/lmdb/index.d.ts +10 -0
- package/dest/lmdb/index.d.ts.map +1 -1
- package/dest/lmdb/index.js +28 -1
- package/dest/lmdb/map.d.ts +25 -3
- package/dest/lmdb/map.d.ts.map +1 -1
- package/dest/lmdb/map.js +112 -26
- package/dest/lmdb/set.d.ts +4 -2
- package/dest/lmdb/set.d.ts.map +1 -1
- package/dest/lmdb/set.js +9 -1
- package/dest/lmdb/singleton.d.ts +3 -2
- package/dest/lmdb/singleton.d.ts.map +1 -1
- package/dest/lmdb/singleton.js +4 -1
- package/dest/lmdb/store.d.ts +35 -15
- package/dest/lmdb/store.d.ts.map +1 -1
- package/dest/lmdb/store.js +47 -27
- package/dest/stores/l2_tips_store.d.ts +2 -2
- package/dest/stores/l2_tips_store.d.ts.map +1 -1
- package/dest/stores/l2_tips_store.js +13 -13
- package/dest/utils.d.ts +8 -7
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +6 -29
- package/package.json +54 -37
- package/src/indexeddb/array.ts +118 -0
- package/src/indexeddb/index.ts +29 -0
- package/src/indexeddb/map.ts +142 -0
- package/src/indexeddb/set.ts +37 -0
- package/src/indexeddb/singleton.ts +49 -0
- package/src/indexeddb/store.ts +193 -0
- package/src/interfaces/array.ts +48 -12
- package/src/interfaces/array_test_suite.ts +130 -0
- package/src/interfaces/counter.ts +23 -1
- package/src/interfaces/map.ts +90 -14
- package/src/interfaces/map_test_suite.ts +158 -0
- package/src/interfaces/set.ts +25 -8
- package/src/interfaces/set_test_suite.ts +81 -0
- package/src/interfaces/singleton.ts +14 -6
- package/src/interfaces/singleton_test_suite.ts +46 -0
- package/src/interfaces/store.ts +99 -8
- package/src/interfaces/store_test_suite.ts +56 -0
- package/src/interfaces/utils.ts +21 -0
- package/src/lmdb/array.ts +26 -2
- package/src/lmdb/counter.ts +14 -2
- package/src/lmdb/index.ts +36 -0
- package/src/lmdb/map.ts +130 -23
- package/src/lmdb/set.ts +12 -2
- package/src/lmdb/singleton.ts +6 -2
- package/src/lmdb/store.ts +73 -43
- package/src/stores/l2_tips_store.ts +17 -17
- package/src/utils.ts +8 -37
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { toArray } from '@aztec/foundation/iterable';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
|
|
5
|
+
import { type AztecArray, type AztecAsyncArray } from './array.js';
|
|
6
|
+
import { type AztecAsyncKVStore, type AztecKVStore } from './store.js';
|
|
7
|
+
import { isSyncStore } from './utils.js';
|
|
8
|
+
|
|
9
|
+
export function describeAztecArray(
|
|
10
|
+
testName: string,
|
|
11
|
+
getStore: () => AztecKVStore | Promise<AztecAsyncKVStore>,
|
|
12
|
+
forceAsync: boolean = false,
|
|
13
|
+
) {
|
|
14
|
+
describe(testName, () => {
|
|
15
|
+
let store: AztecKVStore | AztecAsyncKVStore;
|
|
16
|
+
let arr: AztecArray<number> | AztecAsyncArray<number>;
|
|
17
|
+
|
|
18
|
+
beforeEach(async () => {
|
|
19
|
+
store = await getStore();
|
|
20
|
+
arr = store.openArray<number>('test');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
await store.delete();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
async function length(sut: AztecAsyncArray<number> | AztecArray<number> = arr) {
|
|
28
|
+
return isSyncStore(store) && !forceAsync
|
|
29
|
+
? (sut as AztecArray<number>).length
|
|
30
|
+
: await (sut as AztecAsyncArray<number>).lengthAsync();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function at(index: number) {
|
|
34
|
+
return isSyncStore(store) && !forceAsync
|
|
35
|
+
? (arr as AztecArray<number>).at(index)
|
|
36
|
+
: await (arr as AztecAsyncArray<number>).atAsync(index);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function entries() {
|
|
40
|
+
return isSyncStore(store) && !forceAsync
|
|
41
|
+
? await toArray((arr as AztecArray<number>).entries())
|
|
42
|
+
: await toArray((arr as AztecAsyncArray<number>).entriesAsync());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function values(sut: AztecAsyncArray<number> | AztecArray<number> = arr) {
|
|
46
|
+
return isSyncStore(store) && !forceAsync
|
|
47
|
+
? await toArray((sut as AztecArray<number>).values())
|
|
48
|
+
: await toArray((sut as AztecAsyncArray<number>).valuesAsync());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
it('should be able to push and pop values', async () => {
|
|
52
|
+
await arr.push(1);
|
|
53
|
+
await arr.push(2);
|
|
54
|
+
await arr.push(3);
|
|
55
|
+
|
|
56
|
+
expect(await length()).to.equal(3);
|
|
57
|
+
|
|
58
|
+
expect(await arr.pop()).to.equal(3);
|
|
59
|
+
expect(await arr.pop()).to.equal(2);
|
|
60
|
+
expect(await arr.pop()).to.equal(1);
|
|
61
|
+
expect(await arr.pop()).to.equal(undefined);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should be able to get values by index', async () => {
|
|
65
|
+
await arr.push(1);
|
|
66
|
+
await arr.push(2);
|
|
67
|
+
await arr.push(3);
|
|
68
|
+
|
|
69
|
+
expect(await at(0)).to.equal(1);
|
|
70
|
+
expect(await at(1)).to.equal(2);
|
|
71
|
+
expect(await at(2)).to.equal(3);
|
|
72
|
+
expect(await at(3)).to.equal(undefined);
|
|
73
|
+
expect(await at(-1)).to.equal(3);
|
|
74
|
+
expect(await at(-2)).to.equal(2);
|
|
75
|
+
expect(await at(-3)).to.equal(1);
|
|
76
|
+
expect(await at(-4)).to.equal(undefined);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should be able to set values by index', async () => {
|
|
80
|
+
await arr.push(1);
|
|
81
|
+
await arr.push(2);
|
|
82
|
+
await arr.push(3);
|
|
83
|
+
|
|
84
|
+
expect(await arr.setAt(0, 4)).to.equal(true);
|
|
85
|
+
expect(await arr.setAt(1, 5)).to.equal(true);
|
|
86
|
+
expect(await arr.setAt(2, 6)).to.equal(true);
|
|
87
|
+
|
|
88
|
+
expect(await arr.setAt(3, 7)).to.equal(false);
|
|
89
|
+
|
|
90
|
+
expect(await at(0)).to.equal(4);
|
|
91
|
+
expect(await at(1)).to.equal(5);
|
|
92
|
+
expect(await at(2)).to.equal(6);
|
|
93
|
+
expect(await at(3)).to.equal(undefined);
|
|
94
|
+
|
|
95
|
+
expect(await arr.setAt(-1, 8)).to.equal(true);
|
|
96
|
+
expect(await arr.setAt(-2, 9)).to.equal(true);
|
|
97
|
+
expect(await arr.setAt(-3, 10)).to.equal(true);
|
|
98
|
+
|
|
99
|
+
expect(await arr.setAt(-4, 11)).to.equal(false);
|
|
100
|
+
|
|
101
|
+
expect(await at(-1)).to.equal(8);
|
|
102
|
+
expect(await at(-2)).to.equal(9);
|
|
103
|
+
expect(await at(-3)).to.equal(10);
|
|
104
|
+
expect(await at(-4)).to.equal(undefined);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should be able to iterate over values', async () => {
|
|
108
|
+
await arr.push(1);
|
|
109
|
+
await arr.push(2);
|
|
110
|
+
await arr.push(3);
|
|
111
|
+
|
|
112
|
+
expect(await values()).to.deep.equal([1, 2, 3]);
|
|
113
|
+
expect(await entries()).to.deep.equal([
|
|
114
|
+
[0, 1],
|
|
115
|
+
[1, 2],
|
|
116
|
+
[2, 3],
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should be able to restore state', async () => {
|
|
121
|
+
await arr.push(1);
|
|
122
|
+
await arr.push(2);
|
|
123
|
+
await arr.push(3);
|
|
124
|
+
|
|
125
|
+
const arr2 = store.openArray<number>('test');
|
|
126
|
+
expect(await length(arr2)).to.equal(3);
|
|
127
|
+
expect(await values(arr2)).to.deep.equal(await values());
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
@@ -6,7 +6,7 @@ import { type Key, type Range } from './common.js';
|
|
|
6
6
|
*
|
|
7
7
|
* Keys are stored in sorted order
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
interface AztecBaseCounter<K extends Key = Key> {
|
|
10
10
|
/**
|
|
11
11
|
* Resets the count of the given key to the given value.
|
|
12
12
|
* @param key - The key to reset
|
|
@@ -22,7 +22,9 @@ export interface AztecCounter<K extends Key = Key> {
|
|
|
22
22
|
* @param delta - The amount to modify the key by
|
|
23
23
|
*/
|
|
24
24
|
update(key: K, delta: number): Promise<void>;
|
|
25
|
+
}
|
|
25
26
|
|
|
27
|
+
export interface AztecCounter<K extends Key = Key> extends AztecBaseCounter<K> {
|
|
26
28
|
/**
|
|
27
29
|
* Gets the current count.
|
|
28
30
|
* @param key - The key to get the count of
|
|
@@ -41,3 +43,23 @@ export interface AztecCounter<K extends Key = Key> {
|
|
|
41
43
|
*/
|
|
42
44
|
entries(range: Range<K>): IterableIterator<[K, number]>;
|
|
43
45
|
}
|
|
46
|
+
|
|
47
|
+
export interface AztecAsyncCounter<K extends Key = Key> extends AztecBaseCounter<K> {
|
|
48
|
+
/**
|
|
49
|
+
* Gets the current count.
|
|
50
|
+
* @param key - The key to get the count of
|
|
51
|
+
*/
|
|
52
|
+
getAsync(key: K): Promise<number>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns keys in the map in sorted order. Only returns keys that have been seen at least once.
|
|
56
|
+
* @param range - The range of keys to iterate over
|
|
57
|
+
*/
|
|
58
|
+
keysAsync(range: Range<K>): AsyncIterableIterator<K>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns keys and their counts in the map sorted by the key. Only returns keys that have been seen at least once.
|
|
62
|
+
* @param range - The range of keys to iterate over
|
|
63
|
+
*/
|
|
64
|
+
entriesAsync(range: Range<K>): AsyncIterableIterator<[K, number]>;
|
|
65
|
+
}
|
package/src/interfaces/map.ts
CHANGED
|
@@ -3,20 +3,7 @@ import { type Key, type Range } from './common.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* A map backed by a persistent store.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Gets the value at the given key.
|
|
9
|
-
* @param key - The key to get the value from
|
|
10
|
-
*/
|
|
11
|
-
get(key: K): V | undefined;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Checks if a key exists in the map.
|
|
15
|
-
* @param key - The key to check
|
|
16
|
-
* @returns True if the key exists, false otherwise
|
|
17
|
-
*/
|
|
18
|
-
has(key: K): boolean;
|
|
19
|
-
|
|
6
|
+
interface AztecBaseMap<K extends Key, V> {
|
|
20
7
|
/**
|
|
21
8
|
* Sets the value at the given key.
|
|
22
9
|
* @param key - The key to set the value at
|
|
@@ -43,6 +30,20 @@ export interface AztecMap<K extends Key, V> {
|
|
|
43
30
|
* @param key - The key to delete the value at
|
|
44
31
|
*/
|
|
45
32
|
delete(key: K): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export interface AztecMap<K extends Key, V> extends AztecBaseMap<K, V> {
|
|
35
|
+
/**
|
|
36
|
+
* Gets the value at the given key.
|
|
37
|
+
* @param key - The key to get the value from
|
|
38
|
+
*/
|
|
39
|
+
get(key: K): V | undefined;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Checks if a key exists in the map.
|
|
43
|
+
* @param key - The key to check
|
|
44
|
+
* @returns True if the key exists, false otherwise
|
|
45
|
+
*/
|
|
46
|
+
has(key: K): boolean;
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
49
|
* Iterates over the map's key-value entries in the key's natural order
|
|
@@ -61,6 +62,19 @@ export interface AztecMap<K extends Key, V> {
|
|
|
61
62
|
* @param range - The range of keys to iterate over
|
|
62
63
|
*/
|
|
63
64
|
keys(range?: Range<K>): IterableIterator<K>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Clears the map.
|
|
68
|
+
*/
|
|
69
|
+
clear(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface AztecMapWithSize<K extends Key, V> extends AztecMap<K, V> {
|
|
73
|
+
/**
|
|
74
|
+
* Gets the size of the map.
|
|
75
|
+
* @returns The size of the map
|
|
76
|
+
*/
|
|
77
|
+
size(): number;
|
|
64
78
|
}
|
|
65
79
|
|
|
66
80
|
/**
|
|
@@ -80,3 +94,65 @@ export interface AztecMultiMap<K extends Key, V> extends AztecMap<K, V> {
|
|
|
80
94
|
*/
|
|
81
95
|
deleteValue(key: K, val: V): Promise<void>;
|
|
82
96
|
}
|
|
97
|
+
|
|
98
|
+
export interface AztecMultiMapWithSize<K extends Key, V> extends AztecMultiMap<K, V> {
|
|
99
|
+
/**
|
|
100
|
+
* Gets the size of the map.
|
|
101
|
+
* @returns The size of the map
|
|
102
|
+
*/
|
|
103
|
+
size(): number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A map backed by a persistent store.
|
|
108
|
+
*/
|
|
109
|
+
export interface AztecAsyncMap<K extends Key, V> extends AztecBaseMap<K, V> {
|
|
110
|
+
/**
|
|
111
|
+
* Gets the value at the given key.
|
|
112
|
+
* @param key - The key to get the value from
|
|
113
|
+
*/
|
|
114
|
+
getAsync(key: K): Promise<V | undefined>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Checks if a key exists in the map.
|
|
118
|
+
* @param key - The key to check
|
|
119
|
+
* @returns True if the key exists, false otherwise
|
|
120
|
+
*/
|
|
121
|
+
hasAsync(key: K): Promise<boolean>;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Iterates over the map's key-value entries in the key's natural order
|
|
125
|
+
* @param range - The range of keys to iterate over
|
|
126
|
+
*/
|
|
127
|
+
entriesAsync(range?: Range<K>): AsyncIterableIterator<[K, V]>;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Iterates over the map's values in the key's natural order
|
|
131
|
+
* @param range - The range of keys to iterate over
|
|
132
|
+
*/
|
|
133
|
+
valuesAsync(range?: Range<K>): AsyncIterableIterator<V>;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Iterates over the map's keys in the key's natural order
|
|
137
|
+
* @param range - The range of keys to iterate over
|
|
138
|
+
*/
|
|
139
|
+
keysAsync(range?: Range<K>): AsyncIterableIterator<K>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* A map backed by a persistent store that can have multiple values for a single key.
|
|
144
|
+
*/
|
|
145
|
+
export interface AztecAsyncMultiMap<K extends Key, V> extends AztecAsyncMap<K, V> {
|
|
146
|
+
/**
|
|
147
|
+
* Gets all the values at the given key.
|
|
148
|
+
* @param key - The key to get the values from
|
|
149
|
+
*/
|
|
150
|
+
getValuesAsync(key: K): AsyncIterableIterator<V>;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Deletes a specific value at the given key.
|
|
154
|
+
* @param key - The key to delete the value at
|
|
155
|
+
* @param val - The value to delete
|
|
156
|
+
*/
|
|
157
|
+
deleteValue(key: K, val: V): Promise<void>;
|
|
158
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { toArray } from '@aztec/foundation/iterable';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
|
|
5
|
+
import { type Key, type Range } from './common.js';
|
|
6
|
+
import { type AztecAsyncMap, type AztecAsyncMultiMap, type AztecMap, type AztecMultiMap } from './map.js';
|
|
7
|
+
import { type AztecAsyncKVStore, type AztecKVStore } from './store.js';
|
|
8
|
+
import { isSyncStore } from './utils.js';
|
|
9
|
+
|
|
10
|
+
export function describeAztecMap(
|
|
11
|
+
testName: string,
|
|
12
|
+
getStore: () => AztecKVStore | Promise<AztecAsyncKVStore>,
|
|
13
|
+
forceAsync: boolean = false,
|
|
14
|
+
) {
|
|
15
|
+
describe(testName, () => {
|
|
16
|
+
let store: AztecKVStore | AztecAsyncKVStore;
|
|
17
|
+
let map: AztecMultiMap<Key, string> | AztecAsyncMultiMap<Key, string>;
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
store = await getStore();
|
|
21
|
+
map = store.openMultiMap<string | [number, string], string>('test');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
await store.delete();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
async function get(key: Key, sut: AztecAsyncMap<any, any> | AztecMap<any, any> = map) {
|
|
29
|
+
return isSyncStore(store) && !forceAsync
|
|
30
|
+
? (sut as AztecMultiMap<any, any>).get(key)
|
|
31
|
+
: await (sut as AztecAsyncMultiMap<any, any>).getAsync(key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function entries() {
|
|
35
|
+
return isSyncStore(store) && !forceAsync
|
|
36
|
+
? await toArray((map as AztecMultiMap<any, any>).entries())
|
|
37
|
+
: await toArray((map as AztecAsyncMultiMap<any, any>).entriesAsync());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function values() {
|
|
41
|
+
return isSyncStore(store) && !forceAsync
|
|
42
|
+
? await toArray((map as AztecMultiMap<any, any>).values())
|
|
43
|
+
: await toArray((map as AztecAsyncMultiMap<any, any>).valuesAsync());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function keys(range?: Range<Key>, sut: AztecAsyncMap<any, any> | AztecMap<any, any> = map) {
|
|
47
|
+
return isSyncStore(store) && !forceAsync
|
|
48
|
+
? await toArray((sut as AztecMultiMap<any, any>).keys(range))
|
|
49
|
+
: await toArray((sut as AztecAsyncMultiMap<any, any>).keysAsync(range));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function getValues(key: Key) {
|
|
53
|
+
return isSyncStore(store) && !forceAsync
|
|
54
|
+
? await toArray((map as AztecMultiMap<any, any>).getValues(key))
|
|
55
|
+
: await toArray((map as AztecAsyncMultiMap<any, any>).getValuesAsync(key));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
it('should be able to set and get values', async () => {
|
|
59
|
+
await map.set('foo', 'bar');
|
|
60
|
+
await map.set('baz', 'qux');
|
|
61
|
+
|
|
62
|
+
expect(await get('foo')).to.equal('bar');
|
|
63
|
+
expect(await get('baz')).to.equal('qux');
|
|
64
|
+
expect(await get('quux')).to.equal(undefined);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should be able to set values if they do not exist', async () => {
|
|
68
|
+
expect(await map.setIfNotExists('foo', 'bar')).to.equal(true);
|
|
69
|
+
expect(await map.setIfNotExists('foo', 'baz')).to.equal(false);
|
|
70
|
+
|
|
71
|
+
expect(await get('foo')).to.equal('bar');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should be able to delete values', async () => {
|
|
75
|
+
await map.set('foo', 'bar');
|
|
76
|
+
await map.set('baz', 'qux');
|
|
77
|
+
|
|
78
|
+
await map.delete('foo');
|
|
79
|
+
|
|
80
|
+
expect(await get('foo')).to.equal(undefined);
|
|
81
|
+
expect(await get('baz')).to.equal('qux');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should be able to iterate over entries when there are no keys', async () => {
|
|
85
|
+
expect(await entries()).to.deep.equal([]);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should be able to iterate over entries', async () => {
|
|
89
|
+
await map.set('foo', 'bar');
|
|
90
|
+
await map.set('baz', 'qux');
|
|
91
|
+
|
|
92
|
+
expect(await entries()).to.deep.equal([
|
|
93
|
+
['baz', 'qux'],
|
|
94
|
+
['foo', 'bar'],
|
|
95
|
+
]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should be able to iterate over values', async () => {
|
|
99
|
+
await map.set('foo', 'bar');
|
|
100
|
+
await map.set('baz', 'quux');
|
|
101
|
+
|
|
102
|
+
expect(await values()).to.deep.equal(['quux', 'bar']);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should be able to iterate over keys', async () => {
|
|
106
|
+
await map.set('foo', 'bar');
|
|
107
|
+
await map.set('baz', 'qux');
|
|
108
|
+
|
|
109
|
+
expect(await keys()).to.deep.equal(['baz', 'foo']);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should be able to get multiple values for a single key', async () => {
|
|
113
|
+
await map.set('foo', 'bar');
|
|
114
|
+
await map.set('foo', 'baz');
|
|
115
|
+
|
|
116
|
+
expect(await getValues('foo')).to.deep.equal(['bar', 'baz']);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should be able to delete individual values for a single key', async () => {
|
|
120
|
+
await map.set('foo', 'bar');
|
|
121
|
+
await map.set('foo', 'baz');
|
|
122
|
+
|
|
123
|
+
await map.deleteValue('foo', 'bar');
|
|
124
|
+
|
|
125
|
+
expect(await getValues('foo')).to.deep.equal(['baz']);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('supports tuple keys', async () => {
|
|
129
|
+
// Use a new map because key structure has changed
|
|
130
|
+
const tupleMap = store.openMap<[number, string], string>('test-tuple');
|
|
131
|
+
|
|
132
|
+
await tupleMap.set([5, 'bar'], 'val');
|
|
133
|
+
await tupleMap.set([0, 'foo'], 'val');
|
|
134
|
+
|
|
135
|
+
expect(await keys(undefined, tupleMap)).to.deep.equal([
|
|
136
|
+
[0, 'foo'],
|
|
137
|
+
[5, 'bar'],
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
expect(await get([5, 'bar'], tupleMap)).to.equal('val');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('supports range queries', async () => {
|
|
144
|
+
await map.set('a', 'a');
|
|
145
|
+
await map.set('b', 'b');
|
|
146
|
+
await map.set('c', 'c');
|
|
147
|
+
await map.set('d', 'd');
|
|
148
|
+
|
|
149
|
+
expect(await keys({ start: 'b', end: 'c' })).to.deep.equal(['b']);
|
|
150
|
+
expect(await keys({ start: 'b' })).to.deep.equal(['b', 'c', 'd']);
|
|
151
|
+
expect(await keys({ end: 'c' })).to.deep.equal(['a', 'b']);
|
|
152
|
+
expect(await keys({ start: 'b', end: 'c', reverse: true })).to.deep.equal(['c']);
|
|
153
|
+
expect(await keys({ start: 'b', limit: 1 })).to.deep.equal(['b']);
|
|
154
|
+
expect(await keys({ start: 'b', reverse: true })).to.deep.equal(['d', 'c']);
|
|
155
|
+
expect(await keys({ end: 'b', reverse: true })).to.deep.equal(['b', 'a']);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
}
|
package/src/interfaces/set.ts
CHANGED
|
@@ -3,14 +3,7 @@ import { type Key, type Range } from './common.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* A set backed by a persistent store.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Checks if a key exists in the set.
|
|
9
|
-
* @param key - The key to check
|
|
10
|
-
* @returns True if the key exists, false otherwise
|
|
11
|
-
*/
|
|
12
|
-
has(key: K): boolean;
|
|
13
|
-
|
|
6
|
+
interface AztecBaseSet<K extends Key> {
|
|
14
7
|
/**
|
|
15
8
|
* Adds the given value.
|
|
16
9
|
* @param key - The key to add.
|
|
@@ -22,6 +15,15 @@ export interface AztecSet<K extends Key> {
|
|
|
22
15
|
* @param key - The key to delete.
|
|
23
16
|
*/
|
|
24
17
|
delete(key: K): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AztecSet<K extends Key> extends AztecBaseSet<K> {
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a key exists in the set.
|
|
23
|
+
* @param key - The key to check
|
|
24
|
+
* @returns True if the key exists, false otherwise
|
|
25
|
+
*/
|
|
26
|
+
has(key: K): boolean;
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Iterates over the sets's keys entries in the key's natural order
|
|
@@ -29,3 +31,18 @@ export interface AztecSet<K extends Key> {
|
|
|
29
31
|
*/
|
|
30
32
|
entries(range?: Range<K>): IterableIterator<K>;
|
|
31
33
|
}
|
|
34
|
+
|
|
35
|
+
export interface AztecAsyncSet<K extends Key> extends AztecBaseSet<K> {
|
|
36
|
+
/**
|
|
37
|
+
* Checks if a key exists in the set.
|
|
38
|
+
* @param key - The key to check
|
|
39
|
+
* @returns True if the key exists, false otherwise
|
|
40
|
+
*/
|
|
41
|
+
hasAsync(key: K): Promise<boolean>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Iterates over the sets's keys entries in the key's natural order
|
|
45
|
+
* @param range - The range of keys to iterate over
|
|
46
|
+
*/
|
|
47
|
+
entriesAsync(range?: Range<K>): AsyncIterableIterator<K>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { toArray } from '@aztec/foundation/iterable';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
|
|
5
|
+
import { type Range } from './common.js';
|
|
6
|
+
import { type AztecAsyncSet, type AztecSet } from './set.js';
|
|
7
|
+
import { type AztecAsyncKVStore, type AztecKVStore } from './store.js';
|
|
8
|
+
import { isSyncStore } from './utils.js';
|
|
9
|
+
|
|
10
|
+
export function describeAztecSet(
|
|
11
|
+
testName: string,
|
|
12
|
+
getStore: () => AztecKVStore | Promise<AztecAsyncKVStore>,
|
|
13
|
+
forceAsync: boolean = false,
|
|
14
|
+
) {
|
|
15
|
+
describe(testName, () => {
|
|
16
|
+
let store: AztecKVStore | AztecAsyncKVStore;
|
|
17
|
+
let set: AztecSet<string> | AztecAsyncSet<string>;
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
store = await getStore();
|
|
21
|
+
set = store.openSet<string>('test');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
await store.delete();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
async function has(key: string) {
|
|
29
|
+
return isSyncStore(store) && !forceAsync
|
|
30
|
+
? (set as AztecSet<string>).has(key)
|
|
31
|
+
: await (set as AztecAsyncSet<string>).hasAsync(key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function entries(range?: Range<any>) {
|
|
35
|
+
return isSyncStore(store) && !forceAsync
|
|
36
|
+
? await toArray((set as AztecSet<string>).entries(range))
|
|
37
|
+
: await toArray((set as AztecAsyncSet<string>).entriesAsync(range));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it('should be able to set and get values', async () => {
|
|
41
|
+
await set.add('foo');
|
|
42
|
+
await set.add('baz');
|
|
43
|
+
|
|
44
|
+
expect(await has('foo')).to.equal(true);
|
|
45
|
+
expect(await has('baz')).to.equal(true);
|
|
46
|
+
expect(await has('bar')).to.equal(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should be able to delete values', async () => {
|
|
50
|
+
await set.add('foo');
|
|
51
|
+
await set.add('baz');
|
|
52
|
+
|
|
53
|
+
await set.delete('foo');
|
|
54
|
+
|
|
55
|
+
expect(await has('foo')).to.equal(false);
|
|
56
|
+
expect(await has('baz')).to.equal(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should be able to iterate over entries', async () => {
|
|
60
|
+
await set.add('baz');
|
|
61
|
+
await set.add('foo');
|
|
62
|
+
|
|
63
|
+
expect(await entries()).to.deep.equal(['baz', 'foo']);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('supports range queries', async () => {
|
|
67
|
+
await set.add('a');
|
|
68
|
+
await set.add('b');
|
|
69
|
+
await set.add('c');
|
|
70
|
+
await set.add('d');
|
|
71
|
+
|
|
72
|
+
expect(await entries({ start: 'b', end: 'c' })).to.deep.equal(['b']);
|
|
73
|
+
expect(await entries({ start: 'b' })).to.deep.equal(['b', 'c', 'd']);
|
|
74
|
+
expect(await entries({ end: 'c' })).to.deep.equal(['a', 'b']);
|
|
75
|
+
expect(await entries({ start: 'b', end: 'c', reverse: true })).to.deep.equal(['c']);
|
|
76
|
+
expect(await entries({ start: 'b', limit: 1 })).to.deep.equal(['b']);
|
|
77
|
+
expect(await entries({ start: 'b', reverse: true })).to.deep.equal(['d', 'c']);
|
|
78
|
+
expect(await entries({ end: 'b', reverse: true })).to.deep.equal(['b', 'a']);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -2,12 +2,7 @@
|
|
|
2
2
|
* Represents a singleton value in the database.
|
|
3
3
|
* Note: The singleton loses type info so it's recommended to serialize to buffer when storing it.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Gets the value.
|
|
8
|
-
*/
|
|
9
|
-
get(): T | undefined;
|
|
10
|
-
|
|
5
|
+
interface AztecBaseSingleton<T> {
|
|
11
6
|
/**
|
|
12
7
|
* Sets the value.
|
|
13
8
|
* @param val - The new value
|
|
@@ -19,3 +14,16 @@ export interface AztecSingleton<T> {
|
|
|
19
14
|
*/
|
|
20
15
|
delete(): Promise<boolean>;
|
|
21
16
|
}
|
|
17
|
+
export interface AztecSingleton<T> extends AztecBaseSingleton<T> {
|
|
18
|
+
/**
|
|
19
|
+
* Gets the value.
|
|
20
|
+
*/
|
|
21
|
+
get(): T | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface AztecAsyncSingleton<T> extends AztecBaseSingleton<T> {
|
|
25
|
+
/**
|
|
26
|
+
* Gets the value.
|
|
27
|
+
*/
|
|
28
|
+
getAsync(): Promise<T | undefined>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
|
|
3
|
+
import { type AztecAsyncSingleton, type AztecSingleton } from './singleton.js';
|
|
4
|
+
import { type AztecAsyncKVStore, type AztecKVStore } from './store.js';
|
|
5
|
+
import { isSyncStore } from './utils.js';
|
|
6
|
+
|
|
7
|
+
export function describeAztecSingleton(
|
|
8
|
+
testName: string,
|
|
9
|
+
getStore: () => AztecKVStore | Promise<AztecAsyncKVStore>,
|
|
10
|
+
forceAsync: boolean = false,
|
|
11
|
+
) {
|
|
12
|
+
describe(testName, () => {
|
|
13
|
+
let store: AztecKVStore | AztecAsyncKVStore;
|
|
14
|
+
let singleton: AztecSingleton<string> | AztecAsyncSingleton<string>;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
store = await getStore();
|
|
18
|
+
singleton = store.openSingleton<string>('test');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(async () => {
|
|
22
|
+
await store.delete();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
async function get() {
|
|
26
|
+
return isSyncStore(store) && !forceAsync
|
|
27
|
+
? (singleton as AztecSingleton<string>).get()
|
|
28
|
+
: await (singleton as AztecAsyncSingleton<string>).getAsync();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
it('returns undefined if the value is not set', async () => {
|
|
32
|
+
expect(await get()).to.equal(undefined);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should be able to set and get values', async () => {
|
|
36
|
+
expect(await singleton.set('foo')).to.equal(true);
|
|
37
|
+
expect(await get()).to.equal('foo');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('overwrites the value if it is set again', async () => {
|
|
41
|
+
expect(await singleton.set('foo')).to.equal(true);
|
|
42
|
+
expect(await singleton.set('bar')).to.equal(true);
|
|
43
|
+
expect(await get()).to.equal('bar');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|