@aztec/kv-store 0.0.0-test.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.
Files changed (166) hide show
  1. package/README.md +10 -0
  2. package/dest/config.d.ts +17 -0
  3. package/dest/config.d.ts.map +1 -0
  4. package/dest/config.js +24 -0
  5. package/dest/indexeddb/array.d.ts +21 -0
  6. package/dest/indexeddb/array.d.ts.map +1 -0
  7. package/dest/indexeddb/array.js +104 -0
  8. package/dest/indexeddb/index.d.ts +7 -0
  9. package/dest/indexeddb/index.d.ts.map +1 -0
  10. package/dest/indexeddb/index.js +19 -0
  11. package/dest/indexeddb/map.d.ts +26 -0
  12. package/dest/indexeddb/map.d.ts.map +1 -0
  13. package/dest/indexeddb/map.js +133 -0
  14. package/dest/indexeddb/set.d.ts +17 -0
  15. package/dest/indexeddb/set.d.ts.map +1 -0
  16. package/dest/indexeddb/set.js +24 -0
  17. package/dest/indexeddb/singleton.d.ts +16 -0
  18. package/dest/indexeddb/singleton.d.ts.map +1 -0
  19. package/dest/indexeddb/singleton.js +37 -0
  20. package/dest/indexeddb/store.d.ts +97 -0
  21. package/dest/indexeddb/store.d.ts.map +1 -0
  22. package/dest/indexeddb/store.js +164 -0
  23. package/dest/interfaces/array.d.ts +80 -0
  24. package/dest/interfaces/array.d.ts.map +1 -0
  25. package/dest/interfaces/array.js +3 -0
  26. package/dest/interfaces/array_test_suite.d.ts +3 -0
  27. package/dest/interfaces/array_test_suite.d.ts.map +1 -0
  28. package/dest/interfaces/array_test_suite.js +104 -0
  29. package/dest/interfaces/common.d.ts +23 -0
  30. package/dest/interfaces/common.d.ts.map +1 -0
  31. package/dest/interfaces/common.js +3 -0
  32. package/dest/interfaces/counter.d.ts +59 -0
  33. package/dest/interfaces/counter.d.ts.map +1 -0
  34. package/dest/interfaces/counter.js +1 -0
  35. package/dest/interfaces/index.d.ts +8 -0
  36. package/dest/interfaces/index.d.ts.map +1 -0
  37. package/dest/interfaces/index.js +6 -0
  38. package/dest/interfaces/map.d.ts +134 -0
  39. package/dest/interfaces/map.d.ts.map +1 -0
  40. package/dest/interfaces/map.js +3 -0
  41. package/dest/interfaces/map_test_suite.d.ts +3 -0
  42. package/dest/interfaces/map_test_suite.d.ts.map +1 -0
  43. package/dest/interfaces/map_test_suite.js +151 -0
  44. package/dest/interfaces/set.d.ts +44 -0
  45. package/dest/interfaces/set.d.ts.map +1 -0
  46. package/dest/interfaces/set.js +1 -0
  47. package/dest/interfaces/set_test_suite.d.ts +3 -0
  48. package/dest/interfaces/set_test_suite.d.ts.map +1 -0
  49. package/dest/interfaces/set_test_suite.js +96 -0
  50. package/dest/interfaces/singleton.d.ts +29 -0
  51. package/dest/interfaces/singleton.d.ts.map +1 -0
  52. package/dest/interfaces/singleton.js +4 -0
  53. package/dest/interfaces/singleton_test_suite.d.ts +3 -0
  54. package/dest/interfaces/singleton_test_suite.d.ts.map +1 -0
  55. package/dest/interfaces/singleton_test_suite.js +30 -0
  56. package/dest/interfaces/store.d.ts +145 -0
  57. package/dest/interfaces/store.d.ts.map +1 -0
  58. package/dest/interfaces/store.js +1 -0
  59. package/dest/interfaces/store_test_suite.d.ts +3 -0
  60. package/dest/interfaces/store_test_suite.d.ts.map +1 -0
  61. package/dest/interfaces/store_test_suite.js +37 -0
  62. package/dest/interfaces/utils.d.ts +16 -0
  63. package/dest/interfaces/utils.d.ts.map +1 -0
  64. package/dest/interfaces/utils.js +16 -0
  65. package/dest/lmdb/array.d.ts +23 -0
  66. package/dest/lmdb/array.d.ts.map +1 -0
  67. package/dest/lmdb/array.js +117 -0
  68. package/dest/lmdb/counter.d.ts +19 -0
  69. package/dest/lmdb/counter.d.ts.map +1 -0
  70. package/dest/lmdb/counter.js +50 -0
  71. package/dest/lmdb/index.d.ts +12 -0
  72. package/dest/lmdb/index.d.ts.map +1 -0
  73. package/dest/lmdb/index.js +25 -0
  74. package/dest/lmdb/map.d.ts +52 -0
  75. package/dest/lmdb/map.d.ts.map +1 -0
  76. package/dest/lmdb/map.js +222 -0
  77. package/dest/lmdb/set.d.ts +18 -0
  78. package/dest/lmdb/set.d.ts.map +1 -0
  79. package/dest/lmdb/set.js +32 -0
  80. package/dest/lmdb/singleton.d.ts +14 -0
  81. package/dest/lmdb/singleton.d.ts.map +1 -0
  82. package/dest/lmdb/singleton.js +26 -0
  83. package/dest/lmdb/store.d.ts +110 -0
  84. package/dest/lmdb/store.d.ts.map +1 -0
  85. package/dest/lmdb/store.js +216 -0
  86. package/dest/lmdb-v2/array.d.ts +18 -0
  87. package/dest/lmdb-v2/array.d.ts.map +1 -0
  88. package/dest/lmdb-v2/array.js +101 -0
  89. package/dest/lmdb-v2/factory.d.ts +12 -0
  90. package/dest/lmdb-v2/factory.d.ts.map +1 -0
  91. package/dest/lmdb-v2/factory.js +60 -0
  92. package/dest/lmdb-v2/index.d.ts +3 -0
  93. package/dest/lmdb-v2/index.d.ts.map +1 -0
  94. package/dest/lmdb-v2/index.js +2 -0
  95. package/dest/lmdb-v2/map.d.ts +86 -0
  96. package/dest/lmdb-v2/map.d.ts.map +1 -0
  97. package/dest/lmdb-v2/map.js +193 -0
  98. package/dest/lmdb-v2/message.d.ts +112 -0
  99. package/dest/lmdb-v2/message.d.ts.map +1 -0
  100. package/dest/lmdb-v2/message.js +18 -0
  101. package/dest/lmdb-v2/read_transaction.d.ts +14 -0
  102. package/dest/lmdb-v2/read_transaction.d.ts.map +1 -0
  103. package/dest/lmdb-v2/read_transaction.js +101 -0
  104. package/dest/lmdb-v2/singleton.d.ts +12 -0
  105. package/dest/lmdb-v2/singleton.d.ts.map +1 -0
  106. package/dest/lmdb-v2/singleton.js +31 -0
  107. package/dest/lmdb-v2/store.d.ts +43 -0
  108. package/dest/lmdb-v2/store.d.ts.map +1 -0
  109. package/dest/lmdb-v2/store.js +181 -0
  110. package/dest/lmdb-v2/utils.d.ts +19 -0
  111. package/dest/lmdb-v2/utils.d.ts.map +1 -0
  112. package/dest/lmdb-v2/utils.js +126 -0
  113. package/dest/lmdb-v2/write_transaction.d.ts +19 -0
  114. package/dest/lmdb-v2/write_transaction.d.ts.map +1 -0
  115. package/dest/lmdb-v2/write_transaction.js +254 -0
  116. package/dest/stores/index.d.ts +2 -0
  117. package/dest/stores/index.d.ts.map +1 -0
  118. package/dest/stores/index.js +1 -0
  119. package/dest/stores/l2_tips_store.d.ts +13 -0
  120. package/dest/stores/l2_tips_store.d.ts.map +1 -0
  121. package/dest/stores/l2_tips_store.js +65 -0
  122. package/dest/utils.d.ts +12 -0
  123. package/dest/utils.d.ts.map +1 -0
  124. package/dest/utils.js +24 -0
  125. package/package.json +99 -0
  126. package/src/config.ts +34 -0
  127. package/src/indexeddb/array.ts +118 -0
  128. package/src/indexeddb/index.ts +29 -0
  129. package/src/indexeddb/map.ts +142 -0
  130. package/src/indexeddb/set.ts +37 -0
  131. package/src/indexeddb/singleton.ts +49 -0
  132. package/src/indexeddb/store.ts +197 -0
  133. package/src/interfaces/array.ts +90 -0
  134. package/src/interfaces/array_test_suite.ts +130 -0
  135. package/src/interfaces/common.ts +20 -0
  136. package/src/interfaces/counter.ts +65 -0
  137. package/src/interfaces/index.ts +7 -0
  138. package/src/interfaces/map.ts +151 -0
  139. package/src/interfaces/map_test_suite.ts +143 -0
  140. package/src/interfaces/set.ts +48 -0
  141. package/src/interfaces/set_test_suite.ts +81 -0
  142. package/src/interfaces/singleton.ts +29 -0
  143. package/src/interfaces/singleton_test_suite.ts +46 -0
  144. package/src/interfaces/store.ts +177 -0
  145. package/src/interfaces/store_test_suite.ts +56 -0
  146. package/src/interfaces/utils.ts +21 -0
  147. package/src/lmdb/array.ts +139 -0
  148. package/src/lmdb/counter.ts +67 -0
  149. package/src/lmdb/index.ts +37 -0
  150. package/src/lmdb/map.ts +248 -0
  151. package/src/lmdb/set.ts +45 -0
  152. package/src/lmdb/singleton.ts +35 -0
  153. package/src/lmdb/store.ts +263 -0
  154. package/src/lmdb-v2/array.ts +115 -0
  155. package/src/lmdb-v2/factory.ts +98 -0
  156. package/src/lmdb-v2/index.ts +2 -0
  157. package/src/lmdb-v2/map.ts +233 -0
  158. package/src/lmdb-v2/message.ts +146 -0
  159. package/src/lmdb-v2/read_transaction.ts +116 -0
  160. package/src/lmdb-v2/singleton.ts +34 -0
  161. package/src/lmdb-v2/store.ts +237 -0
  162. package/src/lmdb-v2/utils.ts +150 -0
  163. package/src/lmdb-v2/write_transaction.ts +314 -0
  164. package/src/stores/index.ts +1 -0
  165. package/src/stores/l2_tips_store.ts +70 -0
  166. package/src/utils.ts +40 -0
