@spine-event-engine/storage 2.0.0-snapshot.2 → 2.0.0-snapshot.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -14
- package/REFERENCE.md +26 -18
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/entity-commit.d.ts +28 -23
- package/dist/internal/entity-commit.d.ts.map +1 -1
- package/dist/internal/entity-commit.js +10 -1
- package/dist/internal/entity-commit.js.map +1 -1
- package/dist/internal/entity-history.d.ts +1 -1
- package/dist/internal/entity-history.d.ts.map +1 -1
- package/dist/memory/canonical-utf8.d.ts.map +1 -1
- package/dist/memory/canonical-utf8.js +13 -6
- package/dist/memory/canonical-utf8.js.map +1 -1
- package/dist/memory/in-memory-entity-commit.d.ts +38 -6
- package/dist/memory/in-memory-entity-commit.d.ts.map +1 -1
- package/dist/memory/in-memory-entity-commit.js +281 -68
- package/dist/memory/in-memory-entity-commit.js.map +1 -1
- package/dist/memory/in-memory-entity-history.d.ts +115 -1
- package/dist/memory/in-memory-entity-history.d.ts.map +1 -1
- package/dist/memory/in-memory-entity-history.js +186 -41
- package/dist/memory/in-memory-entity-history.js.map +1 -1
- package/dist/memory/in-memory-record-storage.d.ts +19 -0
- package/dist/memory/in-memory-record-storage.d.ts.map +1 -1
- package/dist/memory/in-memory-record-storage.js +25 -4
- package/dist/memory/in-memory-record-storage.js.map +1 -1
- package/dist/memory/tenant-records.d.ts +33 -7
- package/dist/memory/tenant-records.d.ts.map +1 -1
- package/dist/memory/tenant-records.js +297 -77
- package/dist/memory/tenant-records.js.map +1 -1
- package/dist/provider.d.ts +18 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +23 -0
- package/dist/provider.js.map +1 -0
- package/dist/query/query-policy.d.ts +18 -14
- package/dist/query/query-policy.d.ts.map +1 -1
- package/dist/query/query-policy.js +55 -28
- package/dist/query/query-policy.js.map +1 -1
- package/dist/record/record-query.d.ts +12 -11
- package/dist/record/record-query.d.ts.map +1 -1
- package/dist/record/record-query.js +4 -1
- package/dist/record/record-query.js.map +1 -1
- package/dist/record/record-storage.d.ts +12 -5
- package/dist/record/record-storage.d.ts.map +1 -1
- package/dist/record/record-storage.js +14 -12
- package/dist/record/record-storage.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -27
- package/dist/record/record-mask.d.ts +0 -11
- package/dist/record/record-mask.d.ts.map +0 -1
- package/dist/record/record-mask.js +0 -82
- package/dist/record/record-mask.js.map +0 -1
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
* the License.
|
|
13
13
|
*/
|
|
14
14
|
import { CanonicalUtf8 } from "./canonical-utf8.js";
|
|
15
|
-
const tenantRecordsHost = globalThis;
|
|
16
15
|
/**
|
|
17
|
-
* Record slice
|
|
16
|
+
* Record slice for one tenant of an in-memory record storage.
|
|
17
|
+
*
|
|
18
|
+
* @typeParam I Record identifier type.
|
|
19
|
+
* @typeParam R Stored Protobuf message type.
|
|
18
20
|
*/
|
|
19
21
|
export class TenantRecords {
|
|
20
22
|
#records = new Map();
|
|
@@ -86,22 +88,25 @@ export class TenantRecords {
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
/**
|
|
89
|
-
*
|
|
91
|
+
* Captures one complete materialized slot for an Entity commit.
|
|
90
92
|
*
|
|
91
|
-
* @
|
|
93
|
+
* @param id Identifies the affected slot.
|
|
94
|
+
* @returns The slot key and its prior entry, including materialized columns.
|
|
92
95
|
*/
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
capture(id) {
|
|
97
|
+
const key = StoredValues.key(id);
|
|
98
|
+
return { key, entry: this.#records.get(key) };
|
|
95
99
|
}
|
|
96
100
|
/**
|
|
97
|
-
*
|
|
101
|
+
* Applies or restores one prepared slot without recomputing its key.
|
|
98
102
|
*
|
|
99
|
-
* @param
|
|
103
|
+
* @param slot Supplies the prepared key and complete entry or prior absence.
|
|
100
104
|
*/
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
apply(slot) {
|
|
106
|
+
if (slot.entry === undefined)
|
|
107
|
+
this.#records.delete(slot.key);
|
|
108
|
+
else
|
|
109
|
+
this.#records.set(slot.key, slot.entry);
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
/**
|
|
@@ -111,6 +116,11 @@ const StoredRecords = {
|
|
|
111
116
|
// prettier-ignore
|
|
112
117
|
/**
|
|
113
118
|
* Determines whether two materialized records represent the same stored value.
|
|
119
|
+
* @typeParam I Record identifier type.
|
|
120
|
+
* @typeParam R Stored Protobuf message type.
|
|
121
|
+
* @param left Supplies the first materialized record, when present.
|
|
122
|
+
* @param right Supplies the second materialized record, when present.
|
|
123
|
+
* @returns Whether both records have the same stored value.
|
|
114
124
|
*/
|
|
115
125
|
equal(left, right) {
|
|
116
126
|
if (left === undefined || right === undefined)
|
|
@@ -124,7 +134,13 @@ const StoredRecords = {
|
|
|
124
134
|
const TenantRecordQuery = {
|
|
125
135
|
// prettier-ignore
|
|
126
136
|
/**
|
|
127
|
-
*
|
|
137
|
+
* Returns logical entries for one tenant-scoped query.
|
|
138
|
+
* @typeParam I Record identifier type.
|
|
139
|
+
* @typeParam R Stored Protobuf message type.
|
|
140
|
+
* @param entries Supplies this tenant's stored entries.
|
|
141
|
+
* @param spec Defines record identity and materialized columns.
|
|
142
|
+
* @param query Specifies filters, ordering, continuation, and windowing.
|
|
143
|
+
* @returns Matching logical record entries in query order.
|
|
128
144
|
*/
|
|
129
145
|
entries(entries, spec, query) {
|
|
130
146
|
const bounded = TenantRecordQuery.selectBounded(entries, spec, query);
|
|
@@ -143,38 +159,160 @@ const TenantRecordQuery = {
|
|
|
143
159
|
}));
|
|
144
160
|
},
|
|
145
161
|
/**
|
|
146
|
-
*
|
|
162
|
+
* Returns the finite ordered window without retaining every matching entry.
|
|
163
|
+
* @typeParam I Record identifier type.
|
|
164
|
+
* @typeParam R Stored Protobuf message type.
|
|
165
|
+
* @param entries Supplies this tenant's stored entries.
|
|
166
|
+
* @param spec Defines record identity and materialized columns.
|
|
167
|
+
* @param query Specifies filters, ordering, continuation, and windowing.
|
|
168
|
+
* @returns The selected window, or undefined when bounded selection does not apply.
|
|
147
169
|
*/
|
|
148
170
|
selectBounded(entries, spec, query) {
|
|
149
|
-
|
|
171
|
+
const windowSize = TenantRecordQuery.boundedWindowSize(query.limit, query.offset);
|
|
172
|
+
if (windowSize === undefined)
|
|
150
173
|
return undefined;
|
|
151
174
|
const offset = query.offset ?? 0;
|
|
152
|
-
const windowSize = offset + query.limit;
|
|
153
|
-
if (!Number.isInteger(offset) ||
|
|
154
|
-
!Number.isInteger(query.limit) ||
|
|
155
|
-
offset < 0 ||
|
|
156
|
-
query.limit < 0) {
|
|
157
|
-
return undefined;
|
|
158
|
-
}
|
|
159
175
|
if (windowSize === 0)
|
|
160
176
|
return [];
|
|
161
177
|
const orders = query.sort ?? [];
|
|
162
178
|
const selected = [];
|
|
179
|
+
const filters = TenantRecordQuery.prepareFilters(query.filters);
|
|
180
|
+
const after = query.after === undefined ? undefined : TenantRecordQuery.prepareContinuation(query.after);
|
|
163
181
|
for (const entry of entries) {
|
|
164
|
-
if (!TenantRecordQuery.
|
|
165
|
-
(
|
|
166
|
-
|
|
182
|
+
if (!TenantRecordQuery.matchesIds(spec, entry, query.ids) ||
|
|
183
|
+
!TenantRecordQuery.matchesPreparedFilters(entry.stored, filters))
|
|
184
|
+
continue;
|
|
185
|
+
const prepared = TenantRecordQuery.prepareEntry(entry, orders);
|
|
186
|
+
if (after !== undefined &&
|
|
187
|
+
TenantRecordQuery.comparePreparedAfter(prepared, orders, after) <= 0)
|
|
167
188
|
continue;
|
|
168
|
-
|
|
169
|
-
TenantRecordQuery.insertSelected(selected, entry, windowSize, orders);
|
|
189
|
+
TenantRecordQuery.insertSelected(selected, prepared, windowSize, orders);
|
|
170
190
|
}
|
|
171
|
-
return selected.slice(offset);
|
|
191
|
+
return selected.slice(offset).map((candidate) => candidate.entry);
|
|
192
|
+
},
|
|
193
|
+
/**
|
|
194
|
+
* Determines the finite selection capacity of one bounded query.
|
|
195
|
+
* @param limit Maximum returned record count.
|
|
196
|
+
* @param offset Number of leading matches to skip.
|
|
197
|
+
* @returns Required capacity, or undefined for an unbounded query.
|
|
198
|
+
*/
|
|
199
|
+
boundedWindowSize(limit, offset) {
|
|
200
|
+
if (limit === undefined || !Number.isFinite(limit))
|
|
201
|
+
return undefined;
|
|
202
|
+
const start = offset ?? 0;
|
|
203
|
+
if (!Number.isInteger(start) || !Number.isInteger(limit) || start < 0 || limit < 0)
|
|
204
|
+
return undefined;
|
|
205
|
+
return start + limit;
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* Prepares expected filter values once for a bounded query.
|
|
209
|
+
* @param filters Supplies the requested column filters.
|
|
210
|
+
* @returns Canonical expected values for each filter.
|
|
211
|
+
*/
|
|
212
|
+
prepareFilters(filters) {
|
|
213
|
+
return filters?.map((filter) => ({
|
|
214
|
+
column: filter.column,
|
|
215
|
+
keys: (Array.isArray(filter.value) ? filter.value : [filter.value]).map((value) => StoredValues.key(value)),
|
|
216
|
+
}));
|
|
172
217
|
},
|
|
173
218
|
/**
|
|
174
|
-
*
|
|
219
|
+
* Matches materialized columns against filter keys prepared for this query.
|
|
220
|
+
* @typeParam I Record identifier type.
|
|
221
|
+
* @typeParam R Stored Protobuf message type.
|
|
222
|
+
* @param entry Supplies the materialized record.
|
|
223
|
+
* @param filters Supplies the prepared column filters, when present.
|
|
224
|
+
* @returns Whether every filter matches the record.
|
|
225
|
+
*/
|
|
226
|
+
matchesPreparedFilters(entry, filters) {
|
|
227
|
+
if (filters === undefined || filters.length === 0)
|
|
228
|
+
return true;
|
|
229
|
+
return filters.every((filter) => filter.keys.includes(StoredValues.key(TenantRecordQuery.resolveValue(entry, filter.column))));
|
|
230
|
+
},
|
|
231
|
+
/**
|
|
232
|
+
* Normalizes an entry's identity and ordered fields once for this query.
|
|
233
|
+
* @typeParam I Record identifier type.
|
|
234
|
+
* @typeParam R Stored Protobuf message type.
|
|
235
|
+
* @param entry Supplies the matching materialized record.
|
|
236
|
+
* @param orders Specifies the requested sort fields.
|
|
237
|
+
* @returns The prepared comparison values and original entry.
|
|
238
|
+
*/
|
|
239
|
+
prepareEntry(entry, orders) {
|
|
240
|
+
const id = StoredValues.normalize(entry.slotId);
|
|
241
|
+
return {
|
|
242
|
+
entry,
|
|
243
|
+
id,
|
|
244
|
+
values: orders.map((order) => order.field === "id"
|
|
245
|
+
? id
|
|
246
|
+
: StoredValues.normalize(TenantRecordQuery.resolveValue(entry.stored, order.field))),
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* Normalizes the requested keyset position once for this query.
|
|
251
|
+
* @typeParam I Record identifier type.
|
|
252
|
+
* @param after Supplies the keyset position.
|
|
253
|
+
* @returns The prepared continuation values.
|
|
254
|
+
*/
|
|
255
|
+
prepareContinuation(after) {
|
|
256
|
+
return {
|
|
257
|
+
id: StoredValues.normalize(after.id),
|
|
258
|
+
values: after.values.map((value) => StoredValues.normalize(value.value)),
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
/**
|
|
262
|
+
* Compares prepared entries by requested fields and storage identity.
|
|
263
|
+
* @typeParam I Record identifier type.
|
|
264
|
+
* @typeParam R Stored Protobuf message type.
|
|
265
|
+
* @param left Supplies the first prepared entry.
|
|
266
|
+
* @param right Supplies the second prepared entry.
|
|
267
|
+
* @param orders Specifies the requested sort fields.
|
|
268
|
+
* @returns A negative, zero, or positive comparison result.
|
|
269
|
+
*/
|
|
270
|
+
comparePrepared(left, right, orders) {
|
|
271
|
+
for (let index = 0; index < orders.length; index += 1) {
|
|
272
|
+
const order = orders[index];
|
|
273
|
+
if (order === undefined)
|
|
274
|
+
throw new Error("Record query sort order is invalid.");
|
|
275
|
+
const comparison = order.field === "id"
|
|
276
|
+
? StoredValues.compareIdentityNormalized(left.id, right.id)
|
|
277
|
+
: StoredValues.compareNormalized(left.values[index], right.values[index]);
|
|
278
|
+
if (comparison !== 0)
|
|
279
|
+
return order.direction === "desc" ? comparison * -1 : comparison;
|
|
280
|
+
}
|
|
281
|
+
return StoredValues.compareIdentityNormalized(left.id, right.id);
|
|
282
|
+
},
|
|
283
|
+
/**
|
|
284
|
+
* Compares one prepared entry to a normalized keyset continuation.
|
|
285
|
+
* @typeParam I Record identifier type.
|
|
286
|
+
* @typeParam R Stored Protobuf message type.
|
|
287
|
+
* @param entry Supplies the prepared entry.
|
|
288
|
+
* @param orders Specifies the requested sort fields.
|
|
289
|
+
* @param after Supplies the prepared continuation.
|
|
290
|
+
* @returns A negative, zero, or positive comparison result.
|
|
291
|
+
*/
|
|
292
|
+
comparePreparedAfter(entry, orders, after) {
|
|
293
|
+
for (let index = 0; index < orders.length; index += 1) {
|
|
294
|
+
const order = orders[index];
|
|
295
|
+
if (order === undefined)
|
|
296
|
+
throw new Error("Record query continuation sort order is invalid.");
|
|
297
|
+
const comparison = order.field === "id"
|
|
298
|
+
? StoredValues.compareIdentityNormalized(entry.id, after.values[index])
|
|
299
|
+
: StoredValues.compareNormalized(entry.values[index], after.values[index]);
|
|
300
|
+
if (comparison !== 0)
|
|
301
|
+
return order.direction === "desc" ? comparison * -1 : comparison;
|
|
302
|
+
}
|
|
303
|
+
return StoredValues.compareIdentityNormalized(entry.id, after.id);
|
|
304
|
+
},
|
|
305
|
+
/**
|
|
306
|
+
* Adds an entry to a bounded, ordered top window.
|
|
307
|
+
* @typeParam I Record identifier type.
|
|
308
|
+
* @typeParam R Stored Protobuf message type.
|
|
309
|
+
* @param selected Supplies the current prepared window to update.
|
|
310
|
+
* @param entry Supplies the prepared candidate entry.
|
|
311
|
+
* @param windowSize Sets the maximum number of entries to retain.
|
|
312
|
+
* @param orders Specifies the requested sort order.
|
|
175
313
|
*/
|
|
176
314
|
insertSelected(selected, entry, windowSize, orders) {
|
|
177
|
-
const comparison = (candidate) => TenantRecordQuery.
|
|
315
|
+
const comparison = (candidate) => TenantRecordQuery.comparePrepared(candidate, entry, orders);
|
|
178
316
|
let low = 0;
|
|
179
317
|
let high = selected.length;
|
|
180
318
|
while (low < high) {
|
|
@@ -195,6 +333,11 @@ const TenantRecordQuery = {
|
|
|
195
333
|
},
|
|
196
334
|
/**
|
|
197
335
|
* Applies offset and limit after filtering, ordering, and continuation.
|
|
336
|
+
* @typeParam T Record entry type.
|
|
337
|
+
* @param records Supplies ordered matching records.
|
|
338
|
+
* @param offset Sets the number of leading records to skip.
|
|
339
|
+
* @param limit Sets the maximum number of records to return.
|
|
340
|
+
* @returns The requested record window.
|
|
198
341
|
*/
|
|
199
342
|
applyWindow(records, offset, limit) {
|
|
200
343
|
const start = offset ?? 0;
|
|
@@ -202,6 +345,12 @@ const TenantRecordQuery = {
|
|
|
202
345
|
},
|
|
203
346
|
/**
|
|
204
347
|
* Removes entries at or before a keyset continuation.
|
|
348
|
+
* @typeParam I Record identifier type.
|
|
349
|
+
* @typeParam R Stored Protobuf message type.
|
|
350
|
+
* @param records Supplies ordered matching records.
|
|
351
|
+
* @param orders Specifies the requested sort order.
|
|
352
|
+
* @param after Supplies the continuation position, when present.
|
|
353
|
+
* @returns Records after the continuation position.
|
|
205
354
|
*/
|
|
206
355
|
continueAfter(records, orders, after) {
|
|
207
356
|
return after === undefined
|
|
@@ -209,7 +358,13 @@ const TenantRecordQuery = {
|
|
|
209
358
|
: records.filter((entry) => TenantRecordQuery.compareToContinuation(entry, orders, after) > 0);
|
|
210
359
|
},
|
|
211
360
|
/**
|
|
212
|
-
*
|
|
361
|
+
* Returns the comparison of entries by requested fields and storage-slot identity.
|
|
362
|
+
* @typeParam I Record identifier type.
|
|
363
|
+
* @typeParam R Stored Protobuf message type.
|
|
364
|
+
* @param left Supplies the first entry to compare.
|
|
365
|
+
* @param right Supplies the second entry to compare.
|
|
366
|
+
* @param orders Specifies the requested sort order.
|
|
367
|
+
* @returns A negative, zero, or positive comparison result.
|
|
213
368
|
*/
|
|
214
369
|
compareEntries(left, right, orders) {
|
|
215
370
|
for (const order of orders) {
|
|
@@ -222,7 +377,13 @@ const TenantRecordQuery = {
|
|
|
222
377
|
return StoredValues.compareIdentity(left.slotId, right.slotId);
|
|
223
378
|
},
|
|
224
379
|
/**
|
|
225
|
-
*
|
|
380
|
+
* Returns the comparison of an entry with one keyset continuation.
|
|
381
|
+
* @typeParam I Record identifier type.
|
|
382
|
+
* @typeParam R Stored Protobuf message type.
|
|
383
|
+
* @param entry Supplies the entry to compare.
|
|
384
|
+
* @param orders Specifies the requested sort order.
|
|
385
|
+
* @param after Supplies the continuation position.
|
|
386
|
+
* @returns A negative, zero, or positive comparison result.
|
|
226
387
|
*/
|
|
227
388
|
compareToContinuation(entry, orders, after) {
|
|
228
389
|
for (let index = 0; index < orders.length; index += 1) {
|
|
@@ -239,6 +400,12 @@ const TenantRecordQuery = {
|
|
|
239
400
|
},
|
|
240
401
|
/**
|
|
241
402
|
* Matches one entry against ID and column filters.
|
|
403
|
+
* @typeParam I Record identifier type.
|
|
404
|
+
* @typeParam R Stored Protobuf message type.
|
|
405
|
+
* @param spec Defines record identity and materialized columns.
|
|
406
|
+
* @param entry Supplies the candidate entry.
|
|
407
|
+
* @param query Specifies ID and column filters.
|
|
408
|
+
* @returns Whether the entry matches the query filters.
|
|
242
409
|
*/
|
|
243
410
|
matches(spec, entry, query) {
|
|
244
411
|
return (TenantRecordQuery.matchesIds(spec, entry, query.ids) &&
|
|
@@ -246,6 +413,11 @@ const TenantRecordQuery = {
|
|
|
246
413
|
},
|
|
247
414
|
/**
|
|
248
415
|
* Matches materialized values against all requested column filters.
|
|
416
|
+
* @typeParam I Record identifier type.
|
|
417
|
+
* @typeParam R Stored Protobuf message type.
|
|
418
|
+
* @param entry Supplies the materialized record and columns.
|
|
419
|
+
* @param filters Specifies column filters, when present.
|
|
420
|
+
* @returns Whether every filter matches the entry.
|
|
249
421
|
*/
|
|
250
422
|
matchesFilters(entry, filters) {
|
|
251
423
|
if (filters === undefined || filters.length === 0)
|
|
@@ -258,6 +430,12 @@ const TenantRecordQuery = {
|
|
|
258
430
|
},
|
|
259
431
|
/**
|
|
260
432
|
* Matches an entry's storage slot against requested logical IDs.
|
|
433
|
+
* @typeParam I Record identifier type.
|
|
434
|
+
* @typeParam R Stored Protobuf message type.
|
|
435
|
+
* @param spec Defines how record identifiers are copied.
|
|
436
|
+
* @param entry Supplies the candidate entry.
|
|
437
|
+
* @param ids Specifies requested identifiers, when present.
|
|
438
|
+
* @returns Whether the entry matches a requested identifier.
|
|
261
439
|
*/
|
|
262
440
|
matchesIds(spec, entry, ids) {
|
|
263
441
|
if (ids === undefined || ids.length === 0)
|
|
@@ -266,6 +444,11 @@ const TenantRecordQuery = {
|
|
|
266
444
|
},
|
|
267
445
|
/**
|
|
268
446
|
* Resolves an ID, materialized column, or record path value.
|
|
447
|
+
* @typeParam I Record identifier type.
|
|
448
|
+
* @typeParam R Stored Protobuf message type.
|
|
449
|
+
* @param entry Supplies the materialized record.
|
|
450
|
+
* @param field Names the ID, column, or record path to read.
|
|
451
|
+
* @returns The resolved field value.
|
|
269
452
|
*/
|
|
270
453
|
resolveValue(entry, field) {
|
|
271
454
|
if (field === "id")
|
|
@@ -282,24 +465,35 @@ const StoredValues = {
|
|
|
282
465
|
// prettier-ignore
|
|
283
466
|
/**
|
|
284
467
|
* Creates a canonical value key.
|
|
468
|
+
* @param value Supplies the value to encode.
|
|
469
|
+
* @returns A canonical key for the value.
|
|
285
470
|
*/
|
|
286
471
|
key(value) {
|
|
287
|
-
return
|
|
472
|
+
return JSON.stringify(StoredValues.encoded(value));
|
|
288
473
|
},
|
|
289
474
|
/**
|
|
290
475
|
* Compares values with the storage ordering rules.
|
|
476
|
+
* @param left Supplies the first value.
|
|
477
|
+
* @param right Supplies the second value.
|
|
478
|
+
* @returns A negative, zero, or positive comparison result.
|
|
291
479
|
*/
|
|
292
480
|
compare(left, right) {
|
|
293
481
|
return StoredValues.compareNormalized(StoredValues.normalize(left), StoredValues.normalize(right));
|
|
294
482
|
},
|
|
295
483
|
/**
|
|
296
484
|
* Compares storage slot identities with canonical UTF-8 text ordering.
|
|
485
|
+
* @param left Supplies the first identity.
|
|
486
|
+
* @param right Supplies the second identity.
|
|
487
|
+
* @returns A negative, zero, or positive comparison result.
|
|
297
488
|
*/
|
|
298
489
|
compareIdentity(left, right) {
|
|
299
490
|
return StoredValues.compareIdentityNormalized(StoredValues.normalize(left), StoredValues.normalize(right));
|
|
300
491
|
},
|
|
301
492
|
/**
|
|
302
493
|
* Reads a dot-separated path from an object value.
|
|
494
|
+
* @param value Supplies the value to inspect.
|
|
495
|
+
* @param path Names the dot-separated property path.
|
|
496
|
+
* @returns The value at the path, or undefined when absent.
|
|
303
497
|
*/
|
|
304
498
|
readPath(value, path) {
|
|
305
499
|
let current = value;
|
|
@@ -312,6 +506,9 @@ const StoredValues = {
|
|
|
312
506
|
},
|
|
313
507
|
/**
|
|
314
508
|
* Compares normalized values of the same or distinct kinds.
|
|
509
|
+
* @param left Supplies the first normalized value.
|
|
510
|
+
* @param right Supplies the second normalized value.
|
|
511
|
+
* @returns A negative, zero, or positive comparison result.
|
|
315
512
|
*/
|
|
316
513
|
compareNormalized(left, right) {
|
|
317
514
|
const leftKind = StoredValues.kind(left);
|
|
@@ -340,6 +537,9 @@ const StoredValues = {
|
|
|
340
537
|
},
|
|
341
538
|
/**
|
|
342
539
|
* Compares normalized storage identities, treating text as canonical UTF-8 bytes.
|
|
540
|
+
* @param left Supplies the first normalized identity.
|
|
541
|
+
* @param right Supplies the second normalized identity.
|
|
542
|
+
* @returns A negative, zero, or positive comparison result.
|
|
343
543
|
*/
|
|
344
544
|
compareIdentityNormalized(left, right) {
|
|
345
545
|
const leftKind = StoredValues.kind(left);
|
|
@@ -368,6 +568,9 @@ const StoredValues = {
|
|
|
368
568
|
},
|
|
369
569
|
/**
|
|
370
570
|
* Compares numbers while placing NaN after other numbers.
|
|
571
|
+
* @param left Supplies the first number.
|
|
572
|
+
* @param right Supplies the second number.
|
|
573
|
+
* @returns A negative, zero, or positive comparison result.
|
|
371
574
|
*/
|
|
372
575
|
compareNumbers(left, right) {
|
|
373
576
|
if (Number.isNaN(left) || Number.isNaN(right))
|
|
@@ -376,6 +579,9 @@ const StoredValues = {
|
|
|
376
579
|
},
|
|
377
580
|
/**
|
|
378
581
|
* Compares encoded bigint payloads numerically.
|
|
582
|
+
* @param left Supplies the first encoded bigint.
|
|
583
|
+
* @param right Supplies the second encoded bigint.
|
|
584
|
+
* @returns A negative, zero, or positive comparison result.
|
|
379
585
|
*/
|
|
380
586
|
compareBigInts(left, right) {
|
|
381
587
|
const l = BigInt(left);
|
|
@@ -384,6 +590,10 @@ const StoredValues = {
|
|
|
384
590
|
},
|
|
385
591
|
/**
|
|
386
592
|
* Compares lists lexicographically.
|
|
593
|
+
* @typeParam T List element type.
|
|
594
|
+
* @param left Supplies the first list.
|
|
595
|
+
* @param right Supplies the second list.
|
|
596
|
+
* @returns A negative, zero, or positive comparison result.
|
|
387
597
|
*/
|
|
388
598
|
compareLists(left, right) {
|
|
389
599
|
for (let index = 0; index < Math.min(left.length, right.length); index += 1) {
|
|
@@ -397,6 +607,9 @@ const StoredValues = {
|
|
|
397
607
|
},
|
|
398
608
|
/**
|
|
399
609
|
* Compares normalized objects by keys and then values.
|
|
610
|
+
* @param left Supplies the first normalized object.
|
|
611
|
+
* @param right Supplies the second normalized object.
|
|
612
|
+
* @returns A negative, zero, or positive comparison result.
|
|
400
613
|
*/
|
|
401
614
|
compareObjects(left, right) {
|
|
402
615
|
const leftKeys = Object.keys(left);
|
|
@@ -412,12 +625,18 @@ const StoredValues = {
|
|
|
412
625
|
},
|
|
413
626
|
/**
|
|
414
627
|
* Compares strings in code-unit order.
|
|
628
|
+
* @param left Supplies the first string.
|
|
629
|
+
* @param right Supplies the second string.
|
|
630
|
+
* @returns A negative, zero, or positive comparison result.
|
|
415
631
|
*/
|
|
416
632
|
compareText(left, right) {
|
|
417
633
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
418
634
|
},
|
|
419
635
|
/**
|
|
420
636
|
* Compares identity-value lists recursively.
|
|
637
|
+
* @param left Supplies the first normalized identity list.
|
|
638
|
+
* @param right Supplies the second normalized identity list.
|
|
639
|
+
* @returns A negative, zero, or positive comparison result.
|
|
421
640
|
*/
|
|
422
641
|
compareIdentityLists(left, right) {
|
|
423
642
|
for (let index = 0; index < Math.min(left.length, right.length); index += 1) {
|
|
@@ -429,6 +648,9 @@ const StoredValues = {
|
|
|
429
648
|
},
|
|
430
649
|
/**
|
|
431
650
|
* Compares object-shaped identities by canonical keys and values.
|
|
651
|
+
* @param left Supplies the first normalized identity object.
|
|
652
|
+
* @param right Supplies the second normalized identity object.
|
|
653
|
+
* @returns A negative, zero, or positive comparison result.
|
|
432
654
|
*/
|
|
433
655
|
compareIdentityObjects(left, right) {
|
|
434
656
|
const leftKeys = Object.keys(left);
|
|
@@ -445,6 +667,8 @@ const StoredValues = {
|
|
|
445
667
|
},
|
|
446
668
|
/**
|
|
447
669
|
* Normalizes a value for canonical storage comparison.
|
|
670
|
+
* @param value Supplies the value to normalize.
|
|
671
|
+
* @returns The normalized value representation.
|
|
448
672
|
*/
|
|
449
673
|
normalize(value) {
|
|
450
674
|
if (typeof value === "bigint")
|
|
@@ -472,54 +696,39 @@ const StoredValues = {
|
|
|
472
696
|
}, StoredValues.emptyObject());
|
|
473
697
|
},
|
|
474
698
|
/**
|
|
475
|
-
*
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
return JSON.stringify(StoredValues.encoded(value));
|
|
479
|
-
},
|
|
480
|
-
/**
|
|
481
|
-
* Converts a normalized value to its tagged JSON representation.
|
|
699
|
+
* Converts a raw value to its tagged JSON representation.
|
|
700
|
+
* @param value Supplies the raw value.
|
|
701
|
+
* @returns The tagged JSON representation.
|
|
482
702
|
*/
|
|
483
703
|
encoded(value) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
return [
|
|
508
|
-
"array",
|
|
509
|
-
...value.map((entry) => StoredValues.encoded(entry)),
|
|
510
|
-
];
|
|
511
|
-
case "object":
|
|
512
|
-
return [
|
|
513
|
-
"object",
|
|
514
|
-
...Object.keys(value).map((key) => [
|
|
515
|
-
key,
|
|
516
|
-
StoredValues.encoded(value[key]),
|
|
517
|
-
]),
|
|
518
|
-
];
|
|
519
|
-
}
|
|
704
|
+
if (value === undefined)
|
|
705
|
+
return ["undefined"];
|
|
706
|
+
if (value === null)
|
|
707
|
+
return ["null"];
|
|
708
|
+
if (typeof value === "boolean")
|
|
709
|
+
return ["boolean", value];
|
|
710
|
+
if (typeof value === "number")
|
|
711
|
+
return ["number", String(value)];
|
|
712
|
+
if (typeof value === "string")
|
|
713
|
+
return ["string", value];
|
|
714
|
+
if (typeof value === "bigint")
|
|
715
|
+
return ["bigint", value.toString()];
|
|
716
|
+
if (value instanceof Uint8Array)
|
|
717
|
+
return ["bytes", [...value]];
|
|
718
|
+
if (Array.isArray(value))
|
|
719
|
+
return ["array", ...value.map((entry) => StoredValues.encoded(entry))];
|
|
720
|
+
if (typeof value !== "object")
|
|
721
|
+
return ["undefined"];
|
|
722
|
+
// Evaluate fields in lexical order, then use native numeric-name enumeration.
|
|
723
|
+
const entries = Object.fromEntries(Object.keys(value)
|
|
724
|
+
.sort()
|
|
725
|
+
.map((key) => [key, StoredValues.encoded(Reflect.get(value, key))]));
|
|
726
|
+
return ["object", ...Object.entries(entries)];
|
|
520
727
|
},
|
|
521
728
|
/**
|
|
522
|
-
*
|
|
729
|
+
* Returns the kind of a normalized value.
|
|
730
|
+
* @param value Supplies the normalized value.
|
|
731
|
+
* @returns The normalized value kind.
|
|
523
732
|
*/
|
|
524
733
|
kind(value) {
|
|
525
734
|
if (value === undefined)
|
|
@@ -539,6 +748,11 @@ const StoredValues = {
|
|
|
539
748
|
},
|
|
540
749
|
/**
|
|
541
750
|
* Creates a frozen tagged normalized value.
|
|
751
|
+
* @typeParam K Tag kind.
|
|
752
|
+
* @typeParam P Payload type.
|
|
753
|
+
* @param kind Identifies the tag kind.
|
|
754
|
+
* @param payload Supplies the tag payload.
|
|
755
|
+
* @returns The frozen tagged value.
|
|
542
756
|
*/
|
|
543
757
|
tagged(kind, payload) {
|
|
544
758
|
const tagged = Object.create(null);
|
|
@@ -550,6 +764,8 @@ const StoredValues = {
|
|
|
550
764
|
},
|
|
551
765
|
/**
|
|
552
766
|
* Reads a recognized normalized tag.
|
|
767
|
+
* @param value Supplies the object to inspect.
|
|
768
|
+
* @returns The recognized tag, or undefined for an ordinary object.
|
|
553
769
|
*/
|
|
554
770
|
tag(value) {
|
|
555
771
|
const tag = value[normalizedKind];
|
|
@@ -557,12 +773,16 @@ const StoredValues = {
|
|
|
557
773
|
},
|
|
558
774
|
/**
|
|
559
775
|
* Creates an object with no prototype for normalized fields.
|
|
776
|
+
* @returns An empty object without a prototype.
|
|
560
777
|
*/
|
|
561
778
|
emptyObject() {
|
|
562
779
|
return Object.create(null);
|
|
563
780
|
},
|
|
564
781
|
/**
|
|
565
782
|
* Reads a tagged normalized payload.
|
|
783
|
+
* @typeParam P Payload type.
|
|
784
|
+
* @param value Supplies the tagged value.
|
|
785
|
+
* @returns The tagged payload.
|
|
566
786
|
*/
|
|
567
787
|
payload(value) {
|
|
568
788
|
return value[normalizedPayload];
|