@quereus/store 4.13.1 → 4.15.2

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 (51) hide show
  1. package/README.md +761 -702
  2. package/dist/src/common/cost-profile.d.ts +13 -0
  3. package/dist/src/common/cost-profile.d.ts.map +1 -1
  4. package/dist/src/common/cost-profile.js.map +1 -1
  5. package/dist/src/common/events.d.ts +18 -28
  6. package/dist/src/common/events.d.ts.map +1 -1
  7. package/dist/src/common/events.js.map +1 -1
  8. package/dist/src/common/index.d.ts +1 -0
  9. package/dist/src/common/index.d.ts.map +1 -1
  10. package/dist/src/common/index.js +5 -0
  11. package/dist/src/common/index.js.map +1 -1
  12. package/dist/src/common/memory-store.d.ts +9 -0
  13. package/dist/src/common/memory-store.d.ts.map +1 -1
  14. package/dist/src/common/memory-store.js +11 -0
  15. package/dist/src/common/memory-store.js.map +1 -1
  16. package/dist/src/common/store-module-access-plan.js +15 -7
  17. package/dist/src/common/store-module-access-plan.js.map +1 -1
  18. package/dist/src/common/store-module-alter-column.d.ts.map +1 -1
  19. package/dist/src/common/store-module-alter-column.js +77 -62
  20. package/dist/src/common/store-module-alter-column.js.map +1 -1
  21. package/dist/src/common/store-module-alter.d.ts.map +1 -1
  22. package/dist/src/common/store-module-alter.js +2 -3
  23. package/dist/src/common/store-module-alter.js.map +1 -1
  24. package/dist/src/common/store-module-schema-sync.d.ts.map +1 -1
  25. package/dist/src/common/store-module-schema-sync.js +6 -0
  26. package/dist/src/common/store-module-schema-sync.js.map +1 -1
  27. package/dist/src/common/store-module.d.ts +17 -0
  28. package/dist/src/common/store-module.d.ts.map +1 -1
  29. package/dist/src/common/store-module.js +26 -2
  30. package/dist/src/common/store-module.js.map +1 -1
  31. package/dist/src/common/store-table.d.ts +17 -7
  32. package/dist/src/common/store-table.d.ts.map +1 -1
  33. package/dist/src/common/store-table.js +25 -12
  34. package/dist/src/common/store-table.js.map +1 -1
  35. package/dist/src/testing/index.d.ts +12 -0
  36. package/dist/src/testing/index.d.ts.map +1 -1
  37. package/dist/src/testing/index.js +12 -0
  38. package/dist/src/testing/index.js.map +1 -1
  39. package/dist/src/testing/kv-counting-store.d.ts +96 -0
  40. package/dist/src/testing/kv-counting-store.d.ts.map +1 -0
  41. package/dist/src/testing/kv-counting-store.js +226 -0
  42. package/dist/src/testing/kv-counting-store.js.map +1 -0
  43. package/dist/src/testing/kv-delegating-store.d.ts +28 -0
  44. package/dist/src/testing/kv-delegating-store.d.ts.map +1 -0
  45. package/dist/src/testing/kv-delegating-store.js +47 -0
  46. package/dist/src/testing/kv-delegating-store.js.map +1 -0
  47. package/dist/src/testing/memory-provider.d.ts +51 -0
  48. package/dist/src/testing/memory-provider.d.ts.map +1 -0
  49. package/dist/src/testing/memory-provider.js +124 -0
  50. package/dist/src/testing/memory-provider.js.map +1 -0
  51. package/package.json +5 -5
@@ -19,10 +19,22 @@
19
19
  * of two of those batteries, exported standalone so a spec can drive them directly
20
20
  * (including against a double built to fail them — a guard nobody has watched fail is not
21
21
  * a guard).
22
+ *
23
+ * {@link CountingKVStore} / {@link createCountingProvider} are not a conformance battery —
24
+ * they are the shared counting test double several specs in this package (and its
25
+ * benchmark suite) use to assert on storage traffic: reads (`iterate`/`get`/`getMany`) and
26
+ * writes (point `put`/`delete`, and batch commits with the operations they carried).
27
+ *
28
+ * {@link createInMemoryProvider} is the shared all-`InMemoryKVStore` {@link KVStoreProvider}
29
+ * most specs in this package (and its benchmark suite) need as a plain backend, with no
30
+ * counting attached.
22
31
  */
