@lossless.org/client 1.8.0 → 1.10.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 +2 -2
- package/dist_ts/nosqldb/classes.testdatabase.d.ts +14 -1
- package/dist_ts/nosqldb/classes.testdatabase.js +38 -16
- package/dist_ts/nosqldb/testsupport.d.ts +1 -1
- package/package.json +2 -2
- package/readme.md +9 -6
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/nosqldb/classes.testdatabase.ts +56 -16
- package/ts/nosqldb/testsupport.ts +2 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@lossless.org/client',
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '1.10.0',
|
|
7
7
|
description: 'One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.'
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxzQkFBc0I7SUFDNUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLDBGQUEwRjtDQUN4RyxDQUFBIn0=
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SmartdataDb } from './classes.db.js';
|
|
2
2
|
import { SmartDataDbDoc } from './classes.doc.js';
|
|
3
3
|
import { SmartdataPersistenceError } from './classes.persistence.js';
|
|
4
|
+
/** A loopback TCP engine endpoint. */
|
|
4
5
|
export interface ISmartdataTestConnection {
|
|
5
6
|
/** Literal loopback IPv4, ::1, or localhost (normalized to 127.0.0.1). */
|
|
6
7
|
host: string;
|
|
@@ -9,8 +10,20 @@ export interface ISmartdataTestConnection {
|
|
|
9
10
|
username?: string;
|
|
10
11
|
password?: string;
|
|
11
12
|
}
|
|
13
|
+
/** A unix-domain socket engine endpoint. */
|
|
14
|
+
export interface ISmartdataTestSocketConnection {
|
|
15
|
+
/**
|
|
16
|
+
* Absolute canonical path ending in `.sock` (the MongoDB connection-string rule for
|
|
17
|
+
* socket hosts), at most 107 UTF-8 bytes, without control characters, lone surrogates or `%`.
|
|
18
|
+
*/
|
|
19
|
+
socketPath: string;
|
|
20
|
+
/** Supply both credentials or neither. Authentication uses admin. */
|
|
21
|
+
username?: string;
|
|
22
|
+
password?: string;
|
|
23
|
+
}
|
|
24
|
+
export type TSmartdataTestConnection = ISmartdataTestConnection | ISmartdataTestSocketConnection;
|
|
12
25
|
export interface ISmartdataTestDatabaseOptions {
|
|
13
|
-
connection:
|
|
26
|
+
connection: TSmartdataTestConnection;
|
|
14
27
|
/** Default 5000; maximum 120000 ms, shared by connection and ownership checks. */
|
|
15
28
|
timeoutMs?: number;
|
|
16
29
|
signal?: AbortSignal;
|
|
@@ -16,6 +16,32 @@ export class SmartdataTestDatabaseCreationError extends SmartdataPersistenceErro
|
|
|
16
16
|
}
|
|
17
17
|
const faultError = () => new SmartdataPersistenceError('invalid_argument', 'Fault data must be bounded, inert, canonical BSON with an explicit scalar _id.');
|
|
18
18
|
const canonicalFaultDocument = (valueArg, maxBytesArg) => snapshotBoundedBsonDocument(valueArg, maxBytesArg, faultError);
|
|
19
|
+
/** Linux `sun_path` holds 108 bytes including the terminating NUL. */
|
|
20
|
+
const socketPathMaxBytes = 107;
|
|
21
|
+
/**
|
|
22
|
+
* mongodb 7.6.0 percent-decodes a socket host once when parsing it and again when it rebuilds
|
|
23
|
+
* the server address, so a path containing `%` cannot be reached as written and is refused.
|
|
24
|
+
*/
|
|
25
|
+
const isSocketPath = (valueArg) => typeof valueArg === 'string' &&
|
|
26
|
+
valueArg.startsWith('/') && valueArg.endsWith('.sock') && Buffer.byteLength(valueArg) <= socketPathMaxBytes &&
|
|
27
|
+
!/[\p{Cc}\p{Cs}%]/u.test(valueArg) &&
|
|
28
|
+
valueArg.split('/').slice(1).every((partArg) => partArg !== '' && partArg !== '.' && partArg !== '..');
|
|
29
|
+
/**
|
|
30
|
+
* The connection-string host of an accepted endpoint, or undefined. The driver reads a
|
|
31
|
+
* percent-encoded host ending in `.sock` as a unix-domain socket path.
|
|
32
|
+
*/
|
|
33
|
+
const connectionHost = (connectionArg) => {
|
|
34
|
+
if (Object.hasOwn(connectionArg, 'socketPath')) {
|
|
35
|
+
return Object.hasOwn(connectionArg, 'host') || Object.hasOwn(connectionArg, 'port') ||
|
|
36
|
+
!isSocketPath(connectionArg.socketPath) ? undefined : encodeURIComponent(connectionArg.socketPath);
|
|
37
|
+
}
|
|
38
|
+
const { host, port } = connectionArg;
|
|
39
|
+
if (typeof host !== 'string' ||
|
|
40
|
+
!(host === 'localhost' || host === '::1' || (plugins.nodeNet.isIP(host) === 4 && host.startsWith('127.'))) ||
|
|
41
|
+
!Number.isSafeInteger(port) || port < 1 || port > 65535)
|
|
42
|
+
return undefined;
|
|
43
|
+
return `${host === 'localhost' ? '127.0.0.1' : host === '::1' ? '[::1]' : host}:${port}`;
|
|
44
|
+
};
|
|
19
45
|
/** Disposable fault injection is available only through the testsupport package subpath. */
|
|
20
46
|
export class SmartdataTestDatabase {
|
|
21
47
|
db;
|
|
@@ -27,34 +53,30 @@ export class SmartdataTestDatabase {
|
|
|
27
53
|
#reconnectForRemoval = false;
|
|
28
54
|
#active;
|
|
29
55
|
#closing;
|
|
30
|
-
constructor(
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const credentials = connectionArg.username === undefined ? ''
|
|
34
|
-
: `${encodeURIComponent(connectionArg.username)}:${encodeURIComponent(connectionArg.password)}@`;
|
|
56
|
+
constructor(hostArg, usernameArg, passwordArg) {
|
|
57
|
+
const credentials = usernameArg === undefined ? ''
|
|
58
|
+
: `${encodeURIComponent(usernameArg)}:${encodeURIComponent(passwordArg)}@`;
|
|
35
59
|
this.#descriptor = Object.freeze({
|
|
36
60
|
mongoDbName: this.#name,
|
|
37
|
-
mongoDbUrl: `mongodb://${credentials}${
|
|
61
|
+
mongoDbUrl: `mongodb://${credentials}${hostArg}/?directConnection=true&authSource=admin`,
|
|
38
62
|
});
|
|
39
63
|
this.db = new SmartdataDb(this.#descriptor);
|
|
40
64
|
}
|
|
41
65
|
static async create(optionsArg) {
|
|
42
66
|
const options = assertDataOptions(optionsArg, ['connection', 'timeoutMs', 'signal']);
|
|
43
|
-
const connection = assertDataOptions(options.connection, ['host', 'port', 'username', 'password']);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
((connection.username === undefined) !== (connection.password === undefined)) ||
|
|
49
|
-
[connection.username, connection.password].some((valueArg) => valueArg !== undefined &&
|
|
67
|
+
const connection = assertDataOptions(options.connection, ['host', 'port', 'socketPath', 'username', 'password']);
|
|
68
|
+
const { username, password } = connection;
|
|
69
|
+
const host = connectionHost(connection);
|
|
70
|
+
if (host === undefined || ((username === undefined) !== (password === undefined)) ||
|
|
71
|
+
[username, password].some((valueArg) => valueArg !== undefined &&
|
|
50
72
|
(typeof valueArg !== 'string' || valueArg.length < 1 || valueArg.length > 1024))) {
|
|
51
|
-
throw new SmartdataPersistenceError('invalid_argument', 'An explicit loopback host
|
|
73
|
+
throw new SmartdataPersistenceError('invalid_argument', 'An explicit loopback host and port or unix socket path, and an optional credential pair, are required.');
|
|
52
74
|
}
|
|
53
75
|
const budget = new SmartdataOperationBudget(options.timeoutMs ?? 5000, options.signal);
|
|
54
76
|
let fixture;
|
|
55
77
|
try {
|
|
56
78
|
budget.check();
|
|
57
|
-
fixture = new SmartdataTestDatabase(
|
|
79
|
+
fixture = new SmartdataTestDatabase(host, username, password);
|
|
58
80
|
await fixture.db.init({ timeoutMs: budget.remainingMs(), signal: budget.signal });
|
|
59
81
|
const databases = await fixture.db.mongoDb.admin().listDatabases({
|
|
60
82
|
filter: { name: fixture.#name }, nameOnly: true, authorizedDatabases: false,
|
|
@@ -247,4 +269,4 @@ export class SmartdataTestDatabase {
|
|
|
247
269
|
this.#owned = false;
|
|
248
270
|
}
|
|
249
271
|
}
|
|
250
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50ZXN0ZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9ub3NxbGRiL2NsYXNzZXMudGVzdGRhdGFiYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHdCQUF3QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFvQzNGLDhGQUE4RjtBQUM5RixNQUFNLE9BQU8sa0NBQW1DLFNBQVEseUJBQXlCO0lBQ3RFLFFBQVEsQ0FBc0I7SUFDdkMsWUFBWSxVQUErQjtRQUN6QyxLQUFLLENBQUMsdUJBQXVCLEVBQUUsNEVBQTRFLENBQUMsQ0FBQztRQUM3RyxJQUFJLENBQUMsSUFBSSxHQUFHLG9DQUFvQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO0lBQzdCLENBQUM7SUFDTSxLQUFLLEtBQW9CLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztDQUMxRDtBQUVELE1BQU0sVUFBVSxHQUFHLEdBQThCLEVBQUUsQ0FBQyxJQUFJLHlCQUF5QixDQUMvRSxrQkFBa0IsRUFBRSxnRkFBZ0YsQ0FDckcsQ0FBQztBQUVGLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxRQUFpQixFQUFFLFdBQW1CLEVBQTRCLEVBQUUsQ0FDbEcsMkJBQTJCLENBQUMsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUVqRSw0RkFBNEY7QUFDNUYsTUFBTSxP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
|
|
272
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50ZXN0ZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9ub3NxbGRiL2NsYXNzZXMudGVzdGRhdGFiYXNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDckUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHdCQUF3QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFtRDNGLDhGQUE4RjtBQUM5RixNQUFNLE9BQU8sa0NBQW1DLFNBQVEseUJBQXlCO0lBQ3RFLFFBQVEsQ0FBc0I7SUFDdkMsWUFBWSxVQUErQjtRQUN6QyxLQUFLLENBQUMsdUJBQXVCLEVBQUUsNEVBQTRFLENBQUMsQ0FBQztRQUM3RyxJQUFJLENBQUMsSUFBSSxHQUFHLG9DQUFvQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxRQUFRLEdBQUcsVUFBVSxDQUFDO0lBQzdCLENBQUM7SUFDTSxLQUFLLEtBQW9CLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztDQUMxRDtBQUVELE1BQU0sVUFBVSxHQUFHLEdBQThCLEVBQUUsQ0FBQyxJQUFJLHlCQUF5QixDQUMvRSxrQkFBa0IsRUFBRSxnRkFBZ0YsQ0FDckcsQ0FBQztBQUVGLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxRQUFpQixFQUFFLFdBQW1CLEVBQTRCLEVBQUUsQ0FDbEcsMkJBQTJCLENBQUMsUUFBUSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUVqRSxzRUFBc0U7QUFDdEUsTUFBTSxr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
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import './shim.js';
|
|
2
2
|
export { SmartdataTestDatabase, SmartdataTestDatabaseCreationError, } from './classes.testdatabase.js';
|
|
3
|
-
export type { ISmartdataTestConnection, ISmartdataTestDatabaseOptions, ISmartdataStoredDocumentFaultOptions, ISmartdataIndexFaultOptions, TSmartdataTestModel, } from './classes.testdatabase.js';
|
|
3
|
+
export type { ISmartdataTestConnection, ISmartdataTestSocketConnection, TSmartdataTestConnection, ISmartdataTestDatabaseOptions, ISmartdataStoredDocumentFaultOptions, ISmartdataIndexFaultOptions, TSmartdataTestModel, } from './classes.testdatabase.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lossless.org/client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.",
|
|
6
6
|
"exports": {
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"@git.zone/tsrun": "3.0.0",
|
|
86
86
|
"@git.zone/tstest": "6.3.0",
|
|
87
87
|
"@lossless.org/nosqldb": "8.0.2",
|
|
88
|
-
"@lossless.org/nosqldb-qualified": "npm:@lossless.org/nosqldb@10.
|
|
88
|
+
"@lossless.org/nosqldb-qualified": "npm:@lossless.org/nosqldb@10.7.0",
|
|
89
89
|
"@lossless.org/objectstorage": "10.3.1",
|
|
90
90
|
"@lossless.org/sqldb": "0.2.3",
|
|
91
91
|
"@push.rocks/qenv": "^6.1.3",
|
package/readme.md
CHANGED
|
@@ -104,6 +104,7 @@ Family imports preserve the established SmartData and SmartBucket names and cons
|
|
|
104
104
|
| Key-value store readiness | `EasyStore.ensureInitialized()` — installs the store's declared index at startup, outside any transaction window, so a first `readKey()`/`writeKey()` needs no index DDL |
|
|
105
105
|
| Client deadlines | `timeoutMS` (1..120000) on every ordinary model read and write, instance `save()`/`saveIf()`/`delete()` included, on every exact call, and `session.withTransaction(callback, { timeoutMS })` for a whole transaction, retries and commit included; expiry rejects with `SmartdataPersistenceError` code `timeout`, and an exact write interrupted in flight with `ambiguous_write` |
|
|
106
106
|
| Cancellation | `signal` on every exact call, `atomicDeleteMany()` and `session.withTransaction(callback, { signal })`, which interrupts the session's operation in flight, rolls the attempt back and never commits after an abort |
|
|
107
|
+
| 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 |
|
|
107
108
|
|
|
108
109
|
`docs/source/smartdata/readme.md` documents each one with its refusals.
|
|
109
110
|
|
|
@@ -118,7 +119,7 @@ A bucket lookup sends one HeadBucket for the named bucket, never ListBuckets, so
|
|
|
118
119
|
|
|
119
120
|
### Document APIs that need a MongoDB backend
|
|
120
121
|
|
|
121
|
-
The document model runs on both NoSQLDB and MongoDB, but
|
|
122
|
+
The document model runs on both NoSQLDB and MongoDB, but several APIs do not mean the same thing on both. The NoSQLDB engine is qualified at 8.0.2 and 10.7.0 (see [Verification](#verification)); the two releases part on the grouped-totals and guarded-`$expr` rows below — 10.7.0 groups composite keys exactly and evaluates the guard, 8.0.2 does neither — on whether a migration can create a partial index or a collection validator at all, and on when a transaction learns of a write conflict.
|
|
122
123
|
|
|
123
124
|
`init()` asks the connected engine what it is with one `buildInfo` command and records the answer on the database as `engineIdentity` (`{ product, version }`). NoSQLDB answers with its own `nosqldb` identity document from 10.3.0 onward; a MongoDB server answers `buildInfo` without one; an engine that refuses the command — NoSQLDB 8.0.2 answers `CommandNotFound` — stays `{ product: 'unknown', version: null }`. The identity is what states `capabilities` on a plain `SmartdataDb`, and an unidentified engine states none at all, so every capability-gated call refuses. `NoSqlConnection` keeps stating the capabilities of its declared backend from construction on.
|
|
124
125
|
|
|
@@ -126,12 +127,14 @@ The document model runs on both NoSQLDB and MongoDB, but four APIs do not mean t
|
|
|
126
127
|
| --- | --- | --- |
|
|
127
128
|
| `getGroupedTotals()` / `getGroupedTotalsPage()` with one `groupBy` field | exact, including `sums` | exact |
|
|
128
129
|
| the same with **two** `groupBy` fields | exact, `sums` included, on an engine that identifies itself as NoSQLDB 10.5.0 or newer: that release evaluates the composite group key per document. Below it the call is refused with `unsupported_operation` naming both fields and the single-field form, because the engine leaves the composite group key unresolved and answers with a single row whose group values are the literal field paths (`'$owner'`) and whose count is the whole filtered collection; the refusal is the guard against that wrong number, not a fix for it | exact |
|
|
129
|
-
| guarded `$expr` atomic filters (`$add`, `$lte`, `$ifNull`) | exact on 10.6.0: the engine evaluates the client's fail-closed compilation (`$cond`, `$let`, `$isNumber`, `$type`), so the guard admits within the limit, refuses beyond it and never matches a stored value that is not a finite number. 8.0.2 rejects the compilation with `invalid argument: $cond` and leaves the document untouched | exact |
|
|
130
|
+
| guarded `$expr` atomic filters (`$add`, `$lte`, `$ifNull`) | exact on 10.6.0 and newer: the engine evaluates the client's fail-closed compilation (`$cond`, `$let`, `$isNumber`, `$type`), so the guard admits within the limit, refuses beyond it and never matches a stored value that is not a finite number. 8.0.2 rejects the compilation with `invalid argument: $cond` and leaves the document untouched | exact |
|
|
130
131
|
| `watch()` change streams | unsupported. `NoSqlConnection` refuses with `unsupported_capability`, and so does a plain `SmartdataDb` whose engine identified itself; against an engine that answers no identity the refusal instead arrives from the engine as `CommandNotFound` once the change stream is read | supported on replica sets |
|
|
131
|
-
| model-declared partial indexes (`partialFilterExpression`) | not expressible: the index-option type rejects it and the runtime refuses it with `invalid_configuration`. A client decision, not an engine limit on every release — 10.6.0
|
|
132
|
+
| model-declared partial indexes (`partialFilterExpression`) | not expressible: the index-option type rejects it and the runtime refuses it with `invalid_configuration`. A client decision, not an engine limit on every release — 10.6.0 and newer create partial indexes, 8.0.2 refuses the option with `InvalidOptions` (72) — because one model declaration has to hold on every qualified backend. A migration may create one on 10.7.0; `toleratedIndexNames` accepts it and inspection reports its filter | not expressible, but a migration may own one; inspection reports its filter |
|
|
133
|
+
| collection validators (`validator`, `validationLevel`, `validationAction`) | no client API; a migration owns a validator through the driver. 10.7.0 creates the collection, lists the options exactly as given and enforces them on every model write: a violating `insert()` or `atomicUpdate()` rejects with the engine's `DocumentValidationFailure` (121) and its `errInfo`, which the client passes through unchanged rather than mapping to a `SmartdataPersistenceError` code, and stores nothing. Models initialize on a validated collection like on any other. 8.0.2 refuses the option with `InvalidOptions` (72) and creates no collection, so a validator is never silently dropped | enforced; not exercised by the client's MongoDB suite |
|
|
134
|
+
| write conflicts between transactions, and writes outside a transaction to a document a transaction holds | 10.7.0 (since 10.6.1) detects a conflict at the statement, as MongoDB does: the first writer wins, and the later transaction's statement rejects with the engine's `WriteConflict` (112) labelled `TransientTransactionError`, which the client passes through so `session.withTransaction()` re-runs that callback. A write outside a transaction waits until the transaction holding its document ends, then applies on top; the wait is bounded by the write's own `timeoutMS` and by the engine's fixed 60-second transaction lifetime, after which a waiting writer aborts the holder. Awaiting such a write inside the holding transaction's callback therefore stalls that transaction until one of the two expires. 8.0.2 detects the conflict at commit: the first transaction to commit wins, a write outside a transaction applies at once, and the transaction that wrote first re-runs. Both writes land on either engine; a callback must be safe to re-run and must not swallow the statement error | first writer wins at the statement and outside writes wait, MongoDB's documented rule; not exercised by the client's MongoDB suite |
|
|
132
135
|
| aggregation-pipeline (array) updates | refused by the client with `invalid_argument` before any backend is contacted. A client-owned refusal, not an engine limit: both qualified engines apply a pipeline update themselves | same client refusal |
|
|
133
136
|
|
|
134
|
-
`test/nosqldb/smartdb/test.engine-capability-boundary.node.ts` asserts the identity, grouped-totals, guarded-`$expr`, partial-index and pipeline-update rows against both qualified engines, so a boundary that moves shows up as a failing suite rather than as a changed number in a consumer. The two halves of the grouped-totals
|
|
137
|
+
`test/nosqldb/smartdb/test.engine-capability-boundary.node.ts` asserts the identity, grouped-totals, guarded-`$expr`, partial-index, collection-validator, write-conflict and pipeline-update rows against both qualified engines, so a boundary that moves shows up as a failing suite rather than as a changed number in a consumer. The two halves of the grouped-totals, guarded-`$expr` and write-conflict rows are separate tests, each bound to the engine that answers it, and the engine's own composite-key answer stays under assertion through the raw `aggregateGroupedTotals()` boundary — one literal row on 8.0.2, the two exact pairs on 10.7.0. The same boundary pins the rest of the engine's `$group` stage: a non-document accumulator is refused with `TypeMismatch` (14) on 10.7.0 while 8.0.2 answers it, and a `$cond` inside a composite key is evaluated per document on 10.7.0 while 8.0.2 answers its single literal row. It also pins whether a migration can create a partial index — 10.7.0 creates it and lists the filter, 8.0.2 refuses with 72 — and a collection validator — 10.7.0 creates and enforces it against model inserts and updates, 8.0.2 refuses with 72 — and which writer a conflict sends back: on 10.7.0 the later transaction fails at its statement and re-runs while a write outside a transaction waits for the holder's commit, on 8.0.2 the later transaction commits first and the holder re-runs. The `watch()` row is the contract refusal `ts/nosqldb/classes.collection.ts` states; the engine suite opens no change stream.
|
|
135
138
|
|
|
136
139
|
## Relational SQL
|
|
137
140
|
|
|
@@ -211,14 +214,14 @@ Qualified engines:
|
|
|
211
214
|
|
|
212
215
|
| Component | Qualified versions |
|
|
213
216
|
| --- | --- |
|
|
214
|
-
| NoSQLDB engine | **8.0.2 and 10.
|
|
217
|
+
| NoSQLDB engine | **8.0.2 and 10.7.0** — the same `test/nosqldb/smartdb/` suite runs against both, through the single engine seam in `test/nosqldb/helpers/smartdb.ts`; `NOSQLDB_ENGINE=qualified` selects 10.7.0 |
|
|
215
218
|
| MongoDB | 8.0.26 replica sets |
|
|
216
219
|
| ObjectStorage | 10.3.1 |
|
|
217
220
|
| SQLDB | 0.2.3 |
|
|
218
221
|
| MariaDB | 11.8 |
|
|
219
222
|
| ClickHouse | 25.8 |
|
|
220
223
|
|
|
221
|
-
Both engine versions run the whole document suite. They part on asserted boundaries — 10.
|
|
224
|
+
Both engine versions run the whole document suite. They part on asserted boundaries — 10.7.0 groups composite keys exactly and answers two-field grouped totals, evaluates guarded `$expr` filters, creates migration-owned partial indexes and collection validators and reports a transaction write conflict at the statement, 8.0.2 does none of these, reports the conflict at commit, and the client refuses the two-field form there — which [Document APIs that need a MongoDB backend](#document-apis-that-need-a-mongodb-backend) states row by row. Text search, the Lucene adapter and the broad read-filter surface are exercised against MongoDB only. `pnpm run test:minio` uses a digest-pinned MinIO image: `sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e`. That MinIO version enforces the tested conditional uploads but does not enforce conditional deletion; its exact-purge capability is correctly unavailable. ObjectStorage passes both live probes. AWS S3 has not been qualified against a live account in this migration; no universal S3 exact-operation guarantee is inferred from the SDK.
|
|
222
225
|
|
|
223
226
|
## License and Legal Information
|
|
224
227
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { SmartDataDbDoc } from './classes.doc.js';
|
|
|
5
5
|
import { SmartdataPersistenceError } from './classes.persistence.js';
|
|
6
6
|
import { assertDataOptions, SmartdataOperationBudget } from './classes.operationbudget.js';
|
|
7
7
|
|
|
8
|
+
/** A loopback TCP engine endpoint. */
|
|
8
9
|
export interface ISmartdataTestConnection {
|
|
9
10
|
/** Literal loopback IPv4, ::1, or localhost (normalized to 127.0.0.1). */
|
|
10
11
|
host: string;
|
|
@@ -14,8 +15,22 @@ export interface ISmartdataTestConnection {
|
|
|
14
15
|
password?: string;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
/** A unix-domain socket engine endpoint. */
|
|
19
|
+
export interface ISmartdataTestSocketConnection {
|
|
20
|
+
/**
|
|
21
|
+
* Absolute canonical path ending in `.sock` (the MongoDB connection-string rule for
|
|
22
|
+
* socket hosts), at most 107 UTF-8 bytes, without control characters, lone surrogates or `%`.
|
|
23
|
+
*/
|
|
24
|
+
socketPath: string;
|
|
25
|
+
/** Supply both credentials or neither. Authentication uses admin. */
|
|
26
|
+
username?: string;
|
|
27
|
+
password?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type TSmartdataTestConnection = ISmartdataTestConnection | ISmartdataTestSocketConnection;
|
|
31
|
+
|
|
17
32
|
export interface ISmartdataTestDatabaseOptions {
|
|
18
|
-
connection:
|
|
33
|
+
connection: TSmartdataTestConnection;
|
|
19
34
|
/** Default 5000; maximum 120000 ms, shared by connection and ownership checks. */
|
|
20
35
|
timeoutMs?: number;
|
|
21
36
|
signal?: AbortSignal;
|
|
@@ -57,6 +72,34 @@ const faultError = (): SmartdataPersistenceError => new SmartdataPersistenceErro
|
|
|
57
72
|
const canonicalFaultDocument = (valueArg: unknown, maxBytesArg: number): plugins.mongodb.Document =>
|
|
58
73
|
snapshotBoundedBsonDocument(valueArg, maxBytesArg, faultError);
|
|
59
74
|
|
|
75
|
+
/** Linux `sun_path` holds 108 bytes including the terminating NUL. */
|
|
76
|
+
const socketPathMaxBytes = 107;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* mongodb 7.6.0 percent-decodes a socket host once when parsing it and again when it rebuilds
|
|
80
|
+
* the server address, so a path containing `%` cannot be reached as written and is refused.
|
|
81
|
+
*/
|
|
82
|
+
const isSocketPath = (valueArg: unknown): valueArg is string => typeof valueArg === 'string' &&
|
|
83
|
+
valueArg.startsWith('/') && valueArg.endsWith('.sock') && Buffer.byteLength(valueArg) <= socketPathMaxBytes &&
|
|
84
|
+
!/[\p{Cc}\p{Cs}%]/u.test(valueArg) &&
|
|
85
|
+
valueArg.split('/').slice(1).every((partArg) => partArg !== '' && partArg !== '.' && partArg !== '..');
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The connection-string host of an accepted endpoint, or undefined. The driver reads a
|
|
89
|
+
* percent-encoded host ending in `.sock` as a unix-domain socket path.
|
|
90
|
+
*/
|
|
91
|
+
const connectionHost = (connectionArg: Record<string, unknown>): string | undefined => {
|
|
92
|
+
if (Object.hasOwn(connectionArg, 'socketPath')) {
|
|
93
|
+
return Object.hasOwn(connectionArg, 'host') || Object.hasOwn(connectionArg, 'port') ||
|
|
94
|
+
!isSocketPath(connectionArg.socketPath) ? undefined : encodeURIComponent(connectionArg.socketPath);
|
|
95
|
+
}
|
|
96
|
+
const { host, port } = connectionArg;
|
|
97
|
+
if (typeof host !== 'string' ||
|
|
98
|
+
!(host === 'localhost' || host === '::1' || (plugins.nodeNet.isIP(host) === 4 && host.startsWith('127.'))) ||
|
|
99
|
+
!Number.isSafeInteger(port) || (port as number) < 1 || (port as number) > 65535) return undefined;
|
|
100
|
+
return `${host === 'localhost' ? '127.0.0.1' : host === '::1' ? '[::1]' : host}:${port}`;
|
|
101
|
+
};
|
|
102
|
+
|
|
60
103
|
/** Disposable fault injection is available only through the testsupport package subpath. */
|
|
61
104
|
export class SmartdataTestDatabase {
|
|
62
105
|
public readonly db: SmartdataDb;
|
|
@@ -69,35 +112,32 @@ export class SmartdataTestDatabase {
|
|
|
69
112
|
#active?: Promise<void>;
|
|
70
113
|
#closing?: Promise<void>;
|
|
71
114
|
|
|
72
|
-
private constructor(
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
const credentials = connectionArg.username === undefined ? ''
|
|
76
|
-
: `${encodeURIComponent(connectionArg.username)}:${encodeURIComponent(connectionArg.password!)}@`;
|
|
115
|
+
private constructor(hostArg: string, usernameArg: string | undefined, passwordArg: string | undefined) {
|
|
116
|
+
const credentials = usernameArg === undefined ? ''
|
|
117
|
+
: `${encodeURIComponent(usernameArg)}:${encodeURIComponent(passwordArg!)}@`;
|
|
77
118
|
this.#descriptor = Object.freeze({
|
|
78
119
|
mongoDbName: this.#name,
|
|
79
|
-
mongoDbUrl: `mongodb://${credentials}${
|
|
120
|
+
mongoDbUrl: `mongodb://${credentials}${hostArg}/?directConnection=true&authSource=admin`,
|
|
80
121
|
});
|
|
81
122
|
this.db = new SmartdataDb(this.#descriptor);
|
|
82
123
|
}
|
|
83
124
|
|
|
84
125
|
public static async create(optionsArg: ISmartdataTestDatabaseOptions): Promise<SmartdataTestDatabase> {
|
|
85
126
|
const options = assertDataOptions(optionsArg, ['connection', 'timeoutMs', 'signal']);
|
|
86
|
-
const connection = assertDataOptions(options.connection, ['host', 'port', 'username', 'password']);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
((connection.username === undefined) !== (connection.password === undefined)) ||
|
|
92
|
-
[connection.username, connection.password].some((valueArg) => valueArg !== undefined &&
|
|
127
|
+
const connection = assertDataOptions(options.connection, ['host', 'port', 'socketPath', 'username', 'password']);
|
|
128
|
+
const { username, password } = connection;
|
|
129
|
+
const host = connectionHost(connection);
|
|
130
|
+
if (host === undefined || ((username === undefined) !== (password === undefined)) ||
|
|
131
|
+
[username, password].some((valueArg) => valueArg !== undefined &&
|
|
93
132
|
(typeof valueArg !== 'string' || valueArg.length < 1 || valueArg.length > 1024))) {
|
|
94
|
-
throw new SmartdataPersistenceError('invalid_argument',
|
|
133
|
+
throw new SmartdataPersistenceError('invalid_argument',
|
|
134
|
+
'An explicit loopback host and port or unix socket path, and an optional credential pair, are required.');
|
|
95
135
|
}
|
|
96
136
|
const budget = new SmartdataOperationBudget(options.timeoutMs ?? 5000, options.signal);
|
|
97
137
|
let fixture: SmartdataTestDatabase | undefined;
|
|
98
138
|
try {
|
|
99
139
|
budget.check();
|
|
100
|
-
fixture = new SmartdataTestDatabase(
|
|
140
|
+
fixture = new SmartdataTestDatabase(host, username as string | undefined, password as string | undefined);
|
|
101
141
|
await fixture.db.init({ timeoutMs: budget.remainingMs(), signal: budget.signal });
|
|
102
142
|
const databases = await fixture.db.mongoDb.admin().listDatabases({
|
|
103
143
|
filter: { name: fixture.#name }, nameOnly: true, authorizedDatabases: false,
|