@procedures/collections 0.2.3 → 0.4.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.
@@ -31,6 +31,21 @@ export interface CollectionStorage<T> {
31
31
  * @returns Promise resolving to array of all items
32
32
  */
33
33
  getAll(): Promise<T[]>;
34
+ /**
35
+ * Every item with its id. A sync needs the ids: `getAll` gives only the values (roadmap R2).
36
+ * A storage that cannot give the ids does not have this method.
37
+ *
38
+ * @returns Promise resolving to the [id, item] pairs
39
+ */
40
+ getEntries?(): Promise<Array<[string, T]>>;
41
+ /**
42
+ * The changes after a version (roadmap R28). A storage without a change log does not have
43
+ * this method, and a sync uses `getEntries()`.
44
+ *
45
+ * @param since - A `version` that an earlier call gave. Without it, the result has all items.
46
+ * @returns Promise resolving to the changed items, the deleted ids and the new version
47
+ */
48
+ getChangesSince?(since?: string): Promise<StorageChanges<T>>;
34
49
  /**
35
50
  * Find items matching predicate.
36
51
  *
@@ -93,6 +108,13 @@ export interface CollectionStorage<T> {
93
108
  * @returns Promise resolving to Map of found items (missing IDs are omitted)
94
109
  */
95
110
  getBatch(ids: string[]): Promise<Map<string, T>>;
111
+ /**
112
+ * This method sends the writes that wait in the storage to their destination (roadmap R28). A storage
113
+ * that keeps no writes does not have this method.
114
+ *
115
+ * @returns Promise resolving when the waiting writes reached their destination
116
+ */
117
+ flush?(): Promise<void>;
96
118
  /**
97
119
  * Close storage and cleanup resources.
98
120
  * Should be called when collection is no longer needed.
@@ -108,6 +130,26 @@ export interface CollectionStorage<T> {
108
130
  */
109
131
  getMetadata?(): Promise<StorageMetadata>;
110
132
  }
133
+ /**
134
+ * The changes of a storage after a version (roadmap R28).
135
+ *
136
+ * - `version` is opaque. The next call gives it back as `since`.
137
+ * - When `full` is true, `changed` has every item, and each id that it does not have was
138
+ * deleted. A storage gives a full result when it cannot find the changes since the version:
139
+ * the first call, a version of an older run, or a change log that dropped old deletes.
140
+ * - When `full` is false, `changed` has the items that changed after the version, and `deleted`
141
+ * has the ids that were deleted after it.
142
+ */
143
+ export interface StorageChanges<T> {
144
+ /** The version of the storage that includes these changes. */
145
+ version: string;
146
+ /** True when `changed` has every item of the storage. */
147
+ full: boolean;
148
+ /** The items that changed, with their ids. */
149
+ changed: Array<[string, T]>;
150
+ /** The ids that were deleted. Empty when `full` is true. */
151
+ deleted: string[];
152
+ }
111
153
  /**
112
154
  * Optional storage metadata for monitoring.
113
155
  */