23
32
  export { runKVStoreConformance, assertBoundedIterate, assertBatchPointRead, type KVBackend, type ReadMeter, type PointReadMeter, } from './kv-conformance.js';
24
33
  export { runKVProviderConformance, type KVProviderBackend } from './kv-provider-conformance.js';
25
34
  export { runStoreNameDistinctness, assertStoreNamesDistinct, type KVNamingBackend } from './kv-naming-conformance.js';
26
35
  export { runStoreReclaimConformance, type KVReclaimBackend } from './kv-reclaim-conformance.js';
27
36
  export type { KVProviderLifecycle } from './kv-lifecycle.js';
37
+ export { DelegatingKVStore } from './kv-delegating-store.js';
38
+ export { CountingKVStore, createCountingProvider, type CountingProviderScope, } from './kv-counting-store.js';
39
+ export { createInMemoryProvider, type InMemoryProviderOptions, } from './memory-provider.js';
28
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,cAAc,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,0BAA0B,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAChG,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,cAAc,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,0BAA0B,EAAE,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAChG,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACN,eAAe,EACf,sBAAsB,EACtB,KAAK,qBAAqB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,sBAAsB,EACtB,KAAK,uBAAuB,GAC5B,MAAM,sBAAsB,CAAC"}
@@ -19,9 +19,21 @@
19
19
  * of two of those batteries, exported standalone so a spec can drive them directly
20
20
  * (including against a double built to fail them — a guard nobody has watched fail is not
21
21
  * a guard).
22
+ *
23
+ * {@link CountingKVStore} / {@link createCountingProvider} are not a conformance battery —
24
+ * they are the shared counting test double several specs in this package (and its
25
+ * benchmark suite) use to assert on storage traffic: reads (`iterate`/`get`/`getMany`) and
26
+ * writes (point `put`/`delete`, and batch commits with the operations they carried).
27
+ *
28
+ * {@link createInMemoryProvider} is the shared all-`InMemoryKVStore` {@link KVStoreProvider}
29
+ * most specs in this package (and its benchmark suite) need as a plain backend, with no
30
+ * counting attached.
22
31
  */
23
32
  export { runKVStoreConformance, assertBoundedIterate, assertBatchPointRead, } from './kv-conformance.js';
24
33
  export { runKVProviderConformance } from './kv-provider-conformance.js';
25
34
  export { runStoreNameDistinctness, assertStoreNamesDistinct } from './kv-naming-conformance.js';
26
35
  export { runStoreReclaimConformance } from './kv-reclaim-conformance.js';
