@lossless.org/client 1.18.0 → 1.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/nosqldb/classes.bsonassertion.d.ts +6 -2
- package/dist_ts/nosqldb/classes.bsonassertion.js +9 -7
- package/dist_ts/nosqldb/classes.collection.js +12 -2
- package/dist_ts/nosqldb/classes.collectiontopology.d.ts +7 -0
- package/dist_ts/nosqldb/classes.collectiontopology.js +25 -2
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +41 -5
- package/dist_ts/nosqldb/classes.exactpersistence.js +133 -90
- package/dist_ts/nosqldb/classes.ordinarypersistence.js +2 -2
- package/package.json +4 -4
- package/readme.md +1 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/nosqldb/classes.bsonassertion.ts +9 -6
- package/ts/nosqldb/classes.collection.ts +12 -1
- package/ts/nosqldb/classes.collectiontopology.ts +32 -4
- package/ts/nosqldb/classes.exactpersistence.ts +183 -144
- package/ts/nosqldb/classes.ordinarypersistence.ts +2 -1
|
@@ -76,8 +76,8 @@ export const validateOrdinaryStoredDocument = (documentArg, policyArg, persisted
|
|
|
76
76
|
if (policyArg.timestamps === 'managed' &&
|
|
77
77
|
(typeof clone._createdAt !== 'string' || typeof clone._updatedAt !== 'string'))
|
|
78
78
|
throw invalid();
|
|
79
|
-
assertBsonWithoutMutation(clone, policyArg.assertStoredDocument, invalid);
|
|
79
|
+
assertBsonWithoutMutation(clone, plugins.mongodb.BSON.serialize(clone), (documentArg) => plugins.mongodb.BSON.serialize(documentArg), policyArg.assertStoredDocument, invalid);
|
|
80
80
|
// The assertion must not retain authority to mutate the returned document.
|
|
81
81
|
return plugins.mongodb.BSON.deserialize(plugins.mongodb.BSON.serialize(clone));
|
|
82
82
|
};
|
|
83
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vcmRpbmFyeXBlcnNpc3RlbmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbm9zcWxkYi9jbGFzc2VzLm9yZGluYXJ5cGVyc2lzdGVuY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFpQnZFLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsaURBQWlELENBQUMsQ0FBQztBQUNuRixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLDhDQUE4QyxDQUFDLENBQUM7QUFFL0U7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLHlCQUF5QixHQUFHLENBQUMsUUFBYSxFQUFXLEVBQUUsQ0FDbEUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7QUFFbkM7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sK0JBQStCLEdBQUcsQ0FBQyxPQUFlLEVBQUUsUUFBZ0IsRUFBVyxFQUFFLENBQzVGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxLQUFLLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQztJQUMxRSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsS0FBSyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxXQUFXLENBQUMsQ0FBQztBQUUzRSxNQUFNLENBQUMsTUFBTSw0QkFBNEIsR0FBRyxDQUFDLFFBQWEsRUFBMEMsRUFBRTtJQUNwRyxNQUFNLE1BQU0sR0FBRyxRQUFRLEVBQUUsQ0FBQyxZQUFZLENBQTJDLENBQUM7SUFDbEYsSUFBSSxNQUFNLElB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lossless.org/client",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.",
|
|
6
6
|
"exports": {
|
|
@@ -81,15 +81,15 @@
|
|
|
81
81
|
"@aws-sdk/client-s3": "^3.1039.0",
|
|
82
82
|
"@clickhouse/client": "1.23.1",
|
|
83
83
|
"@git.zone/tsbuild": "5.1.2",
|
|
84
|
-
"@git.zone/tsbundle": "3.1.
|
|
84
|
+
"@git.zone/tsbundle": "3.1.3",
|
|
85
85
|
"@git.zone/tsrun": "3.0.2",
|
|
86
|
-
"@git.zone/tstest": "
|
|
86
|
+
"@git.zone/tstest": "7.1.0",
|
|
87
87
|
"@lossless.org/nosqldb": "8.0.2",
|
|
88
88
|
"@lossless.org/nosqldb-qualified": "npm:@lossless.org/nosqldb@10.7.2",
|
|
89
89
|
"@lossless.org/objectstorage": "10.3.1",
|
|
90
90
|
"@lossless.org/sqldb": "0.2.3",
|
|
91
91
|
"@push.rocks/qenv": "^6.1.3",
|
|
92
|
-
"@types/node": "26.6.
|
|
92
|
+
"@types/node": "26.6.3",
|
|
93
93
|
"mariadb": "3.5.4",
|
|
94
94
|
"mongodb-memory-server": "11.1.0"
|
|
95
95
|
},
|
package/readme.md
CHANGED
|
@@ -115,6 +115,7 @@ Family imports preserve the established SmartData and SmartBucket names and cons
|
|
|
115
115
|
| Grouped totals paging | rows come ordered by group key; `getGroupedTotalsPage()` returns `nextCursor` while `hasMore`, `cursor` continues after it, and `iterateGroupedTotals()` reads every group page by page — exact across pages for null, number, string and boolean group values (proven on NoSQLDB 8.0.2, 10.7.2 and MongoDB; ObjectId and date values are ordered by BSON type order but not yet covered by the paging tests), refused with `unsupported_operation` for other values, and a cursor from another query is refused with `invalid_argument` |
|
|
116
116
|
| Query-plan inspection | `Model.inspectQueryPlan(db, { filter, sort?, projection?, limit?, timeoutMS?, signal? })` — the winning plan's stages (`stage`, `depth`, `indexName`, `direction`) and `nReturned`/`totalKeysExamined`/`totalDocsExamined`, read-only and bounded, so a consumer proves a model query uses its intended index without raw driver access |
|
|
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
|
+
| 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 |
|
|
118
119
|
| 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 |
|
|
119
120
|
|
|
120
121
|
`docs/source/smartdata/readme.md` documents each one with its refusals.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @internal Shared ordinary/exact assertion invariant. `beforeArg` is the
|
|
3
|
+
* document's BSON encoding before the assertion runs; `encodeArg` encodes it
|
|
4
|
+
* again afterwards, and any difference is a mutation.
|
|
5
|
+
*/
|
|
4
6
|
export const assertBsonWithoutMutation = (
|
|
5
7
|
documentArg: object,
|
|
8
|
+
beforeArg: Uint8Array,
|
|
9
|
+
encodeArg: (documentArg: object) => Uint8Array,
|
|
6
10
|
assertionArg: (valueArg: unknown) => void,
|
|
7
11
|
errorArg: (reasonArg: 'assertion' | 'bson' | 'mutation', causeArg?: unknown) => Error,
|
|
8
12
|
): void => {
|
|
9
|
-
const before = plugins.mongodb.BSON.serialize(documentArg);
|
|
10
13
|
try {
|
|
11
14
|
const result = assertionArg(documentArg) as unknown;
|
|
12
15
|
if (result !== undefined) {
|
|
@@ -17,9 +20,9 @@ export const assertBsonWithoutMutation = (
|
|
|
17
20
|
}
|
|
18
21
|
} catch (causeArg) { throw errorArg('assertion', causeArg); }
|
|
19
22
|
let after: Uint8Array;
|
|
20
|
-
try { after =
|
|
23
|
+
try { after = encodeArg(documentArg); }
|
|
21
24
|
catch (causeArg) { throw errorArg('bson', causeArg); }
|
|
22
|
-
if (
|
|
25
|
+
if (Buffer.compare(beforeArg, after) !== 0) {
|
|
23
26
|
throw errorArg('mutation');
|
|
24
27
|
}
|
|
25
28
|
};
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
collectionModelSchemaResolverSymbol,
|
|
39
39
|
collectionTopologyDbInspectionSymbol,
|
|
40
|
+
createMissingCollectionSchemaBindingError,
|
|
40
41
|
findCollectionModelSchemaResolver,
|
|
41
42
|
getExpectedCollectionTopologyForSchema,
|
|
42
43
|
getIdentityIndexName,
|
|
@@ -1238,7 +1239,17 @@ const installCollectionBinding = <
|
|
|
1238
1239
|
schemaResolverArg: () => INormalizedCollectionModelSchema,
|
|
1239
1240
|
managerFollowsReceiverArg = false,
|
|
1240
1241
|
): TCollectionModelConstructor<TModel> => {
|
|
1241
|
-
const getCollection = (receiverArg
|
|
1242
|
+
const getCollection = (receiverArg: unknown) => {
|
|
1243
|
+
// The accessor is inherited. A subclass is served only while the binding
|
|
1244
|
+
// describes it: one that declares decorators or a persistence policy of its
|
|
1245
|
+
// own would otherwise write through this schema, dropping its own fields
|
|
1246
|
+
// and installing its own indexes in this collection.
|
|
1247
|
+
const receivingModel = typeof receiverArg === 'function'
|
|
1248
|
+
? receiverArg
|
|
1249
|
+
: (receiverArg as { constructor?: unknown }).constructor;
|
|
1250
|
+
if (findCollectionModelSchemaResolver(receivingModel) !== schemaResolverArg) {
|
|
1251
|
+
throw createMissingCollectionSchemaBindingError(receivingModel);
|
|
1252
|
+
}
|
|
1242
1253
|
const db = dbResolverArg(receiverArg);
|
|
1243
1254
|
if (!(db instanceof SmartdataDb)) {
|
|
1244
1255
|
throw new SmartdataPersistenceError(
|
|
@@ -262,15 +262,43 @@ export const findCollectionModelSchemaResolver = (
|
|
|
262
262
|
return undefined;
|
|
263
263
|
};
|
|
264
264
|
|
|
265
|
+
/**
|
|
266
|
+
* @internal The refusal for a model that resolves no collection schema
|
|
267
|
+
* binding. When the model extends a bound model, the message names that model
|
|
268
|
+
* and why its binding does not describe the subclass.
|
|
269
|
+
*/
|
|
270
|
+
export const createMissingCollectionSchemaBindingError = (
|
|
271
|
+
constructorArg: unknown,
|
|
272
|
+
): SmartdataPersistenceError => {
|
|
273
|
+
const name = typeof constructorArg === 'function' && constructorArg.name
|
|
274
|
+
? constructorArg.name
|
|
275
|
+
: 'unknown';
|
|
276
|
+
let boundAncestor: unknown = typeof constructorArg === 'function'
|
|
277
|
+
? Object.getPrototypeOf(constructorArg)
|
|
278
|
+
: undefined;
|
|
279
|
+
while (
|
|
280
|
+
typeof boundAncestor === 'function' &&
|
|
281
|
+
!Object.hasOwn(boundAncestor, collectionModelSchemaResolverSymbol)
|
|
282
|
+
) {
|
|
283
|
+
boundAncestor = Object.getPrototypeOf(boundAncestor);
|
|
284
|
+
}
|
|
285
|
+
return new SmartdataPersistenceError(
|
|
286
|
+
'invalid_configuration',
|
|
287
|
+
typeof boundAncestor === 'function'
|
|
288
|
+
? `Model "${name}" has no collection schema binding: it extends the bound model ` +
|
|
289
|
+
`"${boundAncestor.name}" but declares decorators or a persistence policy of its own, ` +
|
|
290
|
+
'which the inherited binding does not describe. Give it its own @Collection(), ' +
|
|
291
|
+
'@managed() or defineCollectionModel() binding.'
|
|
292
|
+
: `Model "${name}" has no collection schema binding.`,
|
|
293
|
+
);
|
|
294
|
+
};
|
|
295
|
+
|
|
265
296
|
const getSchemaResolver = (
|
|
266
297
|
constructorArg: ICollectionTopologyModelConstructor,
|
|
267
298
|
): TCollectionModelSchemaResolver => {
|
|
268
299
|
const resolver = findCollectionModelSchemaResolver(constructorArg);
|
|
269
300
|
if (resolver === undefined) {
|
|
270
|
-
throw
|
|
271
|
-
'invalid_configuration',
|
|
272
|
-
`Model "${constructorArg?.name || 'unknown'}" has no collection schema binding.`,
|
|
273
|
-
);
|
|
301
|
+
throw createMissingCollectionSchemaBindingError(constructorArg);
|
|
274
302
|
}
|
|
275
303
|
return resolver;
|
|
276
304
|
};
|