@@ -1 +1 @@
1
- {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/storage/interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAKlC;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAExC;;;;OAIG;IACH,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAEvB;;;;;OAKG;IACH,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAEpD;;;;;OAKG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElC;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAMxB;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAMvB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;;OAKG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE5C;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAMjD;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;;OAKG;IACH,WAAW,CAAC,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAExD,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,KAAK,CAAC,EAAE;QACN,iDAAiD;QACjD,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB,+CAA+C;QAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;QAElB,mDAAmD;QACnD,UAAU,CAAC,EAAE,MAAM,CAAC;QAEpB,iDAAiD;QACjD,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB,mBAAmB;QACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEvE"}
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/storage/interface.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/storage/interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA8JH;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAI,KAAiB;IACzD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/storage/interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA4MH;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAI,KAAiB;IACzD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -4,7 +4,16 @@
4
4
  * Fast, volatile storage using JavaScript Map.
5
5
  * All operations return Promises for interface consistency.
6
6
  */
7
- import type { CollectionStorage, StorageMetadata } from "./interface.js";
7
+ import type { CollectionStorage, StorageChanges, StorageMetadata } from "./interface.js";
8
+ /** Options of an in-memory storage. */
9
+ export interface InMemoryStorageOptions {
10
+ /**
11
+ * The number of deletes that the change log keeps (roadmap R28). After more deletes, the log
12
+ * drops the oldest ones, and `getChangesSince` of an older version gives all items.
13
+ * @default 10000
14
+ */
15
+ maxTombstones?: number;
16
+ }
8
17
  /**
9
18
  * In-memory storage backed by JavaScript Map.
10
19
  *
@@ -13,6 +22,8 @@ import type { CollectionStorage, StorageMetadata } from "./interface.js";
13
22
  * - No persistence (data lost on restart)
14
23
  * - Memory-bound (limited by available RAM)
15
24
  * - Returns Promises for API consistency with remote storage
25
+ * - Each error is a rejected promise: an error of a `find` predicate does not throw at once
26
+ * - A change log: `getChangesSince(version)` gives the changes after a version (roadmap R28)
16
27
  *
17
28
  * @example
18
29
  * ```typescript
@@ -23,8 +34,24 @@ import type { CollectionStorage, StorageMetadata } from "./interface.js";
23
34
  */
24
35
  export declare class InMemoryStorage<T> implements CollectionStorage<T> {
25
36
  private data;
37
+ private epoch;
38
+ private seq;
39
+ /** The number of the last write of each id that has an item */
40
+ private readonly changedAt;
41
+ /** The number of the delete of each id that has no item, the oldest first (the tombstones) */
42
+ private readonly deletedAt;
43
+ /** The log does not know the deletes at or below this number: they were dropped */
44
+ private floor;
45
+ private readonly maxTombstones;
46
+ constructor(options?: InMemoryStorageOptions);
26
47
  get(id: string): Promise<T | undefined>;
27
48
  getAll(): Promise<T[]>;
49
+ getEntries(): Promise<Array<[string, T]>>;
50
+ /**
51
+ * The changes after a version (roadmap R28). A version of another storage, of a closed
52
+ * storage, or older than the dropped deletes gives all items (`full: true`).
53
+ */
54
+ getChangesSince(since?: string): Promise<StorageChanges<T>>;
28
55
  find(predicate: (item: T) => boolean): Promise<T[]>;
29
56
  has(id: string): Promise<boolean>;
30
57
  size(): Promise<number>;
@@ -64,5 +91,9 @@ export declare class InMemoryStorage<T> implements CollectionStorage<T> {
64
91
  * Make storage iterable.
65
92
  */
66
93
  [Symbol.iterator](): IterableIterator<[string, T]>;
94
+ private noteSet;
95
+ private noteDelete;
96
+ /** The number of a version of this storage, or undefined for another or an unknown version. */
97
+ private parseVersion;
67
98
  }
68
99
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEzE;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,eAAe,CAAC,CAAC,CAAE,YAAW,iBAAiB,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,IAAI,CAAwB;IAMpC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAEtC;IAED,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,CAErB;IAED,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAQlD;IAED,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEhC;IAED,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAEtB;IAMD,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvC;IAED,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEnC;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAGrB;IAMD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjD;IAED,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1C;IAED,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAS/C;IAMD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAIrB;IAED,WAAW,IAAI,OAAO,CAAC,eAAe,CAAC,CAatC;IAMD;;;;OAIG;IACH,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAE/B;IAED;;;;OAIG;IACH,MAAM,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAE5B;IAED;;;;OAIG;IACH,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAEvC;IAED;;;;OAIG;IACH,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAE5E;IAED;;OAEG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAEjD;CACF"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,10 @@
4
4
  * Fast, volatile storage using JavaScript Map.
5
5
  * All operations return Promises for interface consistency.
6
6
  */
7
+ /** A new epoch: a version of another storage, or of a closed one, does not match it. */
8
+ function newEpoch() {
9
+ return Math.random().toString(36).slice(2, 10);
10
+ }
7
11
  /**
8
12
  * In-memory storage backed by JavaScript Map.
9
13
  *
@@ -12,6 +16,8 @@
12
16
  * - No persistence (data lost on restart)
13
17
  * - Memory-bound (limited by available RAM)
14
18
  * - Returns Promises for API consistency with remote storage
19
+ * - Each error is a rejected promise: an error of a `find` predicate does not throw at once
20
+ * - A change log: `getChangesSince(version)` gives the changes after a version (roadmap R28)
15
21
  *
16
22
  * @example
17
23
  * ```typescript
@@ -22,63 +28,107 @@
22
28
  */
23
29
  export class InMemoryStorage {
24
30
  data = new Map();
31
+ // The change log (roadmap R28). Each write gets the next number of `seq`. A version is
32
+ // `<epoch>:<seq>`.
33
+ epoch = newEpoch();
34
+ seq = 0;
35
+ /** The number of the last write of each id that has an item */
36
+ changedAt = new Map();
37
+ /** The number of the delete of each id that has no item, the oldest first (the tombstones) */
38
+ deletedAt = new Map();
39
+ /** The log does not know the deletes at or below this number: they were dropped */
40
+ floor = 0;
41
+ maxTombstones;
42
+ constructor(options = {}) {
43
+ this.maxTombstones = Math.max(0, options.maxTombstones ?? 10_000);
44
+ }
25
45
  //
26
46
  // ═══ Read Operations ═══
27
47
  //
28
- get(id) {
29
- return Promise.resolve(this.data.get(id));
48
+ async get(id) {
49
+ return this.data.get(id);
30
50
  }
31
- getAll() {
32
- return Promise.resolve(Array.from(this.data.values()));
51
+ async getAll() {
52
+ return Array.from(this.data.values());
33
53
  }
34
- find(predicate) {
54
+ async getEntries() {
55
+ return Array.from(this.data.entries());
56
+ }
57
+ /**
58
+ * The changes after a version (roadmap R28). A version of another storage, of a closed
59
+ * storage, or older than the dropped deletes gives all items (`full: true`).
60
+ */
61
+ async getChangesSince(since) {
62
+ const version = `${this.epoch}:${this.seq}`;
63
+ const from = this.parseVersion(since);
64
+ if (from === undefined || from < this.floor) {
65
+ return { version, full: true, changed: Array.from(this.data.entries()), deleted: [] };
66
+ }
67
+ const changed = [];
68
+ for (const [id, at] of this.changedAt) {
69
+ if (at > from)
70
+ changed.push([id, this.data.get(id)]);
71
+ }
72
+ const deleted = [];
73
+ for (const [id, at] of this.deletedAt) {
74
+ if (at > from)
75
+ deleted.push(id);
76
+ }
77
+ return { version, full: false, changed, deleted };
78
+ }
79
+ async find(predicate) {
35
80
  const results = [];
36
81
  for (const item of this.data.values()) {
37
82
  if (predicate(item)) {
38
83
  results.push(item);
39
84
  }
40
85
  }
41
- return Promise.resolve(results);
86
+ return results;
42
87
  }
43
- has(id) {
44
- return Promise.resolve(this.data.has(id));
88
+ async has(id) {
89
+ return this.data.has(id);
45
90
  }
46
- size() {
47
- return Promise.resolve(this.data.size);
91
+ async size() {
92
+ return this.data.size;
48
93
  }
49
94
  //
50
95
  // ═══ Write Operations ═══
51
96
  //
52
- set(id, value) {
97
+ async set(id, value) {
53
98
  this.data.set(id, value);
54
- return Promise.resolve();
99
+ this.noteSet(id);
55
100
  }
56
- delete(id) {
57
- return Promise.resolve(this.data.delete(id));
101
+ async delete(id) {
102
+ const existed = this.data.delete(id);
103
+ if (existed)
104
+ this.noteDelete(id);
105
+ return existed;
58
106
  }
59
- clear() {
107
+ async clear() {
108
+ for (const id of this.data.keys())
109
+ this.noteDelete(id);
60
110
  this.data.clear();
61
- return Promise.resolve();
62
111
  }
63
112
  //
64
113
  // ═══ Bulk Operations ═══
65
114
  //
66
- setBatch(items) {
115
+ async setBatch(items) {
67
116
  for (const [id, value] of items) {
68
117
  this.data.set(id, value);
118
+ this.noteSet(id);
69
119
  }
70
- return Promise.resolve();
71
120
  }
72
- deleteBatch(ids) {
121
+ async deleteBatch(ids) {
73
122
  let deleted = 0;
74
123
  for (const id of ids) {
75
124
  if (this.data.delete(id)) {
125
+ this.noteDelete(id);
76
126
  deleted++;
77
127
  }
78
128
  }
79
- return Promise.resolve(deleted);
129
+ return deleted;
80
130
  }
81
- getBatch(ids) {
131
+ async getBatch(ids) {
82
132
  const result = new Map();
83
133
  for (const id of ids) {
84
134
  const value = this.data.get(id);
@@ -86,28 +136,33 @@ export class InMemoryStorage {
86
136
  result.set(id, value);
87
137
  }
88
138
  }
89
- return Promise.resolve(result);
139
+ return result;
90
140
  }
91
141
  //
92
142
  // ═══ Lifecycle & Metadata ═══
93
143
  //
94
- close() {
144
+ async close() {
95
145
  // No cleanup needed for in-memory storage
96
146
  this.data.clear();
97
- return Promise.resolve();
98
- }
99
- getMetadata() {
147
+ // A new epoch: a version of the closed storage gives all items
148
+ this.changedAt.clear();
149
+ this.deletedAt.clear();
150
+ this.epoch = newEpoch();
151
+ this.seq = 0;
152
+ this.floor = 0;
153
+ }
154
+ async getMetadata() {
100
155
  // Rough memory estimation:
101
156
  // Each entry has ~overhead of 100 bytes (key string + Map entry overhead)
102
157
  const estimatedEntrySize = 100;
103
158
  const memoryUsage = this.data.size * estimatedEntrySize;
104
- return Promise.resolve({
159
+ return {
105
160
  type: "memory",
106
161
  size: this.data.size,
107
162
  stats: {
108
163
  memoryUsage,
109
164
  },
110
- });
165
+ };
111
166
  }
112
167
  //
113
168
  // ═══ Additional Methods (Map compatibility) ═══
@@ -150,5 +205,33 @@ export class InMemoryStorage {
150
205
  [Symbol.iterator]() {
151
206
  return this.data.entries();
152
207
  }
208
+ //
209
+ // ═══ The change log ═══
210
+ //
211
+ noteSet(id) {
212
+ this.changedAt.set(id, ++this.seq);
213
+ this.deletedAt.delete(id);
214
+ }
215
+ noteDelete(id) {
216
+ this.changedAt.delete(id);
217
+ // Delete, then set: the tombstone goes to the end of the order (the newest)
218
+ this.deletedAt.delete(id);
219
+ this.deletedAt.set(id, ++this.seq);
220
+ while (this.deletedAt.size > this.maxTombstones) {
221
+ const [oldest, at] = this.deletedAt.entries().next().value;
222
+ this.deletedAt.delete(oldest);
223
+ this.floor = Math.max(this.floor, at);
224
+ }
225
+ }
226
+ /** The number of a version of this storage, or undefined for another or an unknown version. */
227
+ parseVersion(since) {
228
+ if (since === undefined)
229
+ return undefined;
230
+ const separator = since.lastIndexOf(":");
231
+ if (separator < 0 || since.slice(0, separator) !== this.epoch)
232
+ return undefined;
233
+ const at = Number(since.slice(separator + 1));
234
+ return Number.isInteger(at) && at >= 0 && at <= this.seq ? at : undefined;
235
+ }
153
236
  }
154
237
  //# sourceMappingURL=memory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/storage/memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The checks of the contract suite. The suite does not import a test framework, so a runtime
3
+ * entry of this package never loads one. A failed check throws `ContractViolation`.
4
+ */
5
+ /** The error of a failed check of the contract suite. */
6
+ export declare class ContractViolation extends Error {
7
+ readonly name = "ContractViolation";
8
+ }
9
+ /** This function gives the text of a value for a message: JSON, with a `Map` as its entries. */
10
+ export declare function show(value: unknown): string;
11
+ /**
12
+ * This function compares two values deeply: JSON values, arrays, plain objects and maps. Two maps
13
+ * are equal when they have the same keys with equal values, in any order.
14
+ */
15
+ export declare function deepEqual(actual: unknown, expected: unknown): boolean;
16
+ /** This function throws `ContractViolation` when the two values are not deeply equal. */
17
+ export declare function same(actual: unknown, expected: unknown, what: string): void;
18
+ /** This function throws `ContractViolation` when the condition is false. */
19
+ export declare function holds(condition: boolean, what: string): void;
20
+ /**
21
+ * This function starts an operation that must fail with a rejected promise, and gives the error.
22
+ * A synchronous throw breaks the contract too: each method of a storage gives a promise.
23
+ */
24
+ export declare function rejects(start: () => Promise<unknown>, what: string): Promise<unknown>;
25
+ /** The entries sorted by id, for a comparison where the order is not part of the contract. */
26
+ export declare function byId<T>(entries: ReadonlyArray<readonly [string, T]>): Array<[string, T]>;
27
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/testing/check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yDAAyD;AACzD,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAkB,IAAI,uBAAuB;CAC9C;AAED,gGAAgG;AAChG,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAO3C;AAQD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAkBrE;AAED,yFAAyF;AACzF,wBAAgB,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAI3E;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAc3F;AAED,8FAA8F;AAC9F,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAExF"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The checks of the contract suite. The suite does not import a test framework, so a runtime
3
+ * entry of this package never loads one. A failed check throws `ContractViolation`.
4
+ */
5
+ /** The error of a failed check of the contract suite. */
6
+ export class ContractViolation extends Error {
7
+ name = "ContractViolation";
8
+ }
9
+ /** This function gives the text of a value for a message: JSON, with a `Map` as its entries. */
10
+ export function show(value) {
11
+ if (value === undefined)
12
+ return "undefined";
13
+ try {
14
+ return JSON.stringify(value, (_key, item) => (item instanceof Map ? { Map: [...item.entries()] } : item === undefined ? "<undefined>" : item));
15
+ }
16
+ catch {
17
+ return String(value);
18
+ }
19
+ }
20
+ function isPlainObject(value) {
21
+ if (typeof value !== "object" || value === null)
22
+ return false;
23
+ const prototype = Object.getPrototypeOf(value);
24
+ return prototype === Object.prototype || prototype === null;
25
+ }
26
+ /**
27
+ * This function compares two values deeply: JSON values, arrays, plain objects and maps. Two maps
28
+ * are equal when they have the same keys with equal values, in any order.
29
+ */
30
+ export function deepEqual(actual, expected) {
31
+ if (Object.is(actual, expected))
32
+ return true;
33
+ if (actual instanceof Map && expected instanceof Map) {
34
+ if (actual.size !== expected.size)
35
+ return false;
36
+ for (const [key, value] of actual) {
37
+ if (!expected.has(key) || !deepEqual(value, expected.get(key)))
38
+ return false;
39
+ }
40
+ return true;
41
+ }
42
+ if (Array.isArray(actual) && Array.isArray(expected)) {
43
+ return actual.length === expected.length && actual.every((item, index) => deepEqual(item, expected[index]));
44
+ }
45
+ if (isPlainObject(actual) && isPlainObject(expected)) {
46
+ const keys = Object.keys(actual);
47
+ if (keys.length !== Object.keys(expected).length)
48
+ return false;
49
+ return keys.every((key) => Object.prototype.hasOwnProperty.call(expected, key) && deepEqual(actual[key], expected[key]));
50
+ }
51
+ return false;
52
+ }
53
+ /** This function throws `ContractViolation` when the two values are not deeply equal. */
54
+ export function same(actual, expected, what) {
55
+ if (!deepEqual(actual, expected)) {
56
+ throw new ContractViolation(`${what}: expected ${show(expected)}, got ${show(actual)}`);
57
+ }
58
+ }
59
+ /** This function throws `ContractViolation` when the condition is false. */
60
+ export function holds(condition, what) {
61
+ if (!condition)
62
+ throw new ContractViolation(what);
63
+ }
64
+ /**
65
+ * This function starts an operation that must fail with a rejected promise, and gives the error.
66
+ * A synchronous throw breaks the contract too: each method of a storage gives a promise.
67
+ */
68
+ export async function rejects(start, what) {
69
+ let promise;
70
+ try {
71
+ promise = start();
72
+ }
73
+ catch (error) {
74
+ throw new ContractViolation(`${what}: the method threw at once (${show(error instanceof Error ? error.message : error)}), and did not give a rejected promise`);
75
+ }
76
+ holds(typeof promise?.then === "function", `${what}: the method did not give a promise`);
77
+ try {
78
+ await promise;
79
+ }
80
+ catch (error) {
81
+ return error;
82
+ }
83
+ throw new ContractViolation(`${what}: the promise did not reject`);
84
+ }
85
+ /** The entries sorted by id, for a comparison where the order is not part of the contract. */
86
+ export function byId(entries) {
87
+ return [...entries].map(([id, value]) => [id, value]).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
88
+ }
89
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/testing/check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,yDAAyD;AACzD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACxB,IAAI,GAAG,mBAAmB,CAAC;CAC9C;AAED,gGAAgG;AAChG,MAAM,UAAU,IAAI,CAAC,KAAc;IACjC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAa,EAAE,EAAE,CAAC,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1J,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAY,CAAC;IAC1D,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,QAAiB;IAC1D,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,MAAM,YAAY,GAAG,IAAI,QAAQ,YAAY,GAAG,EAAE,CAAC;QACrD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAChD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QAC/E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9G,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3H,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,IAAI,CAAC,MAAe,EAAE,QAAiB,EAAE,IAAY;IACnE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,cAAc,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,KAAK,CAAC,SAAkB,EAAE,IAAY;IACpD,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAA6B,EAAE,IAAY;IACvE,IAAI,OAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,GAAG,KAAK,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,+BAA+B,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAClK,CAAC;IACD,KAAK,CAAC,OAAO,OAAO,EAAE,IAAI,KAAK,UAAU,EAAE,GAAG,IAAI,qCAAqC,CAAC,CAAC;IACzF,IAAI,CAAC;QACH,MAAM,OAAO,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,iBAAiB,CAAC,GAAG,IAAI,8BAA8B,CAAC,CAAC;AACrE,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,IAAI,CAAI,OAA4C;IAClE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,EAAe,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtH,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `@procedures/collections/testing`: the test-only entry of this package.
3
+ *
4
+ * This entry holds the contract suite of `CollectionStorage`. A storage package runs it in its
5
+ * tests with a factory of its storage. The entry imports no test framework: the caller gives
6
+ * `describe` and `it`. The runtime entries of the package do not import this entry.
7
+ */
8
+ export { collectionStorageContract, describeCollectionStorageContract, type CollectionStorageContractOptions, type ContractCase, type ContractItem, type ContractStorage, type ContractTestApi, type ContractTestContext, } from "./storage-contract.js";
9
+ export { ContractViolation, deepEqual } from "./check.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,yBAAyB,EACzB,iCAAiC,EACjC,KAAK,gCAAgC,EACrC,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `@procedures/collections/testing`: the test-only entry of this package.
3
+ *
4
+ * This entry holds the contract suite of `CollectionStorage`. A storage package runs it in its
5
+ * tests with a factory of its storage. The entry imports no test framework: the caller gives
6
+ * `describe` and `it`. The runtime entries of the package do not import this entry.
7
+ */
8
+ export { collectionStorageContract, describeCollectionStorageContract, } from "./storage-contract.js";
9
+ export { ContractViolation, deepEqual } from "./check.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,yBAAyB,EACzB,iCAAiC,GAOlC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The contract of `CollectionStorage` as one test suite (finding of roadmap R45).
3
+ *
4
+ * Each storage package runs the suite with a factory of its storage: `InMemoryStorage` in this
5
+ * package, `ApiStorage` and `HybridStorage` in `@procedures/store`, and `SqliteStorage` in
6
+ * `@procedures/sqlite`. Before, each package copied the cases of `InMemoryStorage`.
7
+ *
8
+ * The suite is in the test-only entry `@procedures/collections/testing`. It imports no test
9
+ * framework: the caller gives `describe` and `it`, and the checks throw `ContractViolation`. So a
10
+ * storage package imports the suite without a cycle, and a runtime entry never loads vitest.
11
+ *
12
+ * ```ts
13
+ * import { describe, it } from "vitest";
14
+ * import { describeCollectionStorageContract } from "@procedures/collections/testing";
15
+ *
16
+ * describeCollectionStorageContract("MyStorage", { create: () => new MyStorage() }, { describe, it });
17
+ * ```
18
+ */
19
+ import type { CollectionStorage } from "../storage/interface.js";
20
+ /** The item of the suite. Its `id` is its key, so a `HybridStorage` can sync it. */
21
+ export interface ContractItem {
22
+ id: string;
23
+ n: number;
24
+ tags?: string[];
25
+ }
26
+ /** A storage of the suite. */
27
+ export type ContractStorage = CollectionStorage<ContractItem>;
28
+ /** The options of the suite: the factory of the storage, and what the storage keeps. */
29
+ export interface CollectionStorageContractOptions {
30
+ /** This function makes a new, empty storage for each case. The case closes it at its end. */
31
+ create(): ContractStorage | Promise<ContractStorage>;
32
+ /**
33
+ * This function makes a new, empty storage whose change log keeps at most `max` deletes. With it,
34
+ * the suite tests the drop of the old deletes. A storage without such a limit does not give it.
35
+ */
36
+ createWithMaxTombstones?: ((max: number) => ContractStorage | Promise<ContractStorage>) | undefined;
37
+ /**
38
+ * True when the storage keeps a copy of each value: a change of a value after `set`, or of a read
39
+ * value, does not change the stored item. The interface does not ask for copies, so the default
40
+ * is false, and the suite then does not test them.
41
+ */
42
+ copies?: boolean | undefined;
43
+ /**
44
+ * False when a stored `null` reads back as `undefined`. A remote storage can lose the difference
45
+ * on the wire. The default is true.
46
+ */
47
+ nullValues?: boolean | undefined;
48
+ }
49
+ /** The context that a test framework gives to a case. Vitest gives `skip`. */
50
+ export interface ContractTestContext {
51
+ skip?(note?: string): void;
52
+ }
53
+ /** One case of the suite. */
54
+ export interface ContractCase {
55
+ readonly name: string;
56
+ run(context?: ContractTestContext): Promise<void>;
57
+ }
58
+ /** The functions of a test framework that the suite uses: `describe` and `it` of vitest fit. */
59
+ export interface ContractTestApi {
60
+ describe(name: string, body: () => void): unknown;
61
+ it(name: string, body: (context: ContractTestContext) => Promise<void>): unknown;
62
+ }
63
+ /**
64
+ * This function gives the cases of the contract for a storage. Each case makes its own storage
65
+ * with `options.create`. A case for an optional method (`getEntries`, `getChangesSince`, `flush`,
66
+ * `getMetadata`) skips a storage without the method.
67
+ */
68
+ export declare function collectionStorageContract(options: CollectionStorageContractOptions): ContractCase[];
69
+ /**
70
+ * This function declares the suite in a test framework: one `describe` with one `it` for each
71
+ * case. Vitest gives `skip` to a case, so a case for a missing optional method shows as skipped.
72
+ */
73
+ export declare function describeCollectionStorageContract(name: string, options: CollectionStorageContractOptions, api: ContractTestApi): void;
74
+ //# sourceMappingURL=storage-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-contract.d.ts","sourceRoot":"","sources":["../../src/testing/storage-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAkB,MAAM,yBAAyB,CAAC;AAGjF,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,8BAA8B;AAC9B,MAAM,MAAM,eAAe,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;AAE9D,wFAAwF;AACxF,MAAM,WAAW,gCAAgC;IAC/C,6FAA6F;IAC7F,MAAM,IAAI,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrD;;;OAGG;IACH,uBAAuB,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,GAAG,SAAS,CAAC;IACpG;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED,gGAAgG;AAChG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC;IAClD,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;CAClF;AAyCD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gCAAgC,GAAG,YAAY,EAAE,CA6XnG;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gCAAgC,EAAE,GAAG,EAAE,eAAe,GAAG,IAAI,CAMrI"}