36
+ export { DelegatingKVStore } from './kv-delegating-store.js';
37
+ export { CountingKVStore, createCountingProvider, } from './kv-counting-store.js';
38
+ export { createInMemoryProvider, } from './memory-provider.js';
27
39
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GAIpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAA0B,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAwB,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,0BAA0B,EAAyB,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EACN,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,GAIpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAA0B,MAAM,8BAA8B,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAwB,MAAM,4BAA4B,CAAC;AACtH,OAAO,EAAE,0BAA0B,EAAyB,MAAM,6BAA6B,CAAC;AAEhG,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACN,eAAe,EACf,sBAAsB,GAEtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,sBAAsB,GAEtB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Shared counting test doubles for KVStore-backed specs — test-support, ships in
3
+ * `@quereus/store/testing`.
4
+ *
5
+ * Several specs in this package (and this package's benchmark suite) each need a `KVStore`
6
+ * that counts what passes through it: on the read side entries pulled from `iterate()`,
7
+ * `get()` calls, `getMany()` round trips and the keys they carried; on the write side
8
+ * point writes, `write()` round trips and the operations those carried. This file is the
9
+ * one shared implementation — see {@link CountingKVStore}'s doc comment for the two
10
+ * subtleties in how it has to be built.
11
+ */
12
+ import type { IterateOptions, KVEntry, KVStoreProvider, WriteBatch, WriteOptions } from '../common/kv-store.js';
13
+ import { DelegatingKVStore } from './kv-delegating-store.js';
14
+ /**
15
+ * Counts what passes through a wrapped {@link KVStore}. On the read side: entries pulled
16
+ * from `iterate()`, `get()` calls, `getMany()` round trips, and the keys those round trips
17
+ * carried. On the write side: point writes issued outside any batch, `write()` round trips,
18
+ * and the operations those carried.
19
+ *
20
+ * `getMany` routes through `defaultGetMany(this, keys)` rather than forwarding straight to
21
+ * `this.inner.getMany(keys)`. That is deliberate, not an oversight. `defaultGetMany` issues
22
+ * one `get(key)` per key against whatever object it is handed; passing `this` (the wrapper)
23
+ * means each of those `get` calls lands on THIS class's own overridden, counted `get()`
24
+ * (which in turn calls `this.inner.get`) — so a single `getMany` of N keys also advances
25
+ * `getCount` by N, matching how the specs built against this class assert. Forwarding to
26
+ * `this.inner.getMany(keys)` would run `defaultGetMany` with `this = inner`, bypassing the
27
+ * wrapper's `get()` entirely and leaving `getCount` unchanged after a batched read — a subtle
28
+ * break because most of the affected assertions are upper bounds (`.at.most(...)`), not exact
29
+ * equalities, so the bug would pass silently in most specs and only fail the one exact-equal
30
+ * assertion that happens to pin it.
31
+ *
32
+ * The trade-off this creates: `getManyCalls` / `getManyKeyCount` measure batching AT THE CALL
33
+ * BOUNDARY into this wrapper (did the caller invoke `getMany` once with N keys, vs. N calls to
34
+ * `get`) — not the wrapped backend's own internal round-trip count. That is the right thing to
35
+ * measure for the specs this class serves today, which are proving the ENGINE batches its
36
+ * reads, not that the wrapped backend has a native multi-get. A future benchmark reaching for
37
+ * this class to measure a REAL backend's own native batching needs to know that distinction.
38
+ *
39
+ * The write side has the SAME call-boundary caveat, and one structural requirement:
40
+ * `batch()` is overridden to return a {@link CountingWriteBatch}, because the base class's
41
+ * `batch()` hands out the inner store's batch directly and nothing queued on it would ever
42
+ * reach this wrapper. The write counters are deliberately split direct-vs-batched — a commit
43
+ * path that queues N operations and issues ONE `write()` is a different physical cost from
44
+ * one that issues N point writes, and a single combined "writes" number could not tell them
45
+ * apart. The four read counters and the four write counters are independent; a workload
46
+ * touches both.
47
+ */
48
+ export declare class CountingKVStore extends DelegatingKVStore {
49
+ /** Entries pulled from the inner store's `iterate()`. */
50
+ iterateEntryCount: number;
51
+ /** `get()` calls. */
52
+ getCount: number;
53
+ /** `getMany()` calls — round trips, as observed at this counting boundary. */
54
+ getManyCalls: number;
55
+ /** Keys carried by those `getMany()` calls. */
56
+ getManyKeyCount: number;
57
+ /** Puts issued one at a time, outside any batch. */
58
+ directPutCount: number;
59
+ /** Deletes issued one at a time, outside any batch. */
60
+ directDeleteCount: number;
61
+ /** `WriteBatch.write()` calls — the write-side round-trip count. */
62
+ batchWriteCalls: number;
63
+ /** Put/delete operations those `write()` calls carried. */
64
+ batchOpCount: number;
65
+ /** Zero every counter, read and write. */
66
+ reset(): void;
67
+ get(key: Uint8Array): Promise<Uint8Array | undefined>;
68
+ getMany(keys: readonly Uint8Array[]): Promise<(Uint8Array | undefined)[]>;
69
+ iterate(options?: IterateOptions): AsyncIterable<KVEntry>;
70
+ put(key: Uint8Array, value: Uint8Array, options?: WriteOptions): Promise<void>;
71
+ delete(key: Uint8Array, options?: WriteOptions): Promise<void>;
72
+ batch(): WriteBatch;
73
+ }
74
+ /** Which stores {@link createCountingProvider} wraps in a {@link CountingKVStore}. */
75
+ export type CountingProviderScope = 'data' | 'all';
76
+ /**
77
+ * A {@link KVStoreProvider} whose stores are {@link CountingKVStore}s, so a spec can assert
78
+ * on the read traffic (`iterate`/`get`/`getMany`) and the write traffic (point writes and
79
+ * batch commits) StoreModule generates, without reaching into a real backend.
80
+ *
81
+ * Store names come from the shared builders (`buildDataStoreName` / `buildIndexStoreName`,
82
+ * the reserved `__stats__` / `__catalog__` constants) — the same rule every real provider
83
+ * is held to by `runStoreNameDistinctness`. Hand-composing them here would lose the
84
+ * builders' lowercasing, so a mixed-case table name would land on a store no real backend
85
+ * would have used.
86
+ *
87
+ * @param countedStores - Map the counted stores are recorded into, keyed by BUILT store
88
+ * name: `schema.table` (every table's data store) and, when `scope` is `'all'`, also
89
+ * `schema.table_idx_index` (secondary indexes), `__stats__`, and `__catalog__`. The caller
90
+ * reads counters back out of this map after driving a query.
91
+ * @param scope - `'data'` (default): only each table's data store is counted; index,
92
+ * stats, and catalog stores stay plain, uncounted `InMemoryKVStore`s the caller never
93
+ * sees. `'all'`: every store the provider hands out is counted into `countedStores`.
94
+ */
95
+ export declare function createCountingProvider(countedStores: Map<string, CountingKVStore>, scope?: CountingProviderScope): KVStoreProvider;
96
+ //# sourceMappingURL=kv-counting-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-counting-store.d.ts","sourceRoot":"","sources":["../../../src/testing/kv-counting-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAW,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAIzH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AA+C7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,eAAgB,SAAQ,iBAAiB;IACrD,yDAAyD;IACzD,iBAAiB,SAAK;IACtB,qBAAqB;IACrB,QAAQ,SAAK;IACb,8EAA8E;IAC9E,YAAY,SAAK;IACjB,+CAA+C;IAC/C,eAAe,SAAK;IACpB,oDAAoD;IACpD,cAAc,SAAK;IACnB,uDAAuD;IACvD,iBAAiB,SAAK;IACtB,oEAAoE;IACpE,eAAe,SAAK;IACpB,2DAA2D;IAC3D,YAAY,SAAK;IAEjB,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAWE,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAKrD,OAAO,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,CAAC,UAAU,GAAG,SAAS,CAAC,EAAE,CAAC;IAOxE,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC;IAOhE,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9E,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAW9D,KAAK,IAAI,UAAU;CAM5B;AAED,sFAAsF;AACtF,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,KAAK,CAAC;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AAMH,wBAAgB,sBAAsB,CACrC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAC3C,KAAK,GAAE,qBAA8B,GACnC,eAAe,CAqCjB"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Shared counting test doubles for KVStore-backed specs — test-support, ships in
3
+ * `@quereus/store/testing`.
4
+ *
5
+ * Several specs in this package (and this package's benchmark suite) each need a `KVStore`
6
+ * that counts what passes through it: on the read side entries pulled from `iterate()`,
7
+ * `get()` calls, `getMany()` round trips and the keys they carried; on the write side
8
+ * point writes, `write()` round trips and the operations those carried. This file is the
9
+ * one shared implementation — see {@link CountingKVStore}'s doc comment for the two
10
+ * subtleties in how it has to be built.
11
+ */
12
+ import { defaultGetMany } from '../common/kv-store.js';
13
+ import { buildDataStoreName, buildIndexStoreName, CATALOG_STORE_NAME, STATS_STORE_NAME } from '../common/key-builder.js';
14
+ import { InMemoryKVStore } from '../common/memory-store.js';
15
+ import { DelegatingKVStore } from './kv-delegating-store.js';
16
+ /**
17
+ * A {@link WriteBatch} that counts what its owning {@link CountingKVStore} commits.
18
+ *
19
+ * Exists because {@link DelegatingKVStore.batch} hands back the INNER store's batch, whose
20
+ * `put`/`delete`/`write` never pass back through the wrapper — so counting the commit path
21
+ * takes a wrapper here, not merely new fields on the store.
22
+ *
23
+ * Operations are attributed to the `write()` that carried them, not to the moment they were
24
+ * queued: `pending` accumulates and is handed to the owner when `write()` fires, so a batch
25
+ * that is queued and then `clear()`ed (or abandoned without writing) contributes nothing.
26
+ * The hand-off happens BEFORE awaiting the inner write, so a commit that fails still counts
27
+ * as a round trip issued — which is what a caller measuring storage traffic is asking about.
28
+ */
29
+ class CountingWriteBatch {
30
+ inner;
31
+ onWrite;
32
+ /** Operations queued since construction or since the last `write()` / `clear()`. */
33
+ pending = 0;
34
+ constructor(inner, onWrite) {
35
+ this.inner = inner;
36
+ this.onWrite = onWrite;
37
+ }
38
+ put(key, value) {
39
+ this.pending++;
40
+ this.inner.put(key, value);
41
+ }
42
+ delete(key) {
43
+ this.pending++;
44
+ this.inner.delete(key);
45
+ }
46
+ write() {
47
+ const carried = this.pending;
48
+ this.pending = 0;
49
+ this.onWrite(carried);
50
+ return this.inner.write();
51
+ }
52
+ clear() {
53
+ this.pending = 0;
54
+ this.inner.clear();
55
+ }
56
+ }
57
+ /**
58
+ * Counts what passes through a wrapped {@link KVStore}. On the read side: entries pulled
59
+ * from `iterate()`, `get()` calls, `getMany()` round trips, and the keys those round trips
60
+ * carried. On the write side: point writes issued outside any batch, `write()` round trips,
61
+ * and the operations those carried.
62
+ *
63
+ * `getMany` routes through `defaultGetMany(this, keys)` rather than forwarding straight to
64
+ * `this.inner.getMany(keys)`. That is deliberate, not an oversight. `defaultGetMany` issues
65
+ * one `get(key)` per key against whatever object it is handed; passing `this` (the wrapper)
66
+ * means each of those `get` calls lands on THIS class's own overridden, counted `get()`
67
+ * (which in turn calls `this.inner.get`) — so a single `getMany` of N keys also advances
68
+ * `getCount` by N, matching how the specs built against this class assert. Forwarding to
69
+ * `this.inner.getMany(keys)` would run `defaultGetMany` with `this = inner`, bypassing the
70
+ * wrapper's `get()` entirely and leaving `getCount` unchanged after a batched read — a subtle
71
+ * break because most of the affected assertions are upper bounds (`.at.most(...)`), not exact
72
+ * equalities, so the bug would pass silently in most specs and only fail the one exact-equal
73
+ * assertion that happens to pin it.
74
+ *
75
+ * The trade-off this creates: `getManyCalls` / `getManyKeyCount` measure batching AT THE CALL
76
+ * BOUNDARY into this wrapper (did the caller invoke `getMany` once with N keys, vs. N calls to
77
+ * `get`) — not the wrapped backend's own internal round-trip count. That is the right thing to
78
+ * measure for the specs this class serves today, which are proving the ENGINE batches its
79
+ * reads, not that the wrapped backend has a native multi-get. A future benchmark reaching for
80
+ * this class to measure a REAL backend's own native batching needs to know that distinction.
81
+ *
82
+ * The write side has the SAME call-boundary caveat, and one structural requirement:
83
+ * `batch()` is overridden to return a {@link CountingWriteBatch}, because the base class's
84
+ * `batch()` hands out the inner store's batch directly and nothing queued on it would ever
85
+ * reach this wrapper. The write counters are deliberately split direct-vs-batched — a commit
86
+ * path that queues N operations and issues ONE `write()` is a different physical cost from
87
+ * one that issues N point writes, and a single combined "writes" number could not tell them
88
+ * apart. The four read counters and the four write counters are independent; a workload
89
+ * touches both.
90
+ */
91
+ export class CountingKVStore extends DelegatingKVStore {
92
+ /** Entries pulled from the inner store's `iterate()`. */
93
+ iterateEntryCount = 0;
94
+ /** `get()` calls. */
95
+ getCount = 0;
96
+ /** `getMany()` calls — round trips, as observed at this counting boundary. */
97
+ getManyCalls = 0;
98
+ /** Keys carried by those `getMany()` calls. */
99
+ getManyKeyCount = 0;
100
+ /** Puts issued one at a time, outside any batch. */
101
+ directPutCount = 0;
102
+ /** Deletes issued one at a time, outside any batch. */
103
+ directDeleteCount = 0;
104
+ /** `WriteBatch.write()` calls — the write-side round-trip count. */
105
+ batchWriteCalls = 0;
106
+ /** Put/delete operations those `write()` calls carried. */
107
+ batchOpCount = 0;
108
+ /** Zero every counter, read and write. */
109
+ reset() {
110
+ this.iterateEntryCount = 0;
111
+ this.getCount = 0;
112
+ this.getManyCalls = 0;
113
+ this.getManyKeyCount = 0;
114
+ this.directPutCount = 0;
115
+ this.directDeleteCount = 0;
116
+ this.batchWriteCalls = 0;
117
+ this.batchOpCount = 0;
118
+ }
119
+ async get(key) {
120
+ this.getCount++;
121
+ return this.inner.get(key);
122
+ }
123
+ async getMany(keys) {
124
+ this.getManyCalls++;
125
+ this.getManyKeyCount += keys.length;
126
+ // Must route through the wrapper's own `get` — see the class doc comment above.
127
+ return defaultGetMany(this, keys);
128
+ }
129
+ async *iterate(options) {
130
+ for await (const entry of this.inner.iterate(options)) {
131
+ this.iterateEntryCount++;
132
+ yield entry;
133
+ }
134
+ }
135
+ put(key, value, options) {
136
+ this.directPutCount++;
137
+ return this.inner.put(key, value, options);
138
+ }
139
+ delete(key, options) {
140
+ this.directDeleteCount++;
141
+ return this.inner.delete(key, options);
142
+ }
143
+ // NOTE: only the per-store `WriteBatch` path is counted, never `AtomicBatch`. Nothing
144
+ // counted reaches the atomic path today — `createCountingProvider` exposes no
145
+ // `beginAtomicBatch`, so the transaction coordinator always takes its per-store
146
+ // fallback — and an `AtomicBatch` wrapper nothing exercises is dead weight. If the
147
+ // counting provider ever gains a shared commit domain, wrap `AtomicBatch` at the same
148
+ // time: until then such a commit would report zero writes rather than fail loudly.
149
+ batch() {
150
+ return new CountingWriteBatch(this.inner.batch(), (opsCarried) => {
151
+ this.batchWriteCalls++;
152
+ this.batchOpCount += opsCarried;
153
+ });
154
+ }
155
+ }
156
+ /**
157
+ * A {@link KVStoreProvider} whose stores are {@link CountingKVStore}s, so a spec can assert
158
+ * on the read traffic (`iterate`/`get`/`getMany`) and the write traffic (point writes and
159
+ * batch commits) StoreModule generates, without reaching into a real backend.
160
+ *
161
+ * Store names come from the shared builders (`buildDataStoreName` / `buildIndexStoreName`,
162
+ * the reserved `__stats__` / `__catalog__` constants) — the same rule every real provider
163
+ * is held to by `runStoreNameDistinctness`. Hand-composing them here would lose the
164
+ * builders' lowercasing, so a mixed-case table name would land on a store no real backend
165
+ * would have used.
166
+ *
167
+ * @param countedStores - Map the counted stores are recorded into, keyed by BUILT store
168
+ * name: `schema.table` (every table's data store) and, when `scope` is `'all'`, also
169
+ * `schema.table_idx_index` (secondary indexes), `__stats__`, and `__catalog__`. The caller
170
+ * reads counters back out of this map after driving a query.
171
+ * @param scope - `'data'` (default): only each table's data store is counted; index,
172
+ * stats, and catalog stores stay plain, uncounted `InMemoryKVStore`s the caller never
173
+ * sees. `'all'`: every store the provider hands out is counted into `countedStores`.
174
+ */
175
+ // NOTE: implements no `deleteIndexStore` / `deleteTableStores` (both optional on the
176
+ // interface), so a spec that drops a table or index and recreates it under the same name
177
+ // reads the dropped store's entries back. Every spec using this provider today creates its
178
+ // tables once; if one starts exercising drop-then-recreate, implement them (erase, don't
179
+ // just drop the handle) rather than working around it in the spec.
180
+ export function createCountingProvider(countedStores, scope = 'data') {
181
+ const auxStores = new Map();
182
+ const aux = (key) => {
183
+ let s = auxStores.get(key);
184
+ if (!s) {
185
+ s = new InMemoryKVStore();
186
+ auxStores.set(key, s);
187
+ }
188
+ return s;
189
+ };
190
+ const counted = (key) => {
191
+ let s = countedStores.get(key);
192
+ if (!s) {
193
+ s = new CountingKVStore(new InMemoryKVStore());
194
+ countedStores.set(key, s);
195
+ }
196
+ return s;
197
+ };
198
+ const maybeCounted = (key) => (scope === 'all' ? counted(key) : aux(key));
199
+ return {
200
+ async getStore(schemaName, tableName) {
201
+ return counted(buildDataStoreName(schemaName, tableName));
202
+ },
203
+ async getIndexStore(schemaName, tableName, indexName) {
204
+ return maybeCounted(buildIndexStoreName(schemaName, tableName, indexName));
205
+ },
206
+ // One unified stats store for every table, as the interface specifies — the
207
+ // schema/table arguments are ignored.
208
+ async getStatsStore() {
209
+ return maybeCounted(STATS_STORE_NAME);
210
+ },
211
+ async getCatalogStore() {
212
+ return maybeCounted(CATALOG_STORE_NAME);
213
+ },
214
+ async closeStore() { },
215
+ async closeIndexStore() { },
216
+ async closeAll() {
217
+ for (const s of countedStores.values())
218
+ await s.close();
219
+ for (const s of auxStores.values())
220
+ await s.close();
221
+ countedStores.clear();
222
+ auxStores.clear();
223
+ },
224
+ };
225
+ }
226
+ //# sourceMappingURL=kv-counting-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-counting-store.js","sourceRoot":"","sources":["../../../src/testing/kv-counting-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The pass-through {@link KVStore} base every test double in this package extends —
3
+ * test-support, ships in `@quereus/store/testing`.
4
+ *
5
+ * Lives on its own rather than beside any one double because it is not specific to what
6
+ * any of them model: the counting store here, and the buffering / rescanning / getMany-
7
+ * misbehaving doubles in `test/kv-store-doubles.ts`, all subclass it and override exactly
8
+ * the one method whose behavior they are demonstrating.
9
+ */
10
+ import type { IterateOptions, KVEntry, KVStore, WriteBatch, WriteOptions } from '../common/kv-store.js';
11
+ /**
12
+ * Forwards every {@link KVStore} method to an inner store. Subclasses override only
13
+ * the one method whose behavior they are modeling.
14
+ */
15
+ export declare class DelegatingKVStore implements KVStore {
16
+ protected readonly inner: KVStore;
17
+ constructor(inner: KVStore);
18
+ get(key: Uint8Array): Promise<Uint8Array | undefined>;
19
+ getMany(keys: readonly Uint8Array[]): Promise<(Uint8Array | undefined)[]>;
20
+ put(key: Uint8Array, value: Uint8Array, options?: WriteOptions): Promise<void>;
21
+ delete(key: Uint8Array, options?: WriteOptions): Promise<void>;
22
+ has(key: Uint8Array): Promise<boolean>;
23
+ iterate(options?: IterateOptions): AsyncIterable<KVEntry>;
24
+ batch(): WriteBatch;
25
+ close(): Promise<void>;
26
+ approximateCount(options?: IterateOptions): Promise<number>;
27
+ }
28
+ //# sourceMappingURL=kv-delegating-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-delegating-store.d.ts","sourceRoot":"","sources":["../../../src/testing/kv-delegating-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAExG;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,OAAO;IACpC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO;gBAAd,KAAK,EAAE,OAAO;IAE7C,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAIrD,OAAO,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,CAAC,UAAU,GAAG,SAAS,CAAC,EAAE,CAAC;IAIzE,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9E,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,GAAG,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAItC,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC;IAIzD,KAAK,IAAI,UAAU;IAInB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,gBAAgB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;CAG3D"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The pass-through {@link KVStore} base every test double in this package extends —
3
+ * test-support, ships in `@quereus/store/testing`.
4
+ *
5
+ * Lives on its own rather than beside any one double because it is not specific to what
6
+ * any of them model: the counting store here, and the buffering / rescanning / getMany-
7
+ * misbehaving doubles in `test/kv-store-doubles.ts`, all subclass it and override exactly
8
+ * the one method whose behavior they are demonstrating.
9
+ */
10
+ /**
11
+ * Forwards every {@link KVStore} method to an inner store. Subclasses override only
12
+ * the one method whose behavior they are modeling.
13
+ */
14
+ export class DelegatingKVStore {
15
+ inner;
16
+ constructor(inner) {
17
+ this.inner = inner;
18
+ }
19
+ get(key) {
20
+ return this.inner.get(key);
21
+ }
22
+ getMany(keys) {
23
+ return this.inner.getMany(keys);
24
+ }
25
+ put(key, value, options) {
26
+ return this.inner.put(key, value, options);
27
+ }
28
+ delete(key, options) {
29
+ return this.inner.delete(key, options);
30
+ }
31
+ has(key) {
32
+ return this.inner.has(key);
33
+ }
34
+ iterate(options) {
35
+ return this.inner.iterate(options);
36
+ }
37
+ batch() {
38
+ return this.inner.batch();
39
+ }
40
+ close() {
41
+ return this.inner.close();
42
+ }
43
+ approximateCount(options) {
44
+ return this.inner.approximateCount(options);
45
+ }
46
+ }
47
+ //# sourceMappingURL=kv-delegating-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-delegating-store.js","sourceRoot":"","sources":["../../../src/testing/kv-delegating-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IACE;IAA/B,YAA+B,KAAc;QAAd,UAAK,GAAL,KAAK,CAAS;IAAG,CAAC;IAEjD,GAAG,CAAC,GAAe;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,CAAC,IAA2B;QAClC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,GAAG,CAAC,GAAe,EAAE,KAAiB,EAAE,OAAsB;QAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,GAAe,EAAE,OAAsB;QAC7C,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,GAAG,CAAC,GAAe;QAClB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,CAAC,OAAwB;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,KAAK;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,gBAAgB,CAAC,OAAwB;QACxC,OAAO,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;CACD"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Shared in-memory {@link KVStoreProvider} test double — test-support, ships in
3
+ * `@quereus/store/testing`.
4
+ *
5
+ * Nearly every spec in this package's `test/` directory (and this package's benchmark
6
+ * suite) opens with its own private copy of an all-`InMemoryKVStore` provider. This is the
7
+ * one shared implementation, built to the same conventions as its sibling
8
+ * {@link createCountingProvider}:
9
+ *
10
+ * - Store names come from {@link buildDataStoreName} / {@link buildIndexStoreName} and the
11
+ * reserved {@link CATALOG_STORE_NAME} / {@link STATS_STORE_NAME} constants — never
12
+ * hand-composed template strings, which drop the builders' lowercasing.
13
+ * - {@link KVStoreProvider.getStatsStore} returns ONE unified `__stats__` store for every
14
+ * table, as the interface specifies (its schema/table arguments are documented as
15
+ * ignored) — not the per-table `schema.table.__stats__` spelling most local copies use.
16
+ * - `options.costProfile` is spread in only when present, so a provider built with no
17
+ * options (or `{}`) has no `costProfile` property at all, matching what a genuine
18
+ * pre-profile third-party provider looks like.
19
+ *
20
+ * Unlike {@link createCountingProvider} — which deliberately omits `deleteIndexStore` /
21
+ * `deleteTableStores` — this provider implements both, and they ERASE rather than merely
22
+ * drop the map entry: see {@link erase} for why a live handle still needs its bytes cleared.
23
+ * `renameTableStores` is deliberately NOT implemented; `StoreModule` falls back to a generic
24
+ * copy for a provider without it (`test/rename-store-copy-fallback.spec.ts`), and nothing
25
+ * that needs this provider today renames.
26
+ *
27
+ * Neither is `beginAtomicBatch`, and that one is not a gap to fill later: separate
28
+ * `InMemoryKVStore`s share no commit domain, so there is nothing for a cross-store batch to
29
+ * make atomic. The consequence is worth knowing before reading numbers off this provider —
30
+ * `StoreModuleBase` sets `atomicProvider` from that method's presence and commits per store
31
+ * here, where a LevelDB-family provider commits in one physical write. A benchmark putting
32
+ * this provider next to LevelDB is comparing two commit PATHS, not one path over two
33
+ * backends.
34
+ */
35
+ import type { KVStoreProvider } from '../common/kv-store.js';
36
+ import type { KVCostProfile } from '../common/cost-profile.js';
37
+ /** Options accepted by {@link createInMemoryProvider}. */
38
+ export interface InMemoryProviderOptions {
39
+ /**
40
+ * Forwarded verbatim as the provider's declared `costProfile`. Omitted (the default)
41
+ * means the returned provider has no `costProfile` property at all — see the class doc
42
+ * comment above for why that shape matters to `resolveCostProfile`'s parity path.
43
+ */
44
+ readonly costProfile?: KVCostProfile;
45
+ }
46
+ /**
47
+ * Build an all-`InMemoryKVStore` {@link KVStoreProvider}. Every distinct built store name
48
+ * gets its own `InMemoryKVStore`, created lazily on first access.
49
+ */
50
+ export declare function createInMemoryProvider(options?: InMemoryProviderOptions): KVStoreProvider;
51
+ //# sourceMappingURL=memory-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-provider.d.ts","sourceRoot":"","sources":["../../../src/testing/memory-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI/D,0DAA0D;AAC1D,MAAM,WAAW,uBAAuB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,eAAe,CAqFzF"}