@aztec/kv-store 0.81.0 → 0.82.0
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/config.d.ts.map +1 -1
- package/dest/config.js +3 -1
- package/dest/indexeddb/map.d.ts +5 -4
- package/dest/indexeddb/map.d.ts.map +1 -1
- package/dest/indexeddb/map.js +13 -53
- package/dest/indexeddb/multi_map.d.ts +12 -0
- package/dest/indexeddb/multi_map.d.ts.map +1 -0
- package/dest/indexeddb/multi_map.js +54 -0
- package/dest/indexeddb/store.d.ts +2 -1
- package/dest/indexeddb/store.d.ts.map +1 -1
- package/dest/indexeddb/store.js +2 -1
- package/dest/interfaces/index.d.ts +1 -0
- package/dest/interfaces/index.d.ts.map +1 -1
- package/dest/interfaces/index.js +1 -0
- package/dest/interfaces/map.d.ts +0 -46
- package/dest/interfaces/map.d.ts.map +1 -1
- package/dest/interfaces/map.js +1 -1
- package/dest/interfaces/map_test_suite.d.ts.map +1 -1
- package/dest/interfaces/map_test_suite.js +6 -20
- package/dest/interfaces/multi_map.d.ts +35 -0
- package/dest/interfaces/multi_map.d.ts.map +1 -0
- package/dest/interfaces/multi_map.js +3 -0
- package/dest/interfaces/multi_map_test_suite.d.ts +3 -0
- package/dest/interfaces/multi_map_test_suite.d.ts.map +1 -0
- package/dest/interfaces/multi_map_test_suite.js +151 -0
- package/dest/interfaces/store.d.ts +2 -13
- package/dest/interfaces/store.d.ts.map +1 -1
- package/dest/lmdb/map.d.ts +2 -18
- package/dest/lmdb/map.d.ts.map +1 -1
- package/dest/lmdb/map.js +0 -81
- package/dest/lmdb/multi_map.d.ts +12 -0
- package/dest/lmdb/multi_map.d.ts.map +1 -0
- package/dest/lmdb/multi_map.js +29 -0
- package/dest/lmdb/store.d.ts +2 -13
- package/dest/lmdb/store.d.ts.map +1 -1
- package/dest/lmdb/store.js +3 -16
- package/dest/lmdb-v2/array.d.ts.map +1 -1
- package/dest/lmdb-v2/array.js +1 -0
- package/dest/lmdb-v2/map.d.ts +1 -43
- package/dest/lmdb-v2/map.d.ts.map +1 -1
- package/dest/lmdb-v2/map.js +1 -100
- package/dest/lmdb-v2/multi_map.d.ts +46 -0
- package/dest/lmdb-v2/multi_map.d.ts.map +1 -0
- package/dest/lmdb-v2/multi_map.js +103 -0
- package/dest/lmdb-v2/singleton.d.ts.map +1 -1
- package/dest/lmdb-v2/singleton.js +1 -0
- package/dest/lmdb-v2/store.d.ts +2 -1
- package/dest/lmdb-v2/store.d.ts.map +1 -1
- package/dest/lmdb-v2/store.js +5 -1
- package/package.json +5 -5
- package/src/config.ts +3 -1
- package/src/indexeddb/map.ts +15 -47
- package/src/indexeddb/multi_map.ts +53 -0
- package/src/indexeddb/store.ts +9 -3
- package/src/interfaces/index.ts +1 -0
- package/src/interfaces/map.ts +0 -52
- package/src/interfaces/map_test_suite.ts +18 -33
- package/src/interfaces/multi_map.ts +38 -0
- package/src/interfaces/multi_map_test_suite.ts +143 -0
- package/src/interfaces/store.ts +2 -22
- package/src/lmdb/map.ts +2 -88
- package/src/lmdb/multi_map.ts +35 -0
- package/src/lmdb/store.ts +5 -27
- package/src/lmdb-v2/array.ts +1 -0
- package/src/lmdb-v2/map.ts +2 -120
- package/src/lmdb-v2/multi_map.ts +126 -0
- package/src/lmdb-v2/singleton.ts +1 -0
- package/src/lmdb-v2/store.ts +7 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { toArray } from '@aztec/foundation/iterable';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
|
|
5
|
+
import type { Key, Range } from './common.js';
|
|
6
|
+
import type { AztecAsyncMultiMap, AztecMultiMap } from './multi_map.js';
|
|
7
|
+
import type { AztecAsyncKVStore, AztecKVStore } from './store.js';
|
|
8
|
+
import { isSyncStore } from './utils.js';
|
|
9
|
+
|
|
10
|
+
export function describeAztecMultiMap(
|
|
11
|
+
testName: string,
|
|
12
|
+
getStore: () => AztecKVStore | Promise<AztecAsyncKVStore>,
|
|
13
|
+
forceAsync: boolean = false,
|
|
14
|
+
) {
|
|
15
|
+
describe(testName, () => {
|
|
16
|
+
let store: AztecKVStore | AztecAsyncKVStore;
|
|
17
|
+
let multiMap: AztecMultiMap<Key, string> | AztecAsyncMultiMap<Key, string>;
|
|
18
|
+
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
store = await getStore();
|
|
21
|
+
multiMap = store.openMultiMap<string, string>('test');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(async () => {
|
|
25
|
+
await store.delete();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
async function get(key: Key, sut: AztecAsyncMultiMap<any, any> | AztecMultiMap<any, any> = multiMap) {
|
|
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((multiMap as AztecMultiMap<any, any>).entries())
|
|
37
|
+
: await toArray((multiMap as AztecAsyncMultiMap<any, any>).entriesAsync());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function values() {
|
|
41
|
+
return isSyncStore(store) && !forceAsync
|
|
42
|
+
? await toArray((multiMap as AztecMultiMap<any, any>).values())
|
|
43
|
+
: await toArray((multiMap as AztecAsyncMultiMap<any, any>).valuesAsync());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function keys(range?: Range<Key>, sut: AztecAsyncMultiMap<any, any> | AztecMultiMap<any, any> = multiMap) {
|
|
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((multiMap as AztecMultiMap<any, any>).getValues(key))
|
|
55
|
+
: await toArray((multiMap as AztecAsyncMultiMap<any, any>).getValuesAsync(key));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
it('should be able to set and get values', async () => {
|
|
59
|
+
await multiMap.set('foo', 'bar');
|
|
60
|
+
await multiMap.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 multiMap.setIfNotExists('foo', 'bar')).to.equal(true);
|
|
69
|
+
expect(await multiMap.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 multiMap.set('foo', 'bar');
|
|
76
|
+
await multiMap.set('baz', 'qux');
|
|
77
|
+
|
|
78
|
+
await multiMap.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 multiMap.set('foo', 'bar');
|
|
90
|
+
await multiMap.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 multiMap.set('foo', 'bar');
|
|
100
|
+
await multiMap.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 multiMap.set('foo', 'bar');
|
|
107
|
+
await multiMap.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 multiMap.set('foo', 'bar');
|
|
114
|
+
await multiMap.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 multiMap.set('foo', 'bar');
|
|
121
|
+
await multiMap.set('foo', 'baz');
|
|
122
|
+
|
|
123
|
+
await multiMap.deleteValue('foo', 'bar');
|
|
124
|
+
|
|
125
|
+
expect(await getValues('foo')).to.deep.equal(['baz']);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('supports range queries', async () => {
|
|
129
|
+
await multiMap.set('a', 'a');
|
|
130
|
+
await multiMap.set('b', 'b');
|
|
131
|
+
await multiMap.set('c', 'c');
|
|
132
|
+
await multiMap.set('d', 'd');
|
|
133
|
+
|
|
134
|
+
expect(await keys({ start: 'b', end: 'c' })).to.deep.equal(['b']);
|
|
135
|
+
expect(await keys({ start: 'b' })).to.deep.equal(['b', 'c', 'd']);
|
|
136
|
+
expect(await keys({ end: 'c' })).to.deep.equal(['a', 'b']);
|
|
137
|
+
expect(await keys({ start: 'b', end: 'c', reverse: true })).to.deep.equal(['c']);
|
|
138
|
+
expect(await keys({ start: 'b', limit: 1 })).to.deep.equal(['b']);
|
|
139
|
+
expect(await keys({ start: 'b', reverse: true })).to.deep.equal(['d', 'c']);
|
|
140
|
+
expect(await keys({ end: 'b', reverse: true })).to.deep.equal(['b', 'a']);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
package/src/interfaces/store.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import type { AztecArray, AztecAsyncArray } from './array.js';
|
|
2
2
|
import type { Key, StoreSize } from './common.js';
|
|
3
3
|
import type { AztecAsyncCounter, AztecCounter } from './counter.js';
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
AztecAsyncMultiMap,
|
|
7
|
-
AztecMap,
|
|
8
|
-
AztecMapWithSize,
|
|
9
|
-
AztecMultiMap,
|
|
10
|
-
AztecMultiMapWithSize,
|
|
11
|
-
} from './map.js';
|
|
4
|
+
import type { AztecAsyncMap, AztecMap } from './map.js';
|
|
5
|
+
import type { AztecAsyncMultiMap, AztecMultiMap } from './multi_map.js';
|
|
12
6
|
import type { AztecAsyncSet, AztecSet } from './set.js';
|
|
13
7
|
import type { AztecAsyncSingleton, AztecSingleton } from './singleton.js';
|
|
14
8
|
|
|
@@ -36,20 +30,6 @@ export interface AztecKVStore {
|
|
|
36
30
|
*/
|
|
37
31
|
openMultiMap<K extends Key, V>(name: string): AztecMultiMap<K, V>;
|
|
38
32
|
|
|
39
|
-
/**
|
|
40
|
-
* Creates a new multi-map with size.
|
|
41
|
-
* @param name - The name of the multi-map
|
|
42
|
-
* @returns The multi-map
|
|
43
|
-
*/
|
|
44
|
-
openMultiMapWithSize<K extends Key, V>(name: string): AztecMultiMapWithSize<K, V>;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Creates a new map with size.
|
|
48
|
-
* @param name - The name of the map
|
|
49
|
-
* @returns The map
|
|
50
|
-
*/
|
|
51
|
-
openMapWithSize<K extends Key, V>(name: string): AztecMapWithSize<K, V>;
|
|
52
|
-
|
|
53
33
|
/**
|
|
54
34
|
* Creates a new array.
|
|
55
35
|
* @param name - The name of the array
|
package/src/lmdb/map.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Database, RangeOptions } from 'lmdb';
|
|
2
2
|
|
|
3
3
|
import type { Key, Range } from '../interfaces/common.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { AztecAsyncMap, AztecMap } from '../interfaces/map.js';
|
|
5
5
|
|
|
6
6
|
/** The slot where a key-value entry would be stored */
|
|
7
7
|
type MapValueSlot<K extends Key | Buffer> = ['map', string, 'slot', K];
|
|
@@ -9,7 +9,7 @@ type MapValueSlot<K extends Key | Buffer> = ['map', string, 'slot', K];
|
|
|
9
9
|
/**
|
|
10
10
|
* A map backed by LMDB.
|
|
11
11
|
*/
|
|
12
|
-
export class LmdbAztecMap<K extends Key, V> implements
|
|
12
|
+
export class LmdbAztecMap<K extends Key, V> implements AztecMap<K, V>, AztecAsyncMap<K, V> {
|
|
13
13
|
protected db: Database<[K, V], MapValueSlot<K>>;
|
|
14
14
|
protected name: string;
|
|
15
15
|
|
|
@@ -39,26 +39,6 @@ export class LmdbAztecMap<K extends Key, V> implements AztecMultiMap<K, V>, Azte
|
|
|
39
39
|
return Promise.resolve(this.get(key));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
*getValues(key: K): IterableIterator<V> {
|
|
43
|
-
const transaction = this.db.useReadTransaction();
|
|
44
|
-
try {
|
|
45
|
-
const values = this.db.getValues(this.slot(key), {
|
|
46
|
-
transaction,
|
|
47
|
-
});
|
|
48
|
-
for (const value of values) {
|
|
49
|
-
yield value?.[1];
|
|
50
|
-
}
|
|
51
|
-
} finally {
|
|
52
|
-
transaction.done();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async *getValuesAsync(key: K): AsyncIterableIterator<V> {
|
|
57
|
-
for (const value of this.getValues(key)) {
|
|
58
|
-
yield value;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
42
|
has(key: K): boolean {
|
|
63
43
|
return this.db.doesExist(this.slot(key));
|
|
64
44
|
}
|
|
@@ -90,10 +70,6 @@ export class LmdbAztecMap<K extends Key, V> implements AztecMultiMap<K, V>, Azte
|
|
|
90
70
|
await this.db.remove(this.slot(key));
|
|
91
71
|
}
|
|
92
72
|
|
|
93
|
-
async deleteValue(key: K, val: V): Promise<void> {
|
|
94
|
-
await this.db.remove(this.slot(key), [key, val]);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
73
|
*entries(range: Range<K> = {}): IterableIterator<[K, V]> {
|
|
98
74
|
const transaction = this.db.useReadTransaction();
|
|
99
75
|
|
|
@@ -184,65 +160,3 @@ export class LmdbAztecMap<K extends Key, V> implements AztecMultiMap<K, V>, Azte
|
|
|
184
160
|
}
|
|
185
161
|
}
|
|
186
162
|
}
|
|
187
|
-
|
|
188
|
-
export class LmdbAztecMapWithSize<K extends Key, V>
|
|
189
|
-
extends LmdbAztecMap<K, V>
|
|
190
|
-
implements AztecMapWithSize<K, V>, AztecAsyncMultiMap<K, V>
|
|
191
|
-
{
|
|
192
|
-
#sizeCache?: number;
|
|
193
|
-
|
|
194
|
-
constructor(rootDb: Database, mapName: string) {
|
|
195
|
-
super(rootDb, mapName);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
override async set(key: K, val: V): Promise<void> {
|
|
199
|
-
await this.db.childTransaction(() => {
|
|
200
|
-
const exists = this.db.doesExist(this.slot(key));
|
|
201
|
-
this.db.putSync(this.slot(key), [key, val], {
|
|
202
|
-
appendDup: true,
|
|
203
|
-
});
|
|
204
|
-
if (!exists) {
|
|
205
|
-
this.#sizeCache = undefined; // Invalidate cache
|
|
206
|
-
}
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
override async delete(key: K): Promise<void> {
|
|
211
|
-
await this.db.childTransaction(async () => {
|
|
212
|
-
const exists = this.db.doesExist(this.slot(key));
|
|
213
|
-
if (exists) {
|
|
214
|
-
await this.db.remove(this.slot(key));
|
|
215
|
-
this.#sizeCache = undefined; // Invalidate cache
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
override async deleteValue(key: K, val: V): Promise<void> {
|
|
221
|
-
await this.db.childTransaction(async () => {
|
|
222
|
-
const exists = this.db.doesExist(this.slot(key));
|
|
223
|
-
if (exists) {
|
|
224
|
-
await this.db.remove(this.slot(key), [key, val]);
|
|
225
|
-
this.#sizeCache = undefined; // Invalidate cache
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Gets the size of the map by counting entries.
|
|
232
|
-
* @returns The number of entries in the map
|
|
233
|
-
*/
|
|
234
|
-
size(): number {
|
|
235
|
-
if (this.#sizeCache === undefined) {
|
|
236
|
-
this.#sizeCache = this.db.getCount({
|
|
237
|
-
start: this.startSentinel,
|
|
238
|
-
end: this.endSentinel,
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
return this.#sizeCache;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Reset cache on clear/drop operations
|
|
245
|
-
clearCache() {
|
|
246
|
-
this.#sizeCache = undefined;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Key } from '../interfaces/common.js';
|
|
2
|
+
import type { AztecAsyncMultiMap, AztecMultiMap } from '../interfaces/multi_map.js';
|
|
3
|
+
import { LmdbAztecMap } from './map.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A map backed by LMDB.
|
|
7
|
+
*/
|
|
8
|
+
export class LmdbAztecMultiMap<K extends Key, V>
|
|
9
|
+
extends LmdbAztecMap<K, V>
|
|
10
|
+
implements AztecMultiMap<K, V>, AztecAsyncMultiMap<K, V>
|
|
11
|
+
{
|
|
12
|
+
*getValues(key: K): IterableIterator<V> {
|
|
13
|
+
const transaction = this.db.useReadTransaction();
|
|
14
|
+
try {
|
|
15
|
+
const values = this.db.getValues(this.slot(key), {
|
|
16
|
+
transaction,
|
|
17
|
+
});
|
|
18
|
+
for (const value of values) {
|
|
19
|
+
yield value?.[1];
|
|
20
|
+
}
|
|
21
|
+
} finally {
|
|
22
|
+
transaction.done();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async *getValuesAsync(key: K): AsyncIterableIterator<V> {
|
|
27
|
+
for (const value of this.getValues(key)) {
|
|
28
|
+
yield value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async deleteValue(key: K, val: V): Promise<void> {
|
|
33
|
+
await this.db.remove(this.slot(key), [key, val]);
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/lmdb/store.ts
CHANGED
|
@@ -9,20 +9,15 @@ import { join } from 'path';
|
|
|
9
9
|
import type { AztecArray, AztecAsyncArray } from '../interfaces/array.js';
|
|
10
10
|
import type { Key, StoreSize } from '../interfaces/common.js';
|
|
11
11
|
import type { AztecAsyncCounter, AztecCounter } from '../interfaces/counter.js';
|
|
12
|
-
import type {
|
|
13
|
-
|
|
14
|
-
AztecAsyncMultiMap,
|
|
15
|
-
AztecMap,
|
|
16
|
-
AztecMapWithSize,
|
|
17
|
-
AztecMultiMap,
|
|
18
|
-
AztecMultiMapWithSize,
|
|
19
|
-
} from '../interfaces/map.js';
|
|
12
|
+
import type { AztecAsyncMap, AztecMap } from '../interfaces/map.js';
|
|
13
|
+
import type { AztecAsyncMultiMap, AztecMultiMap } from '../interfaces/multi_map.js';
|
|
20
14
|
import type { AztecAsyncSet, AztecSet } from '../interfaces/set.js';
|
|
21
15
|
import type { AztecAsyncSingleton, AztecSingleton } from '../interfaces/singleton.js';
|
|
22
16
|
import type { AztecAsyncKVStore, AztecKVStore } from '../interfaces/store.js';
|
|
23
17
|
import { LmdbAztecArray } from './array.js';
|
|
24
18
|
import { LmdbAztecCounter } from './counter.js';
|
|
25
|
-
import { LmdbAztecMap
|
|
19
|
+
import { LmdbAztecMap } from './map.js';
|
|
20
|
+
import { LmdbAztecMultiMap } from './multi_map.js';
|
|
26
21
|
import { LmdbAztecSet } from './set.js';
|
|
27
22
|
import { LmdbAztecSingleton } from './singleton.js';
|
|
28
23
|
|
|
@@ -119,29 +114,12 @@ export class AztecLmdbStore implements AztecKVStore, AztecAsyncKVStore {
|
|
|
119
114
|
* @returns A new AztecMultiMap
|
|
120
115
|
*/
|
|
121
116
|
openMultiMap<K extends Key, V>(name: string): AztecMultiMap<K, V> & AztecAsyncMultiMap<K, V> {
|
|
122
|
-
return new
|
|
117
|
+
return new LmdbAztecMultiMap(this.#multiMapData, name);
|
|
123
118
|
}
|
|
124
119
|
|
|
125
120
|
openCounter<K extends Key>(name: string): AztecCounter<K> & AztecAsyncCounter<K> {
|
|
126
121
|
return new LmdbAztecCounter(this.#data, name);
|
|
127
122
|
}
|
|
128
|
-
/**
|
|
129
|
-
* Creates a new AztecMultiMapWithSize in the store. A multi-map with size stores multiple values for a single key automatically.
|
|
130
|
-
* @param name - Name of the map
|
|
131
|
-
* @returns A new AztecMultiMapWithSize
|
|
132
|
-
*/
|
|
133
|
-
openMultiMapWithSize<K extends Key, V>(name: string): AztecMultiMapWithSize<K, V> {
|
|
134
|
-
return new LmdbAztecMapWithSize(this.#multiMapData, name);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Creates a new AztecMapWithSize in the store.
|
|
139
|
-
* @param name - Name of the map
|
|
140
|
-
* @returns A new AztecMapWithSize
|
|
141
|
-
*/
|
|
142
|
-
openMapWithSize<K extends Key, V>(name: string): AztecMapWithSize<K, V> {
|
|
143
|
-
return new LmdbAztecMapWithSize(this.#data, name);
|
|
144
|
-
}
|
|
145
123
|
|
|
146
124
|
/**
|
|
147
125
|
* Creates a new AztecArray in the store.
|
package/src/lmdb-v2/array.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Encoder } from 'msgpackr/pack';
|
|
|
3
3
|
import type { AztecAsyncArray } from '../interfaces/array.js';
|
|
4
4
|
import type { AztecAsyncSingleton } from '../interfaces/singleton.js';
|
|
5
5
|
import type { ReadTransaction } from './read_transaction.js';
|
|
6
|
+
// eslint-disable-next-line import/no-cycle
|
|
6
7
|
import { AztecLMDBStoreV2, execInReadTx, execInWriteTx } from './store.js';
|
|
7
8
|
import { deserializeKey, serializeKey } from './utils.js';
|
|
8
9
|
|
package/src/lmdb-v2/map.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Encoder } from 'msgpackr';
|
|
2
2
|
|
|
3
3
|
import type { Key, Range } from '../interfaces/common.js';
|
|
4
|
-
import type { AztecAsyncMap
|
|
4
|
+
import type { AztecAsyncMap } from '../interfaces/map.js';
|
|
5
5
|
import type { ReadTransaction } from './read_transaction.js';
|
|
6
|
+
// eslint-disable-next-line import/no-cycle
|
|
6
7
|
import { type AztecLMDBStoreV2, execInReadTx, execInWriteTx } from './store.js';
|
|
7
8
|
import { deserializeKey, maxKey, minKey, serializeKey } from './utils.js';
|
|
8
9
|
|
|
@@ -112,122 +113,3 @@ export class LMDBMap<K extends Key, V> implements AztecAsyncMap<K, V> {
|
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
export class LMDBMultiMap<K extends Key, V> implements AztecAsyncMultiMap<K, V> {
|
|
117
|
-
private prefix: string;
|
|
118
|
-
private encoder = new Encoder();
|
|
119
|
-
constructor(private store: AztecLMDBStoreV2, name: string) {
|
|
120
|
-
this.prefix = `multimap:${name}`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Sets the value at the given key.
|
|
125
|
-
* @param key - The key to set the value at
|
|
126
|
-
* @param val - The value to set
|
|
127
|
-
*/
|
|
128
|
-
set(key: K, val: V): Promise<void> {
|
|
129
|
-
return execInWriteTx(this.store, tx => tx.setIndex(serializeKey(this.prefix, key), this.encoder.pack(val)));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Sets the value at the given key if it does not already exist.
|
|
134
|
-
* @param key - The key to set the value at
|
|
135
|
-
* @param val - The value to set
|
|
136
|
-
*/
|
|
137
|
-
setIfNotExists(key: K, val: V): Promise<boolean> {
|
|
138
|
-
return execInWriteTx(this.store, async tx => {
|
|
139
|
-
const exists = !!(await this.getAsync(key));
|
|
140
|
-
if (!exists) {
|
|
141
|
-
await tx.setIndex(serializeKey(this.prefix, key), this.encoder.pack(val));
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
return false;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Deletes the value at the given key.
|
|
150
|
-
* @param key - The key to delete the value at
|
|
151
|
-
*/
|
|
152
|
-
delete(key: K): Promise<void> {
|
|
153
|
-
return execInWriteTx(this.store, tx => tx.removeIndex(serializeKey(this.prefix, key)));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
getAsync(key: K): Promise<V | undefined> {
|
|
157
|
-
return execInReadTx(this.store, async tx => {
|
|
158
|
-
const val = await tx.getIndex(serializeKey(this.prefix, key));
|
|
159
|
-
return val.length > 0 ? this.encoder.unpack(val[0]) : undefined;
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
hasAsync(key: K): Promise<boolean> {
|
|
164
|
-
return execInReadTx(this.store, async tx => (await tx.getIndex(serializeKey(this.prefix, key))).length > 0);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Iterates over the map's key-value entries in the key's natural order
|
|
169
|
-
* @param range - The range of keys to iterate over
|
|
170
|
-
*/
|
|
171
|
-
async *entriesAsync(range?: Range<K>): AsyncIterableIterator<[K, V]> {
|
|
172
|
-
const reverse = range?.reverse ?? false;
|
|
173
|
-
const startKey = range?.start ? serializeKey(this.prefix, range.start) : minKey(this.prefix);
|
|
174
|
-
const endKey = range?.end ? serializeKey(this.prefix, range.end) : reverse ? maxKey(this.prefix) : undefined;
|
|
175
|
-
|
|
176
|
-
let tx: ReadTransaction | undefined = this.store.getCurrentWriteTx();
|
|
177
|
-
const shouldClose = !tx;
|
|
178
|
-
tx ??= this.store.getReadTx();
|
|
179
|
-
|
|
180
|
-
try {
|
|
181
|
-
for await (const [key, vals] of tx.iterateIndex(
|
|
182
|
-
reverse ? endKey! : startKey,
|
|
183
|
-
reverse ? startKey : endKey,
|
|
184
|
-
reverse,
|
|
185
|
-
range?.limit,
|
|
186
|
-
)) {
|
|
187
|
-
const deserializedKey = deserializeKey<K>(this.prefix, key);
|
|
188
|
-
if (!deserializedKey) {
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
for (const val of vals) {
|
|
193
|
-
yield [deserializedKey, this.encoder.unpack(val)];
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
} finally {
|
|
197
|
-
if (shouldClose) {
|
|
198
|
-
tx.close();
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Iterates over the map's values in the key's natural order
|
|
205
|
-
* @param range - The range of keys to iterate over
|
|
206
|
-
*/
|
|
207
|
-
async *valuesAsync(range?: Range<K>): AsyncIterableIterator<V> {
|
|
208
|
-
for await (const [_, value] of this.entriesAsync(range)) {
|
|
209
|
-
yield value;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Iterates over the map's keys in the key's natural order
|
|
215
|
-
* @param range - The range of keys to iterate over
|
|
216
|
-
*/
|
|
217
|
-
async *keysAsync(range?: Range<K>): AsyncIterableIterator<K> {
|
|
218
|
-
for await (const [key, _] of this.entriesAsync(range)) {
|
|
219
|
-
yield key;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
deleteValue(key: K, val: V | undefined): Promise<void> {
|
|
224
|
-
return execInWriteTx(this.store, tx => tx.removeIndex(serializeKey(this.prefix, key), this.encoder.pack(val)));
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async *getValuesAsync(key: K): AsyncIterableIterator<V> {
|
|
228
|
-
const values = await execInReadTx(this.store, tx => tx.getIndex(serializeKey(this.prefix, key)));
|
|
229
|
-
for (const value of values) {
|
|
230
|
-
yield this.encoder.unpack(value);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Encoder } from 'msgpackr/pack';
|
|
2
|
+
|
|
3
|
+
import type { Key, Range } from '../interfaces/common.js';
|
|
4
|
+
import type { AztecAsyncMultiMap } from '../interfaces/multi_map.js';
|
|
5
|
+
import type { ReadTransaction } from './read_transaction.js';
|
|
6
|
+
import { type AztecLMDBStoreV2, execInReadTx, execInWriteTx } from './store.js';
|
|
7
|
+
import { deserializeKey, maxKey, minKey, serializeKey } from './utils.js';
|
|
8
|
+
|
|
9
|
+
export class LMDBMultiMap<K extends Key, V> implements AztecAsyncMultiMap<K, V> {
|
|
10
|
+
private prefix: string;
|
|
11
|
+
private encoder = new Encoder();
|
|
12
|
+
constructor(private store: AztecLMDBStoreV2, name: string) {
|
|
13
|
+
this.prefix = `multimap:${name}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Sets the value at the given key.
|
|
18
|
+
* @param key - The key to set the value at
|
|
19
|
+
* @param val - The value to set
|
|
20
|
+
*/
|
|
21
|
+
set(key: K, val: V): Promise<void> {
|
|
22
|
+
return execInWriteTx(this.store, tx => tx.setIndex(serializeKey(this.prefix, key), this.encoder.pack(val)));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Sets the value at the given key if it does not already exist.
|
|
27
|
+
* @param key - The key to set the value at
|
|
28
|
+
* @param val - The value to set
|
|
29
|
+
*/
|
|
30
|
+
setIfNotExists(key: K, val: V): Promise<boolean> {
|
|
31
|
+
return execInWriteTx(this.store, async tx => {
|
|
32
|
+
const exists = !!(await this.getAsync(key));
|
|
33
|
+
if (!exists) {
|
|
34
|
+
await tx.setIndex(serializeKey(this.prefix, key), this.encoder.pack(val));
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Deletes the value at the given key.
|
|
43
|
+
* @param key - The key to delete the value at
|
|
44
|
+
*/
|
|
45
|
+
delete(key: K): Promise<void> {
|
|
46
|
+
return execInWriteTx(this.store, tx => tx.removeIndex(serializeKey(this.prefix, key)));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getAsync(key: K): Promise<V | undefined> {
|
|
50
|
+
return execInReadTx(this.store, async tx => {
|
|
51
|
+
const val = await tx.getIndex(serializeKey(this.prefix, key));
|
|
52
|
+
return val.length > 0 ? this.encoder.unpack(val[0]) : undefined;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
hasAsync(key: K): Promise<boolean> {
|
|
57
|
+
return execInReadTx(this.store, async tx => (await tx.getIndex(serializeKey(this.prefix, key))).length > 0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Iterates over the map's key-value entries in the key's natural order
|
|
62
|
+
* @param range - The range of keys to iterate over
|
|
63
|
+
*/
|
|
64
|
+
async *entriesAsync(range?: Range<K>): AsyncIterableIterator<[K, V]> {
|
|
65
|
+
const reverse = range?.reverse ?? false;
|
|
66
|
+
const startKey = range?.start ? serializeKey(this.prefix, range.start) : minKey(this.prefix);
|
|
67
|
+
const endKey = range?.end ? serializeKey(this.prefix, range.end) : reverse ? maxKey(this.prefix) : undefined;
|
|
68
|
+
|
|
69
|
+
let tx: ReadTransaction | undefined = this.store.getCurrentWriteTx();
|
|
70
|
+
const shouldClose = !tx;
|
|
71
|
+
tx ??= this.store.getReadTx();
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
for await (const [key, vals] of tx.iterateIndex(
|
|
75
|
+
reverse ? endKey! : startKey,
|
|
76
|
+
reverse ? startKey : endKey,
|
|
77
|
+
reverse,
|
|
78
|
+
range?.limit,
|
|
79
|
+
)) {
|
|
80
|
+
const deserializedKey = deserializeKey<K>(this.prefix, key);
|
|
81
|
+
if (!deserializedKey) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const val of vals) {
|
|
86
|
+
yield [deserializedKey, this.encoder.unpack(val)];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
if (shouldClose) {
|
|
91
|
+
tx.close();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Iterates over the map's values in the key's natural order
|
|
98
|
+
* @param range - The range of keys to iterate over
|
|
99
|
+
*/
|
|
100
|
+
async *valuesAsync(range?: Range<K>): AsyncIterableIterator<V> {
|
|
101
|
+
for await (const [_, value] of this.entriesAsync(range)) {
|
|
102
|
+
yield value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Iterates over the map's keys in the key's natural order
|
|
108
|
+
* @param range - The range of keys to iterate over
|
|
109
|
+
*/
|
|
110
|
+
async *keysAsync(range?: Range<K>): AsyncIterableIterator<K> {
|
|
111
|
+
for await (const [key, _] of this.entriesAsync(range)) {
|
|
112
|
+
yield key;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
deleteValue(key: K, val: V | undefined): Promise<void> {
|
|
117
|
+
return execInWriteTx(this.store, tx => tx.removeIndex(serializeKey(this.prefix, key), this.encoder.pack(val)));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async *getValuesAsync(key: K): AsyncIterableIterator<V> {
|
|
121
|
+
const values = await execInReadTx(this.store, tx => tx.getIndex(serializeKey(this.prefix, key)));
|
|
122
|
+
for (const value of values) {
|
|
123
|
+
yield this.encoder.unpack(value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
package/src/lmdb-v2/singleton.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Encoder } from 'msgpackr';
|
|
2
2
|
|
|
3
3
|
import type { AztecAsyncSingleton } from '../interfaces/singleton.js';
|
|
4
|
+
// eslint-disable-next-line import/no-cycle
|
|
4
5
|
import { type AztecLMDBStoreV2, execInReadTx, execInWriteTx } from './store.js';
|
|
5
6
|
import { serializeKey } from './utils.js';
|
|
6
7
|
|