@@ -0,0 +1,197 @@
1
+ import type { Logger } from '@aztec/foundation/log';
2
+
3
+ import { type DBSchema, type IDBPDatabase, deleteDB, openDB } from 'idb';
4
+
5
+ import type { AztecAsyncArray } from '../interfaces/array.js';
6
+ import type { Key, StoreSize } from '../interfaces/common.js';
7
+ import type { AztecAsyncCounter } from '../interfaces/counter.js';
8
+ import type { AztecAsyncMap, AztecAsyncMultiMap } from '../interfaces/map.js';
9
+ import type { AztecAsyncSet } from '../interfaces/set.js';
10
+ import type { AztecAsyncSingleton } from '../interfaces/singleton.js';
11
+ import type { AztecAsyncKVStore } from '../interfaces/store.js';
12
+ import { IndexedDBAztecArray } from './array.js';
13
+ import { IndexedDBAztecMap } from './map.js';
14
+ import { IndexedDBAztecSet } from './set.js';
15
+ import { IndexedDBAztecSingleton } from './singleton.js';
16
+
17
+ export type StoredData<V> = { value: V; container: string; key: string; keyCount: number; slot: string };
18
+
19
+ export interface AztecIDBSchema extends DBSchema {
20
+ data: {
21
+ value: StoredData<any>;
22
+ key: string;
23
+ indexes: { container: string; key: string; keyCount: number };
24
+ };
25
+ }
26
+
27
+ /**
28
+ * A key-value store backed by IndexedDB.
29
+ */
30
+
31
+ export class AztecIndexedDBStore implements AztecAsyncKVStore {
32
+ #log: Logger;
33
+ #rootDB: IDBPDatabase<AztecIDBSchema>;
34
+ #name: string;
35
+
36
+ #containers = new Set<
37
+ IndexedDBAztecArray<any> | IndexedDBAztecMap<any, any> | IndexedDBAztecSet<any> | IndexedDBAztecSingleton<any>
38
+ >();
39
+
40
+ constructor(rootDB: IDBPDatabase<AztecIDBSchema>, public readonly isEphemeral: boolean, log: Logger, name: string) {
41
+ this.#rootDB = rootDB;
42
+ this.#log = log;
43
+ this.#name = name;
44
+ }
45
+ /**
46
+ * Creates a new AztecKVStore backed by IndexedDB. The path to the database is optional. If not provided,
47
+ * the database will be stored in a temporary location and be deleted when the process exists.
48
+ *
49
+ *
50
+ * @param path - A path on the disk to store the database. Optional
51
+ * @param ephemeral - true if the store should only exist in memory and not automatically be flushed to disk. Optional
52
+ * @param log - A logger to use. Optional
53
+ * @returns The store
54
+ */
55
+ static async open(log: Logger, name?: string, ephemeral: boolean = false): Promise<AztecIndexedDBStore> {
56
+ name = name && !ephemeral ? name : self.crypto.getRandomValues(new Uint8Array(16)).join('');
57
+ log.debug(`Opening IndexedDB ${ephemeral ? 'temp ' : ''}database with name ${name}`);
58
+ const rootDB = await openDB<AztecIDBSchema>(name, 1, {
59
+ upgrade(db) {
60
+ const objectStore = db.createObjectStore('data', { keyPath: 'slot' });
61
+
62
+ objectStore.createIndex('key', ['container', 'key'], { unique: false });
63
+ objectStore.createIndex('keyCount', ['container', 'key', 'keyCount'], { unique: false });
64
+ },
65
+ });
66
+
67
+ const kvStore = new AztecIndexedDBStore(rootDB, ephemeral, log, name);
68
+ return kvStore;
69
+ }
70
+
71
+ /**
72
+ * Forks the current DB into a new DB by backing it up to a temporary location and opening a new indexedb.
73
+ * @returns A new AztecIndexedDBStore.
74
+ */
75
+ async fork(): Promise<AztecAsyncKVStore> {
76
+ const forkedStore = await AztecIndexedDBStore.open(this.#log, undefined, true);
77
+ this.#log.verbose(`Forking store to ${forkedStore.#name}`);
78
+
79
+ // Copy old data to new store
80
+ const oldData = this.#rootDB.transaction('data').store;
81
+ const dataToWrite = [];
82
+ for await (const cursor of oldData.iterate()) {
83
+ dataToWrite.push(cursor.value);
84
+ }
85
+ const tx = forkedStore.#rootDB.transaction('data', 'readwrite').store;
86
+ for (const data of dataToWrite) {
87
+ await tx.add(data);
88
+ }
89
+
90
+ this.#log.debug(`Forked store at ${forkedStore.#name} opened successfully`);
91
+ return forkedStore;
92
+ }
93
+
94
+ /**
95
+ * Creates a new AztecMap in the store.
96
+ * @param name - Name of the map
97
+ * @returns A new AztecMap
98
+ */
99
+ openMap<K extends Key, V>(name: string): AztecAsyncMap<K, V> {
100
+ const map = new IndexedDBAztecMap<K, V>(this.#rootDB, name);
101
+ this.#containers.add(map);
102
+ return map;
103
+ }
104
+
105
+ /**
106
+ * Creates a new AztecSet in the store.
107
+ * @param name - Name of the set
108
+ * @returns A new AztecSet
109
+ */
110
+ openSet<K extends Key>(name: string): AztecAsyncSet<K> {
111
+ const set = new IndexedDBAztecSet<K>(this.#rootDB, name);
112
+ this.#containers.add(set);
113
+ return set;
114
+ }
115
+
116
+ /**
117
+ * Creates a new AztecMultiMap in the store. A multi-map stores multiple values for a single key automatically.
118
+ * @param name - Name of the map
119
+ * @returns A new AztecMultiMap
120
+ */
121
+ openMultiMap<K extends Key, V>(name: string): AztecAsyncMultiMap<K, V> {
122
+ const multimap = new IndexedDBAztecMap<K, V>(this.#rootDB, name);
123
+ this.#containers.add(multimap);
124
+ return multimap;
125
+ }
126
+
127
+ openCounter<K extends Key>(_name: string): AztecAsyncCounter<K> {
128
+ throw new Error('Method not implemented.');
129
+ }
130
+
131
+ /**
132
+ * Creates a new AztecArray in the store.
133
+ * @param name - Name of the array
134
+ * @returns A new AztecArray
135
+ */
136
+ openArray<T>(name: string): AztecAsyncArray<T> {
137
+ const array = new IndexedDBAztecArray<T>(this.#rootDB, name);
138
+ this.#containers.add(array);
139
+ return array;
140
+ }
141
+
142
+ /**
143
+ * Creates a new AztecSingleton in the store.
144
+ * @param name - Name of the singleton
145
+ * @returns A new AztecSingleton
146
+ */
147
+ openSingleton<T>(name: string): AztecAsyncSingleton<T> {
148
+ const singleton = new IndexedDBAztecSingleton<T>(this.#rootDB, name);
149
+ this.#containers.add(singleton);
150
+ return singleton;
151
+ }
152
+
153
+ /**
154
+ * Runs a callback in a transaction.
155
+ * @param callback - Function to execute in a transaction
156
+ * @returns A promise that resolves to the return value of the callback
157
+ */
158
+ async transactionAsync<T>(callback: () => Promise<T>): Promise<T> {
159
+ const tx = this.#rootDB.transaction('data', 'readwrite');
160
+ for (const container of this.#containers) {
161
+ container.db = tx.store;
162
+ }
163
+ // Avoid awaiting this promise so it doesn't get scheduled in the next microtask
164
+ // By then, the tx would be closed
165
+ const runningPromise = callback();
166
+ // Wait for the transaction to finish
167
+ await tx.done;
168
+ for (const container of this.#containers) {
169
+ container.db = undefined;
170
+ }
171
+ // Return the result of the callback.
172
+ // Tx is guaranteed to already be closed, so the await doesn't hurt anything here
173
+ return await runningPromise;
174
+ }
175
+
176
+ /**
177
+ * Clears all entries in the store & sub DBs.
178
+ */
179
+ async clear() {
180
+ await this.#rootDB.transaction('data', 'readwrite').store.clear();
181
+ }
182
+
183
+ /** Deletes this store and removes the database */
184
+ delete() {
185
+ this.#containers.clear();
186
+ this.#rootDB.close();
187
+ return deleteDB(this.#name);
188
+ }
189
+
190
+ estimateSize(): Promise<StoreSize> {
191
+ return Promise.resolve({ mappingSize: 0, actualSize: 0, numItems: 0 });
192
+ }
193
+
194
+ close(): Promise<void> {
195
+ return Promise.resolve();
196
+ }
197
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * An array backed by a persistent store. Can not have any holes in it.
3
+ */
4
+ interface BaseAztecArray<T> {
5
+ /**
6
+ * Pushes values to the end of the array
7
+ * @param vals - The values to push to the end of the array
8
+ * @returns The new length of the array
9
+ */
10
+ push(...vals: T[]): Promise<number>;
11
+
12
+ /**
13
+ * Pops a value from the end of the array.
14
+ * @returns The value that was popped, or undefined if the array was empty
15
+ */
16
+ pop(): Promise<T | undefined>;
17
+
18
+ /**
19
+ * Updates the value at the given index. Index can be in the range [-length, length - 1).
20
+ * @param index - The index to set the value at
21
+ * @param val - The value to set
22
+ * @returns Whether the value was set
23
+ */
24
+ setAt(index: number, val: T): Promise<boolean>;
25
+ }
26
+
27
+ /**
28
+ * An array backed by a persistent store. Can not have any holes in it.
29
+ */
30
+ export interface AztecAsyncArray<T> extends BaseAztecArray<T> {
31
+ /**
32
+ * The size of the array
33
+ */
34
+ lengthAsync(): Promise<number>;
35
+
36
+ /**
37
+ * Gets the value at the given index. Index can be in the range [-length, length - 1).
38
+ * If the index is negative, it will be treated as an offset from the end of the array.
39
+ *
40
+ * @param index - The index to get the value from
41
+ * @returns The value at the given index or undefined if the index is out of bounds
42
+ */
43
+ atAsync(index: number): Promise<T | undefined>;
44
+
45
+ /**
46
+ * Iterates over the array with indexes.
47
+ */
48
+ entriesAsync(): AsyncIterableIterator<[number, T]>;
49
+
50
+ /**
51
+ * Iterates over the array.
52
+ */
53
+ valuesAsync(): AsyncIterableIterator<T>;
54
+
55
+ /**
56
+ * Iterates over the array.
57
+ */
58
+ [Symbol.asyncIterator](): AsyncIterableIterator<T>;
59
+ }
60
+
61
+ export interface AztecArray<T> extends BaseAztecArray<T> {
62
+ /**
63
+ * The size of the array
64
+ */
65
+ length: number;
66
+
67
+ /**
68
+ * Gets the value at the given index. Index can be in the range [-length, length - 1).
69
+ * If the index is negative, it will be treated as an offset from the end of the array.
70
+ *
71
+ * @param index - The index to get the value from
72
+ * @returns The value at the given index or undefined if the index is out of bounds
73
+ */
74
+ at(index: number): T | undefined;
75
+
76
+ /**
77
+ * Iterates over the array with indexes.
78
+ */
79
+ entries(): IterableIterator<[number, T]>;
80
+
81
+ /**
82
+ * Iterates over the array.
83
+ */
84
+ values(): IterableIterator<T>;
85
+
86
+ /**
87
+ * Iterates over the array.
88
+ */
89
+ [Symbol.iterator](): IterableIterator<T>;
90
+ }
@@ -0,0 +1,130 @@
1
+ import { toArray } from '@aztec/foundation/iterable';
2
+
3
+ import { expect } from 'chai';
4
+
5
+ import type { AztecArray, AztecAsyncArray } from './array.js';
6
+ import type { AztecAsyncKVStore, 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
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The key type for use with the kv-store
3
+ */
4
+ export type Key = string | number | Array<string | number>;
5
+
6
+ /**
7
+ * A range of keys to iterate over.
8
+ */
9
+ export type Range<K extends Key = Key> = {
10
+ /** The key of the first item to include */
11
+ start?: K;
12
+ /** The key of the last item to include */
13
+ end?: K;
14
+ /** Whether to iterate in reverse */
15
+ reverse?: boolean;
16
+ /** The maximum number of items to iterate over */
17
+ limit?: number;
18
+ };
19
+
20
+ export type StoreSize = { mappingSize: number; actualSize: number; numItems: number };
@@ -0,0 +1,65 @@
1
+ import type { Key, Range } from './common.js';
2
+
3
+ /**
4
+ * A map that counts how many times it sees a key. Once 0 is reached, that key is removed from the map.
5
+ * Iterating over the map will only return keys that have a count over 0.
6
+ *
7
+ * Keys are stored in sorted order
8
+ */
9
+ interface AztecBaseCounter<K extends Key = Key> {
10
+ /**
11
+ * Resets the count of the given key to the given value.
12
+ * @param key - The key to reset
13
+ * @param value - The value to reset the key to
14
+ */
15
+ set(key: K, value: number): Promise<void>;
16
+
17
+ /**
18
+ * Updates the count of the given key by the given delta. This can be used to increment or decrement the count.
19
+ * Once a key's count reaches 0, it is removed from the map.
20
+ *
21
+ * @param key - The key to update
22
+ * @param delta - The amount to modify the key by
23
+ */
24
+ update(key: K, delta: number): Promise<void>;
25
+ }
26
+
27
+ export interface AztecCounter<K extends Key = Key> extends AztecBaseCounter<K> {
28
+ /**
29
+ * Gets the current count.
30
+ * @param key - The key to get the count of
31
+ */
32
+ get(key: K): number;
33
+
34
+ /**
35
+ * Returns keys in the map in sorted order. Only returns keys that have been seen at least once.
36
+ * @param range - The range of keys to iterate over
37
+ */
38
+ keys(range: Range<K>): IterableIterator<K>;
39
+
40
+ /**
41
+ * Returns keys and their counts in the map sorted by the key. Only returns keys that have been seen at least once.
42
+ * @param range - The range of keys to iterate over
43
+ */
44
+ entries(range: Range<K>): IterableIterator<[K, number]>;
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
+ }
@@ -0,0 +1,7 @@
1
+ export * from './array.js';
2
+ export * from './map.js';
3
+ export * from './counter.js';
4
+ export * from './singleton.js';
5
+ export * from './store.js';
6
+ export * from './set.js';
7
+ export type { Range, StoreSize } from './common.js';
@@ -0,0 +1,151 @@
1
+ import type { Key, Range } from './common.js';
2
+
3
+ /**
4
+ * A map backed by a persistent store.
5
+ */
6
+ interface AztecBaseMap<K extends Key, V> {
7
+ /**
8
+ * Sets the value at the given key.
9
+ * @param key - The key to set the value at
10
+ * @param val - The value to set
11
+ */
12
+ set(key: K, val: V): Promise<void>;
13
+
14
+ /**
15
+ * Sets the value at the given key if it does not already exist.
16
+ * @param key - The key to set the value at
17
+ * @param val - The value to set
18
+ */
19
+ setIfNotExists(key: K, val: V): Promise<boolean>;
20
+
21
+ /**
22
+ * Deletes the value at the given key.
23
+ * @param key - The key to delete the value at
24
+ */
25
+ delete(key: K): Promise<void>;
26
+ }
27
+ export interface AztecMap<K extends Key, V> extends AztecBaseMap<K, V> {
28
+ /**
29
+ * Gets the value at the given key.
30
+ * @param key - The key to get the value from
31
+ */
32
+ get(key: K): V | undefined;
33
+
34
+ /**
35
+ * Checks if a key exists in the map.
36
+ * @param key - The key to check
37
+ * @returns True if the key exists, false otherwise
38
+ */
39
+ has(key: K): boolean;
40
+
41
+ /**
42
+ * Iterates over the map's key-value entries in the key's natural order
43
+ * @param range - The range of keys to iterate over
44
+ */
45
+ entries(range?: Range<K>): IterableIterator<[K, V]>;
46
+
47
+ /**
48
+ * Iterates over the map's values in the key's natural order
49
+ * @param range - The range of keys to iterate over
50
+ */
51
+ values(range?: Range<K>): IterableIterator<V>;
52
+
53
+ /**
54
+ * Iterates over the map's keys in the key's natural order
55
+ * @param range - The range of keys to iterate over
56
+ */
57
+ keys(range?: Range<K>): IterableIterator<K>;
58
+
59
+ /**
60
+ * Clears the map.
61
+ */
62
+ clear(): Promise<void>;
63
+ }
64
+
65
+ export interface AztecMapWithSize<K extends Key, V> extends AztecMap<K, V> {
66
+ /**
67
+ * Gets the size of the map.
68
+ * @returns The size of the map
69
+ */
70
+ size(): number;
71
+ }
72
+
73
+ /**
74
+ * A map backed by a persistent store that can have multiple values for a single key.
75
+ */
76
+ export interface AztecMultiMap<K extends Key, V> extends AztecMap<K, V> {
77
+ /**
78
+ * Gets all the values at the given key.
79
+ * @param key - The key to get the values from
80
+ */
81
+ getValues(key: K): IterableIterator<V>;
82
+
83
+ /**
84
+ * Deletes a specific value at the given key.
85
+ * @param key - The key to delete the value at
86
+ * @param val - The value to delete
87
+ */
88
+ deleteValue(key: K, val: V): Promise<void>;
89
+ }
90
+
91
+ export interface AztecMultiMapWithSize<K extends Key, V> extends AztecMultiMap<K, V> {
92
+ /**
93
+ * Gets the size of the map.
94
+ * @returns The size of the map
95
+ */
96
+ size(): number;
97
+ }
98
+
99
+ /**
100
+ * A map backed by a persistent store.
101
+ */
102
+ export interface AztecAsyncMap<K extends Key, V> extends AztecBaseMap<K, V> {
103
+ /**
104
+ * Gets the value at the given key.
105
+ * @param key - The key to get the value from
106
+ */
107
+ getAsync(key: K): Promise<V | undefined>;
108
+
109
+ /**
110
+ * Checks if a key exists in the map.
111
+ * @param key - The key to check
112
+ * @returns True if the key exists, false otherwise
113
+ */
114
+ hasAsync(key: K): Promise<boolean>;
115
+
116
+ /**
117
+ * Iterates over the map's key-value entries in the key's natural order
118
+ * @param range - The range of keys to iterate over
119
+ */
120
+ entriesAsync(range?: Range<K>): AsyncIterableIterator<[K, V]>;
121
+
122
+ /**
123
+ * Iterates over the map's values in the key's natural order
124
+ * @param range - The range of keys to iterate over
125
+ */
126
+ valuesAsync(range?: Range<K>): AsyncIterableIterator<V>;
127
+
128
+ /**
129
+ * Iterates over the map's keys in the key's natural order
130
+ * @param range - The range of keys to iterate over
131
+ */
132
+ keysAsync(range?: Range<K>): AsyncIterableIterator<K>;
133
+ }
134
+
135
+ /**
136
+ * A map backed by a persistent store that can have multiple values for a single key.
137
+ */
138
+ export interface AztecAsyncMultiMap<K extends Key, V> extends AztecAsyncMap<K, V> {
139
+ /**
140
+ * Gets all the values at the given key.
141
+ * @param key - The key to get the values from
142
+ */
143
+ getValuesAsync(key: K): AsyncIterableIterator<V>;
144
+
145
+ /**
146
+ * Deletes a specific value at the given key.
147
+ * @param key - The key to delete the value at
148
+ * @param val - The value to delete
149
+ */
150
+ deleteValue(key: K, val: V): Promise<void>;
151
+ }