@lossless.org/client 1.20.2 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/nosqldb/classes.atomicdelete.js +3 -3
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +6 -3
- package/dist_ts/nosqldb/classes.atomicupdate.js +4 -4
- package/dist_ts/nosqldb/classes.bootstraprecord.js +10 -5
- package/dist_ts/nosqldb/classes.collection.js +53 -16
- package/dist_ts/nosqldb/classes.cursor.d.ts +4 -1
- package/dist_ts/nosqldb/classes.cursor.js +14 -3
- package/dist_ts/nosqldb/classes.db.d.ts +22 -0
- package/dist_ts/nosqldb/classes.db.js +25 -1
- package/dist_ts/nosqldb/classes.doc.js +35 -5
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +6 -0
- package/dist_ts/nosqldb/classes.exactpersistence.js +70 -13
- package/dist_ts/nosqldb/classes.readtracker.d.ts +87 -0
- package/dist_ts/nosqldb/classes.readtracker.js +876 -0
- package/dist_ts/nosqldb/classes.session.d.ts +30 -7
- package/dist_ts/nosqldb/classes.session.js +116 -26
- package/dist_ts/nosqldb/classes.storedinspection.js +12 -4
- package/dist_ts/nosqldb/classes.testdatabase.js +16 -9
- package/dist_ts/nosqldb/classes.writeobserver.d.ts +11 -0
- package/dist_ts/nosqldb/classes.writeobserver.js +1 -1
- package/package.json +1 -1
- package/readme.md +1 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/nosqldb/classes.atomicdelete.ts +16 -2
- package/ts/nosqldb/classes.atomicfindoneandupdate.ts +5 -0
- package/ts/nosqldb/classes.atomicupdate.ts +10 -1
- package/ts/nosqldb/classes.bootstraprecord.ts +7 -4
- package/ts/nosqldb/classes.collection.ts +56 -12
- package/ts/nosqldb/classes.cursor.ts +14 -1
- package/ts/nosqldb/classes.db.ts +32 -0
- package/ts/nosqldb/classes.doc.ts +32 -2
- package/ts/nosqldb/classes.exactpersistence.ts +93 -19
- package/ts/nosqldb/classes.readtracker.ts +1028 -0
- package/ts/nosqldb/classes.session.ts +163 -30
- package/ts/nosqldb/classes.storedinspection.ts +15 -3
- package/ts/nosqldb/classes.testdatabase.ts +14 -8
- package/ts/nosqldb/classes.writeobserver.ts +11 -0
|
@@ -136,4 +136,4 @@ export const captureSmartdataWrite = (dbArg, writeArg) => {
|
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
138
|
};
|
|
139
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
139
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy53cml0ZW9ic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbm9zcWxkYi9jbGFzc2VzLndyaXRlb2JzZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDakUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQW9FdEMsTUFBTSxxQkFBcUIsR0FBRyxFQUFFLENBQUM7QUFDakMsTUFBTSxhQUFhLEdBQUcsSUFBSSxPQUFPLEVBQW9DLENBQUM7QUFFdEUsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLFVBQW1CLEVBQWtCLEVBQUU7SUFDdkUsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxpQkFBaUIsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUNuRixJQUFJLE9BQU8sUUFBUSxLQUFLLFVBQVUsRUFBRSxDQUFDO1FBQ25DLE1BQU0sSUFBSSx5QkFBeUIsQ0FBQyxrQkFBa0IsRUFDcEQsMERBQTBELENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBQ0QsSUFDRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO1dBQ25CLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztXQUNuQixNQUFNLENBQUMsTUFBTSxHQUFHLHFCQUFxQjtXQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FDMUIsT0FBTyxRQUFRLEtBQUssUUFBUTtlQUN6QixRQUFRLENBQUMsTUFBTSxLQUFLLENBQUM7ZUFDckIsUUFBUSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUM7ZUFDdEIsUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztXQUMzQixJQUFJ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
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -117,6 +117,7 @@ Family imports preserve the established SmartData and SmartBucket names and cons
|
|
|
117
117
|
| Per-instance model binding | `bindDocToManager(manager, Model)` returns a subclass of a model declared with `@managed()` and no manager argument, named like the model and bound to that manager, so several databases use the same models at once; any other binding is refused with `invalid_configuration` |
|
|
118
118
|
| Subclasses need their own binding | a subclass of a bound model that declares decorators or a persistence policy of its own and no `@Collection()`, `@managed()` or `defineCollectionModel()` binding is refused with `invalid_configuration` on every read and write, so it never writes through the parent's schema; an undecorated subclass keeps the inherited binding |
|
|
119
119
|
| Observing this process's writes | `db.observeWrites({ fields, listener })` — one frozen report per acknowledged model write, `{ collection, kind, documents, anchors }` with the requested top-level fields of the written documents and of the selector's equality anchors; writes inside a `db.createSession()` transaction are reported after the commit, never after a rollback; works on NoSQLDB, where `watch()` is unsupported |
|
|
120
|
+
| Following this process's reads | `db.trackReads(fn)` resolves `{ result, reads }`; `reads.changed` turns true once a write this process makes through the database's models could have changed what a model read of `fn` returned, judged by the read's query and the ids it returned, and a write it cannot place counts as one that did, so a cache keyed by `reads` rebuilds only what a write touched; works on NoSQLDB |
|
|
120
121
|
| Disposable test databases on a unix socket | `SmartdataTestDatabase.create({ connection: { socketPath } })` from `@lossless.org/client/testsupport` reaches an engine that listens only on a unix-domain socket, fault helpers included; the loopback `host`/`port` form is unchanged |
|
|
121
122
|
|
|
122
123
|
`docs/source/smartdata/readme.md` documents each one with its refusals.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -40,7 +40,14 @@ export const executeAtomicDelete = async <T>(
|
|
|
40
40
|
},
|
|
41
41
|
);
|
|
42
42
|
if (result.deletedCount > 0) {
|
|
43
|
-
reportSmartdataCollectionWrite(
|
|
43
|
+
reportSmartdataCollectionWrite(
|
|
44
|
+
collectionArg,
|
|
45
|
+
optsArg?.session,
|
|
46
|
+
'delete',
|
|
47
|
+
null,
|
|
48
|
+
filterArg,
|
|
49
|
+
{ images: 'none' },
|
|
50
|
+
);
|
|
44
51
|
}
|
|
45
52
|
return result;
|
|
46
53
|
},
|
|
@@ -84,7 +91,14 @@ export const executeAtomicDeleteMany = async <T>(
|
|
|
84
91
|
},
|
|
85
92
|
);
|
|
86
93
|
if (result.deletedCount > 0) {
|
|
87
|
-
reportSmartdataCollectionWrite(
|
|
94
|
+
reportSmartdataCollectionWrite(
|
|
95
|
+
collectionArg,
|
|
96
|
+
optsArg?.session,
|
|
97
|
+
'delete',
|
|
98
|
+
null,
|
|
99
|
+
filterArg,
|
|
100
|
+
{ images: 'none' },
|
|
101
|
+
);
|
|
88
102
|
}
|
|
89
103
|
return result;
|
|
90
104
|
},
|
|
@@ -146,6 +146,10 @@ export const executeAtomicFindOneAndUpdate = async <T>(
|
|
|
146
146
|
classified.status === 'upserted' ? 'insert' : 'update',
|
|
147
147
|
classified.document ? [classified.document] : null,
|
|
148
148
|
filterArg,
|
|
149
|
+
{
|
|
150
|
+
images: classified.document ? optionsArg.returnDocument : 'none',
|
|
151
|
+
update: updateArg,
|
|
152
|
+
},
|
|
149
153
|
);
|
|
150
154
|
}
|
|
151
155
|
return classified;
|
|
@@ -233,6 +237,7 @@ export const executeAtomicFindOneAndReplace = async <T>(
|
|
|
233
237
|
? [classified.document]
|
|
234
238
|
: [classified.document, replacementArg],
|
|
235
239
|
filterArg,
|
|
240
|
+
{ images: optionsArg.returnDocument === 'after' ? 'after' : 'beforeAndAfter' },
|
|
236
241
|
);
|
|
237
242
|
}
|
|
238
243
|
return classified;
|
|
@@ -57,6 +57,7 @@ export const executeAtomicUpdate = async <T>(
|
|
|
57
57
|
result.upsertedCount > 0 ? 'insert' : 'update',
|
|
58
58
|
optsArg?.observedDocument ? [optsArg.observedDocument] : null,
|
|
59
59
|
filterArg,
|
|
60
|
+
{ images: 'none', update: updateArg },
|
|
60
61
|
);
|
|
61
62
|
}
|
|
62
63
|
return result;
|
|
@@ -122,6 +123,7 @@ export const executeAtomicUpsertMany = async <T>(
|
|
|
122
123
|
Object.hasOwn(upsertedIdsArg ?? {}, indexArg) ? 'insert' : 'update',
|
|
123
124
|
null,
|
|
124
125
|
operationArg.filter,
|
|
126
|
+
{ images: 'none', update: operationArg.update },
|
|
125
127
|
);
|
|
126
128
|
});
|
|
127
129
|
};
|
|
@@ -206,7 +208,14 @@ export const executeAtomicUpdateMany = async <T>(
|
|
|
206
208
|
},
|
|
207
209
|
);
|
|
208
210
|
if (result.matchedCount > 0) {
|
|
209
|
-
reportSmartdataCollectionWrite(
|
|
211
|
+
reportSmartdataCollectionWrite(
|
|
212
|
+
collectionArg,
|
|
213
|
+
optsArg?.session,
|
|
214
|
+
'update',
|
|
215
|
+
null,
|
|
216
|
+
filterArg,
|
|
217
|
+
{ images: 'none', update: updateArg },
|
|
218
|
+
);
|
|
210
219
|
}
|
|
211
220
|
return result;
|
|
212
221
|
} catch (errorArg) {
|
|
@@ -6,7 +6,8 @@ import { snapshotBoundedBsonDocument } from './classes.bsonsnapshot.js';
|
|
|
6
6
|
import { validateOrdinaryStoredDocument } from './classes.ordinarypersistence.js';
|
|
7
7
|
import { SmartdataPersistenceError, isMongoDuplicateKeyError } from './classes.persistence.js';
|
|
8
8
|
import { readBoundedInspectionCursor } from './classes.namespaceinspection.js';
|
|
9
|
-
import { reportSmartdataWrite } from './classes.session.js';
|
|
9
|
+
import { reportSmartdataWrite, reportSmartdataWriteFailure } from './classes.session.js';
|
|
10
|
+
import { runSmartdataWrite } from './classes.readtracker.js';
|
|
10
11
|
import {
|
|
11
12
|
collectionModelSchemaResolverSymbol, collectionTopologyDbInspectionSymbol,
|
|
12
13
|
getExpectedCollectionTopologyForSchema, inspectCollectionTopologySnapshot,
|
|
@@ -63,7 +64,7 @@ export const insertBootstrapRecord = async (
|
|
|
63
64
|
let outcome: TBootstrapOutcome;
|
|
64
65
|
try {
|
|
65
66
|
// Explicit preparation uses this same connection-generation guard.
|
|
66
|
-
outcome = await dbArg[collectionTopologyDbInspectionSymbol](async (mongoDbArg, assertCurrentArg) => {
|
|
67
|
+
outcome = await runSmartdataWrite(dbArg, () => dbArg[collectionTopologyDbInspectionSymbol](async (mongoDbArg, assertCurrentArg) => {
|
|
67
68
|
budget.check();
|
|
68
69
|
const namespaces = await readBoundedInspectionCursor(mongoDbArg.listCollections(
|
|
69
70
|
{ name: schema.collectionName },
|
|
@@ -91,18 +92,20 @@ export const insertBootstrapRecord = async (
|
|
|
91
92
|
} catch (errorArg) {
|
|
92
93
|
return isMongoDuplicateKeyError(errorArg) ? 'unique_conflict' : 'ambiguous_write';
|
|
93
94
|
}
|
|
94
|
-
});
|
|
95
|
+
}));
|
|
95
96
|
} catch {
|
|
97
|
+
if (dispatched) reportSmartdataWriteFailure(dbArg, undefined, schema.collectionName);
|
|
96
98
|
throw new SmartdataPersistenceError(dispatched ? 'ambiguous_write' : 'unsupported_operation',
|
|
97
99
|
dispatched ? 'Bootstrap insertion outcome is uncertain; inspect its explicit ID before proceeding.'
|
|
98
100
|
: 'Bootstrap insertion could not inspect the current database connection.');
|
|
99
101
|
}
|
|
100
102
|
if (outcome === 'inserted') {
|
|
101
103
|
reportSmartdataWrite(dbArg, undefined, {
|
|
102
|
-
collection: schema.collectionName, kind: 'insert', documents: [document],
|
|
104
|
+
collection: schema.collectionName, kind: 'insert', documents: [document], images: 'after',
|
|
103
105
|
});
|
|
104
106
|
return Object.freeze({ acknowledged: true, insertedId: document._id as string });
|
|
105
107
|
}
|
|
108
|
+
if (outcome === 'ambiguous_write') reportSmartdataWriteFailure(dbArg, undefined, schema.collectionName);
|
|
106
109
|
const messages = {
|
|
107
110
|
unique_conflict: 'Bootstrap record conflicts with a unique index.',
|
|
108
111
|
invalid_configuration: 'Bootstrap insertion requires absent or exact primary-only collection topology.',
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
leaseOrdinarySmartdataSession,
|
|
36
36
|
reportSmartdataCollectionWrite,
|
|
37
37
|
runWithOrdinarySmartdataSession,
|
|
38
|
+
trackSmartdataRead,
|
|
38
39
|
type TSmartdataOrdinarySession,
|
|
39
40
|
} from './classes.session.js';
|
|
40
41
|
import {
|
|
@@ -2422,12 +2423,20 @@ export class SmartdataCollection<T> {
|
|
|
2422
2423
|
{ ordinaryWrite: false, timeoutMS: opts?.timeoutMS },
|
|
2423
2424
|
async (rawSessionArg, deadlineArg) => {
|
|
2424
2425
|
await deadlineArg.join(this.init());
|
|
2425
|
-
|
|
2426
|
+
const tracked = trackSmartdataRead(this, opts?.session, {
|
|
2427
|
+
kind: 'documents',
|
|
2428
|
+
filter: filterObject,
|
|
2429
|
+
limited: true,
|
|
2430
|
+
});
|
|
2431
|
+
const document = await this.mongoDbCollection.findOne(filterObject, {
|
|
2426
2432
|
projection: opts?.projection,
|
|
2427
2433
|
maxTimeMS: opts?.maxTimeMS,
|
|
2428
2434
|
session: rawSessionArg,
|
|
2429
2435
|
...deadlineArg.commandOptions(),
|
|
2430
2436
|
});
|
|
2437
|
+
if (document) tracked?.record(document);
|
|
2438
|
+
tracked?.settle();
|
|
2439
|
+
return document;
|
|
2431
2440
|
},
|
|
2432
2441
|
);
|
|
2433
2442
|
}
|
|
@@ -2448,10 +2457,14 @@ export class SmartdataCollection<T> {
|
|
|
2448
2457
|
});
|
|
2449
2458
|
try {
|
|
2450
2459
|
await this.init();
|
|
2460
|
+
const tracked = trackSmartdataRead(this, opts?.session, {
|
|
2461
|
+
kind: 'documents',
|
|
2462
|
+
filter: filterObjectArg,
|
|
2463
|
+
});
|
|
2451
2464
|
const cursor = this.mongoDbCollection.find(filterObjectArg, {
|
|
2452
2465
|
session: lease.rawSession,
|
|
2453
2466
|
});
|
|
2454
|
-
return new SmartdataDbCursor(cursor, dbDocArg, lease.release);
|
|
2467
|
+
return new SmartdataDbCursor(cursor, dbDocArg, lease.release, tracked);
|
|
2455
2468
|
} catch (cursorCreationError) {
|
|
2456
2469
|
lease.release();
|
|
2457
2470
|
throw cursorCreationError;
|
|
@@ -2470,6 +2483,10 @@ export class SmartdataCollection<T> {
|
|
|
2470
2483
|
{ ordinaryWrite: false, timeoutMS: opts?.timeoutMS },
|
|
2471
2484
|
async (rawSessionArg, deadlineArg) => {
|
|
2472
2485
|
await deadlineArg.join(this.init());
|
|
2486
|
+
const tracked = trackSmartdataRead(this, opts?.session, {
|
|
2487
|
+
kind: 'documents',
|
|
2488
|
+
filter: filterObject,
|
|
2489
|
+
});
|
|
2473
2490
|
const cursor = this.mongoDbCollection.find(filterObject, {
|
|
2474
2491
|
session: rawSessionArg,
|
|
2475
2492
|
...deadlineArg.cursorOptions(),
|
|
@@ -2482,6 +2499,10 @@ export class SmartdataCollection<T> {
|
|
|
2482
2499
|
(cursorArg) => cursorArg.toArray(),
|
|
2483
2500
|
deadlineArg.signal,
|
|
2484
2501
|
);
|
|
2502
|
+
if (tracked) {
|
|
2503
|
+
for (const document of result) tracked.record(document);
|
|
2504
|
+
tracked.settle();
|
|
2505
|
+
}
|
|
2485
2506
|
|
|
2486
2507
|
// In-memory check for duplicate _id values (should never happen)
|
|
2487
2508
|
if (result.length > 0) {
|
|
@@ -2625,7 +2646,9 @@ export class SmartdataCollection<T> {
|
|
|
2625
2646
|
...deadlineArg.commandOptions(),
|
|
2626
2647
|
});
|
|
2627
2648
|
if (result.acknowledged) {
|
|
2628
|
-
reportSmartdataCollectionWrite(
|
|
2649
|
+
reportSmartdataCollectionWrite(
|
|
2650
|
+
this, opts?.session, 'insert', [saveableObject], undefined, { images: 'after' },
|
|
2651
|
+
);
|
|
2629
2652
|
}
|
|
2630
2653
|
return result;
|
|
2631
2654
|
} catch (err: any) {
|
|
@@ -2668,6 +2691,12 @@ export class SmartdataCollection<T> {
|
|
|
2668
2691
|
{ ordinaryWrite: false, timeoutMS: opts?.timeoutMS, signal: opts?.signal },
|
|
2669
2692
|
async (rawSessionArg, deadlineArg) => {
|
|
2670
2693
|
await deadlineArg.join(this.init());
|
|
2694
|
+
// Totals depend on every matching document, not on which ones come back.
|
|
2695
|
+
trackSmartdataRead(this, opts?.session, {
|
|
2696
|
+
kind: 'documents',
|
|
2697
|
+
filter: matchArg ?? {},
|
|
2698
|
+
matches: true,
|
|
2699
|
+
});
|
|
2671
2700
|
const pipeline: plugins.mongodb.Document[] = [];
|
|
2672
2701
|
if (matchArg && Object.keys(matchArg).length > 0) {
|
|
2673
2702
|
pipeline.push({ $match: matchArg });
|
|
@@ -2741,7 +2770,9 @@ export class SmartdataCollection<T> {
|
|
|
2741
2770
|
.map((indexArg) => saveableObjects[Number(indexArg)])
|
|
2742
2771
|
.filter((documentArg) => documentArg !== undefined);
|
|
2743
2772
|
if (inserted.length > 0) {
|
|
2744
|
-
reportSmartdataCollectionWrite(
|
|
2773
|
+
reportSmartdataCollectionWrite(
|
|
2774
|
+
this, opts?.session, 'insert', inserted, undefined, { images: 'after' },
|
|
2775
|
+
);
|
|
2745
2776
|
}
|
|
2746
2777
|
};
|
|
2747
2778
|
try {
|
|
@@ -2806,7 +2837,9 @@ export class SmartdataCollection<T> {
|
|
|
2806
2837
|
.map((indexArg) => prepared[Number(indexArg)])
|
|
2807
2838
|
.filter((documentArg) => documentArg !== undefined);
|
|
2808
2839
|
if (inserted.length > 0) {
|
|
2809
|
-
reportSmartdataCollectionWrite(
|
|
2840
|
+
reportSmartdataCollectionWrite(
|
|
2841
|
+
this, optsArg.session, 'insert', inserted, undefined, { images: 'after' },
|
|
2842
|
+
);
|
|
2810
2843
|
}
|
|
2811
2844
|
};
|
|
2812
2845
|
try {
|
|
@@ -2881,15 +2914,16 @@ export class SmartdataCollection<T> {
|
|
|
2881
2914
|
}
|
|
2882
2915
|
updateableObject[key] = saveableObject[key];
|
|
2883
2916
|
}
|
|
2917
|
+
const update = {
|
|
2918
|
+
$set: updateableObject,
|
|
2919
|
+
...(Object.keys(insertOnlyObject).length > 0
|
|
2920
|
+
? { $setOnInsert: insertOnlyObject }
|
|
2921
|
+
: {}),
|
|
2922
|
+
};
|
|
2884
2923
|
try {
|
|
2885
2924
|
const result = await this.mongoDbCollection.updateOne(
|
|
2886
2925
|
identifiableObject,
|
|
2887
|
-
|
|
2888
|
-
$set: updateableObject,
|
|
2889
|
-
...(Object.keys(insertOnlyObject).length > 0
|
|
2890
|
-
? { $setOnInsert: insertOnlyObject }
|
|
2891
|
-
: {}),
|
|
2892
|
-
},
|
|
2926
|
+
update,
|
|
2893
2927
|
{ upsert: true, session: rawSessionArg, ...deadlineArg.commandOptions() },
|
|
2894
2928
|
);
|
|
2895
2929
|
if (result.upsertedCount > 0 || result.matchedCount > 0) {
|
|
@@ -2899,6 +2933,7 @@ export class SmartdataCollection<T> {
|
|
|
2899
2933
|
result.upsertedCount > 0 ? 'insert' : 'update',
|
|
2900
2934
|
[saveableObject],
|
|
2901
2935
|
identifiableObject,
|
|
2936
|
+
{ images: 'none', update },
|
|
2902
2937
|
);
|
|
2903
2938
|
}
|
|
2904
2939
|
return result;
|
|
@@ -2939,6 +2974,7 @@ export class SmartdataCollection<T> {
|
|
|
2939
2974
|
'delete',
|
|
2940
2975
|
observedDocument ? [observedDocument] : null,
|
|
2941
2976
|
identifiableObject,
|
|
2977
|
+
{ images: 'none' },
|
|
2942
2978
|
);
|
|
2943
2979
|
}
|
|
2944
2980
|
return result;
|
|
@@ -2990,6 +3026,11 @@ export class SmartdataCollection<T> {
|
|
|
2990
3026
|
{ ordinaryWrite: false, timeoutMS: opts?.timeoutMS, signal: opts?.signal },
|
|
2991
3027
|
async (rawSessionArg, deadlineArg) => {
|
|
2992
3028
|
await deadlineArg.join(this.init());
|
|
3029
|
+
const tracked = trackSmartdataRead(this, opts?.session, {
|
|
3030
|
+
kind: 'count',
|
|
3031
|
+
filter: filterObject,
|
|
3032
|
+
hint: opts?.hint,
|
|
3033
|
+
});
|
|
2993
3034
|
const pipeline: plugins.mongodb.Document[] = [{ $match: filterObject }];
|
|
2994
3035
|
if (opts?.limit !== undefined) {
|
|
2995
3036
|
pipeline.push({ $limit: opts.limit });
|
|
@@ -3001,9 +3042,11 @@ export class SmartdataCollection<T> {
|
|
|
3001
3042
|
...deadlineArg.commandOptions(),
|
|
3002
3043
|
session: rawSessionArg,
|
|
3003
3044
|
});
|
|
3004
|
-
|
|
3045
|
+
const count = await runCursorOperation(cursor, async (cursorArg) =>
|
|
3005
3046
|
(await cursorArg.next())?.count ?? 0,
|
|
3006
3047
|
deadlineArg.signal);
|
|
3048
|
+
tracked?.settle();
|
|
3049
|
+
return count;
|
|
3007
3050
|
},
|
|
3008
3051
|
);
|
|
3009
3052
|
}
|
|
@@ -3065,6 +3108,7 @@ export class SmartdataCollection<T> {
|
|
|
3065
3108
|
duplicateFields: Array<{ field: string; duplicateValues: number }>;
|
|
3066
3109
|
}> {
|
|
3067
3110
|
await this.init();
|
|
3111
|
+
trackSmartdataRead(this, undefined, { kind: 'collection' });
|
|
3068
3112
|
const result = {
|
|
3069
3113
|
ok: true,
|
|
3070
3114
|
estimatedCount: 0,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SmartDataDbDoc } from './classes.doc.js';
|
|
2
|
+
import type { ISmartdataReadRecorder } from './classes.readtracker.js';
|
|
2
3
|
import * as plugins from './plugins.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -16,14 +17,23 @@ export class SmartdataDbCursor<T = any> {
|
|
|
16
17
|
* raw driver session or no session at all.
|
|
17
18
|
*/
|
|
18
19
|
private releaseSession: () => void;
|
|
20
|
+
/** Records the read for open read sets; it settles once the cursor is exhausted. */
|
|
21
|
+
private readRecorder?: ISmartdataReadRecorder;
|
|
19
22
|
constructor(
|
|
20
23
|
cursorArg: plugins.mongodb.FindCursor<T>,
|
|
21
24
|
dbDocArg: typeof SmartDataDbDoc,
|
|
22
25
|
releaseSessionArg: () => void = () => {},
|
|
26
|
+
readRecorderArg?: ISmartdataReadRecorder,
|
|
23
27
|
) {
|
|
24
|
-
this.mongodbCursor =
|
|
28
|
+
this.mongodbCursor = readRecorderArg
|
|
29
|
+
? cursorArg.map((documentArg) => {
|
|
30
|
+
readRecorderArg.record(documentArg);
|
|
31
|
+
return documentArg;
|
|
32
|
+
})
|
|
33
|
+
: cursorArg;
|
|
25
34
|
this.smartdataDbDoc = dbDocArg;
|
|
26
35
|
this.releaseSession = releaseSessionArg;
|
|
36
|
+
this.readRecorder = readRecorderArg;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
public async next(closeAtEnd = true): Promise<T | null> {
|
|
@@ -34,6 +44,7 @@ export class SmartdataDbCursor<T = any> {
|
|
|
34
44
|
return await this.closeAfterError(readError);
|
|
35
45
|
}
|
|
36
46
|
if (nextDocument === null) {
|
|
47
|
+
this.readRecorder?.settle();
|
|
37
48
|
if (closeAtEnd) {
|
|
38
49
|
await this.close();
|
|
39
50
|
}
|
|
@@ -59,6 +70,7 @@ export class SmartdataDbCursor<T = any> {
|
|
|
59
70
|
await forEachFuncArg(nextClassInstance as any);
|
|
60
71
|
}
|
|
61
72
|
} while (nextDocument);
|
|
73
|
+
this.readRecorder?.settle();
|
|
62
74
|
} catch (iterationError) {
|
|
63
75
|
if (closeCursorAtEnd) {
|
|
64
76
|
await this.closeAfterError(iterationError);
|
|
@@ -74,6 +86,7 @@ export class SmartdataDbCursor<T = any> {
|
|
|
74
86
|
let convertedResult: T[];
|
|
75
87
|
try {
|
|
76
88
|
const result = await this.mongodbCursor.toArray();
|
|
89
|
+
this.readRecorder?.settle();
|
|
77
90
|
convertedResult = result.map((itemArg) =>
|
|
78
91
|
this.smartdataDbDoc.createInstanceFromMongoDbNativeDoc(itemArg),
|
|
79
92
|
) as T[];
|
package/ts/nosqldb/classes.db.ts
CHANGED
|
@@ -24,8 +24,15 @@ import {
|
|
|
24
24
|
addSmartdataWriteObserver,
|
|
25
25
|
type ISmartdataWriteObserverOptions,
|
|
26
26
|
} from './classes.writeobserver.js';
|
|
27
|
+
import {
|
|
28
|
+
changeSmartdataReadSetsOfDb,
|
|
29
|
+
trackSmartdataReads,
|
|
30
|
+
type ISmartdataTrackedReads,
|
|
31
|
+
} from './classes.readtracker.js';
|
|
27
32
|
|
|
28
33
|
export { SmartdataSession } from './classes.session.js';
|
|
34
|
+
export { SmartdataReadSet } from './classes.readtracker.js';
|
|
35
|
+
export type { ISmartdataTrackedReads } from './classes.readtracker.js';
|
|
29
36
|
export type {
|
|
30
37
|
ISmartdataTransactionOptions,
|
|
31
38
|
TSmartdataOrdinarySession,
|
|
@@ -358,6 +365,7 @@ export class SmartdataDb {
|
|
|
358
365
|
this.beginLifecycleOperation('close');
|
|
359
366
|
this.transitionLifecycle('closing');
|
|
360
367
|
this.status = 'disconnected';
|
|
368
|
+
changeSmartdataReadSetsOfDb(this);
|
|
361
369
|
const mongoDbClient = this.pendingClient ?? this.mongoDbClient;
|
|
362
370
|
try {
|
|
363
371
|
const closeErrors: unknown[] = [];
|
|
@@ -544,6 +552,30 @@ export class SmartdataDb {
|
|
|
544
552
|
return addSmartdataWriteObserver(this, optionsArg);
|
|
545
553
|
}
|
|
546
554
|
|
|
555
|
+
/**
|
|
556
|
+
* Runs `fnArg` and records every model read it makes on this database:
|
|
557
|
+
* `findOne`, `findAll`, `getCursor`, counts, pages and the exact reads.
|
|
558
|
+
* Each read is kept as its query and the ids it returned. The returned
|
|
559
|
+
* `reads.changed` turns true once a write this process makes through the
|
|
560
|
+
* database's models could have changed any of those results; a write it
|
|
561
|
+
* cannot place, such as an update by a selector it cannot evaluate, counts
|
|
562
|
+
* as one that did. A cache keyed by `reads` rebuilds only what such a write
|
|
563
|
+
* touched.
|
|
564
|
+
*
|
|
565
|
+
* Writes of other processes, raw driver access and migrations are not
|
|
566
|
+
* followed. A read inside a transaction, a read of another database and a
|
|
567
|
+
* write made inside `fnArg` mark the set changed at once. Queries are
|
|
568
|
+
* evaluated by MongoDB's simple binary comparison, so a read of a view or of
|
|
569
|
+
* a collection with a default collation marks the set changed as well; each
|
|
570
|
+
* read collection is checked once per connection when `fnArg` returns.
|
|
571
|
+
* Close a set that is no longer needed.
|
|
572
|
+
*/
|
|
573
|
+
public async trackReads<TResult>(
|
|
574
|
+
fnArg: () => TResult | Promise<TResult>,
|
|
575
|
+
): Promise<ISmartdataTrackedReads<TResult>> {
|
|
576
|
+
return trackSmartdataReads(this, fnArg);
|
|
577
|
+
}
|
|
578
|
+
|
|
547
579
|
/**
|
|
548
580
|
* Creates a narrowly scoped MongoDB administration facade bound to this
|
|
549
581
|
* SmartData lifecycle. Applications never need direct driver access.
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
isOrdinarySessionInTransaction,
|
|
44
44
|
leaseOrdinarySmartdataSession,
|
|
45
45
|
runWithOrdinarySmartdataSession,
|
|
46
|
+
trackSmartdataRead,
|
|
46
47
|
type TSmartdataOrdinarySession,
|
|
47
48
|
} from './classes.session.js';
|
|
48
49
|
import {
|
|
@@ -6055,24 +6056,39 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
6055
6056
|
timeoutMS,
|
|
6056
6057
|
}, async (rawSessionArg, deadlineArg) => {
|
|
6057
6058
|
await deadlineArg.join(collection.init());
|
|
6059
|
+
const sort = { [optionsArg.sortField]: sortDirection, [uniqueField]: sortDirection } as const;
|
|
6060
|
+
const tracked = trackSmartdataRead(collection, optionsArg.session, {
|
|
6061
|
+
kind: 'documents',
|
|
6062
|
+
filter: selector,
|
|
6063
|
+
sort,
|
|
6064
|
+
limited: true,
|
|
6065
|
+
});
|
|
6058
6066
|
const rawCursor = collection.mongoDbCollection
|
|
6059
6067
|
.find(selector, { session: rawSessionArg, ...deadlineArg.cursorOptions() })
|
|
6060
|
-
.sort(
|
|
6068
|
+
.sort(sort)
|
|
6061
6069
|
.limit(limit + 1);
|
|
6062
6070
|
return runCursorOperation(rawCursor, async (cursorArg) => {
|
|
6063
6071
|
const rawDocuments = await cursorArg.toArray();
|
|
6072
|
+
if (tracked) {
|
|
6073
|
+
for (const rawDocument of rawDocuments) tracked.record(rawDocument);
|
|
6074
|
+
tracked.settle();
|
|
6075
|
+
}
|
|
6064
6076
|
const hasMore = rawDocuments.length > limit;
|
|
6065
6077
|
const pageRows = rawDocuments.slice(0, limit);
|
|
6066
6078
|
const documents = pageRows.map(
|
|
6067
6079
|
(rawDocument: any) => (this as any).createInstanceFromMongoDbNativeDoc(rawDocument) as T,
|
|
6068
6080
|
);
|
|
6069
6081
|
const lastRow: any = pageRows[pageRows.length - 1];
|
|
6082
|
+
const countTracked = optionsArg.withTotal
|
|
6083
|
+
? trackSmartdataRead(collection, optionsArg.session, { kind: 'count', filter: baseSelector })
|
|
6084
|
+
: undefined;
|
|
6070
6085
|
const total = optionsArg.withTotal
|
|
6071
6086
|
? await collection.mongoDbCollection.countDocuments(baseSelector, {
|
|
6072
6087
|
session: rawSessionArg,
|
|
6073
6088
|
...deadlineArg.commandOptions(),
|
|
6074
6089
|
})
|
|
6075
6090
|
: undefined;
|
|
6091
|
+
countTracked?.settle();
|
|
6076
6092
|
return {
|
|
6077
6093
|
documents,
|
|
6078
6094
|
...(hasMore && lastRow
|
|
@@ -6211,8 +6227,14 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
6211
6227
|
});
|
|
6212
6228
|
try {
|
|
6213
6229
|
await collection.init();
|
|
6230
|
+
const filter = (this as any).normalizeReadFilter(filterArg);
|
|
6231
|
+
// A modifier changes the query in ways a read set cannot follow, and a
|
|
6232
|
+
// skipped page depends on the documents before it.
|
|
6233
|
+
const tracked = trackSmartdataRead(collection, session, modifier
|
|
6234
|
+
? { kind: 'collection' }
|
|
6235
|
+
: { kind: 'documents', filter, sort, hint, matches: skip !== undefined && skip > 0, limited: Boolean(limit) });
|
|
6214
6236
|
let rawCursor: plugins.mongodb.FindCursor<any> =
|
|
6215
|
-
collection.mongoDbCollection.find(
|
|
6237
|
+
collection.mongoDbCollection.find(filter, {
|
|
6216
6238
|
projection,
|
|
6217
6239
|
session: lease.rawSession,
|
|
6218
6240
|
hint,
|
|
@@ -6261,6 +6283,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
6261
6283
|
rawCursor,
|
|
6262
6284
|
this as any as typeof SmartDataDbDoc,
|
|
6263
6285
|
lease.release,
|
|
6286
|
+
tracked,
|
|
6264
6287
|
);
|
|
6265
6288
|
} catch (cursorCreationError) {
|
|
6266
6289
|
lease.release();
|
|
@@ -6309,12 +6332,19 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
6309
6332
|
defaultTimeoutMS: 5_000,
|
|
6310
6333
|
signal: opts.signal,
|
|
6311
6334
|
}, async (rawSessionArg, deadlineArg) => {
|
|
6335
|
+
const tracked = trackSmartdataRead(collection, opts.session, {
|
|
6336
|
+
kind: 'documents', filter, sort, hint, matches: skip > 0, limited: true,
|
|
6337
|
+
});
|
|
6312
6338
|
const rawCursor = collection.mongoDbCollection.find(filter, {
|
|
6313
6339
|
projection, sort, hint, skip, limit, maxTimeMS,
|
|
6314
6340
|
...deadlineArg.cursorOptions(), session: rawSessionArg,
|
|
6315
6341
|
});
|
|
6316
6342
|
return runCursorOperation(rawCursor, async (cursorArg) => {
|
|
6317
6343
|
const documents = await cursorArg.toArray();
|
|
6344
|
+
if (tracked) {
|
|
6345
|
+
for (const document of documents) tracked.record(document);
|
|
6346
|
+
tracked.settle();
|
|
6347
|
+
}
|
|
6318
6348
|
return documents.map((documentArg) =>
|
|
6319
6349
|
(this as any).createInstanceFromMongoDbNativeDoc(documentArg) as T,
|
|
6320
6350
|
);
|