@lossless.org/client 1.5.0 → 1.6.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.collection.d.ts +2 -0
- package/dist_ts/nosqldb/classes.collection.js +5 -2
- package/dist_ts/nosqldb/classes.collectiontopology.d.ts +9 -0
- package/dist_ts/nosqldb/classes.collectiontopology.js +46 -2
- package/dist_ts/nosqldb/classes.db.d.ts +30 -2
- package/dist_ts/nosqldb/classes.db.js +1 -1
- package/dist_ts/nosqldb/classes.doc.d.ts +8 -4
- package/dist_ts/nosqldb/classes.doc.js +7 -3
- package/package.json +7 -7
- package/readme.md +9 -6
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/nosqldb/classes.collection.ts +6 -0
- package/ts/nosqldb/classes.collectiontopology.ts +61 -1
- package/ts/nosqldb/classes.db.ts +32 -5
- package/ts/nosqldb/classes.doc.ts +8 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lossless.org/client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "One typed client for NoSQLDB, MongoDB, SQLDB, MariaDB, ClickHouse and S3 object storage.",
|
|
6
6
|
"exports": {
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"@push.rocks/smartstring": "^4.1.0",
|
|
58
58
|
"@push.rocks/smarttime": "^4.2.3",
|
|
59
59
|
"@push.rocks/smartunique": "^3.0.9",
|
|
60
|
-
"@push.rocks/taskbuffer": "^
|
|
60
|
+
"@push.rocks/taskbuffer": "^9.0.3",
|
|
61
61
|
"@tsclass/tsclass": "^9.5.1",
|
|
62
62
|
"minimatch": "^10.2.5",
|
|
63
63
|
"mongodb": "^7.2.0"
|
|
@@ -81,15 +81,15 @@
|
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@aws-sdk/client-s3": "^3.1039.0",
|
|
83
83
|
"@clickhouse/client": "1.23.1",
|
|
84
|
-
"@git.zone/tsbuild": "
|
|
85
|
-
"@git.zone/tsrun": "
|
|
86
|
-
"@git.zone/tstest": "6.
|
|
84
|
+
"@git.zone/tsbuild": "5.0.0",
|
|
85
|
+
"@git.zone/tsrun": "3.0.0",
|
|
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.6.0",
|
|
89
89
|
"@lossless.org/objectstorage": "10.1.0",
|
|
90
90
|
"@lossless.org/sqldb": "0.2.3",
|
|
91
91
|
"@push.rocks/qenv": "^6.1.3",
|
|
92
|
-
"@types/node": "26.
|
|
92
|
+
"@types/node": "26.6.1",
|
|
93
93
|
"mariadb": "3.5.4",
|
|
94
94
|
"mongodb-memory-server": "11.1.0"
|
|
95
95
|
},
|
package/readme.md
CHANGED
|
@@ -91,6 +91,8 @@ Family imports preserve the established SmartData and SmartBucket names and cons
|
|
|
91
91
|
| Identities on a migrated unique index | `@unI({ indexName })` names the index that backs the identity instead of `<field>_1` |
|
|
92
92
|
| Typed `null` predicates | read and atomic filters accept `null` for a field declared optional, so a value stored as an explicit null stays addressable |
|
|
93
93
|
| Owned sessions on cursors | `getCursor()` takes the handle from `db.createSession()` and keeps it leased until the cursor is closed |
|
|
94
|
+
| Owned sessions on instance writes | `instance.save({ session })` and `instance.delete({ session })` take the handle from `db.createSession()`, leased for the one write like every other model API |
|
|
95
|
+
| Typed connection pool options | `new SmartdataDb(options: ISmartdataDbOptions)` types `maxPoolSize`, `maxIdleTimeMS`, `serverSelectionTimeoutMS` and `socketTimeoutMS` beside the descriptor fields, so no cast through `IMongoDescriptor` is needed |
|
|
94
96
|
| Named plural selectors | a non-empty `$in` anchors `atomicUpdateMany()`, `atomicDeleteMany()` and `atomicUpsertMany()`; singular operations are unchanged |
|
|
95
97
|
| Fields only atomic writes may update | `@svDb({ atomicOnly: true })` and `atomicOnlyFields` — seeded by every write that creates the document, never overwritten by a later `save()` |
|
|
96
98
|
| Defaults inside `$expr` | `{ $ifNull: ['$field', literal] }` operands, so a guard covers rows written before the field existed |
|
|
@@ -98,13 +100,14 @@ Family imports preserve the established SmartData and SmartBucket names and cons
|
|
|
98
100
|
| Identity rotation | `Model.atomicFindOneAndReplace(filter, replacement, opts?)` — the one write that moves an `@unI()` identity, under the matched document's `_id` |
|
|
99
101
|
| Fail-fast on unprepared collections | a session-carrying call inside a transaction refuses instead of stalling on lazy index DDL until the client deadline |
|
|
100
102
|
| Migration-owned indexes | `toleratedIndexNames` on the model — named undeclared indexes are observed, never created, dropped or verified, and no longer make the topology divergent |
|
|
103
|
+
| Partial index filters in inspection | `inspectNamespace()`, `inspectCollectionTopology()` and `getIndexInfo()` report a partial index's `partialFilterExpression` exactly as the backend lists it, as a frozen snapshot present only on a partial index |
|
|
101
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 |
|
|
102
105
|
|
|
103
106
|
`docs/source/smartdata/readme.md` documents each one with its refusals.
|
|
104
107
|
|
|
105
108
|
### Document APIs that need a MongoDB backend
|
|
106
109
|
|
|
107
|
-
The document model runs on both NoSQLDB and MongoDB, but four APIs do not mean the same thing on both. The NoSQLDB engine is qualified at 8.0.2 and 10.
|
|
110
|
+
The document model runs on both NoSQLDB and MongoDB, but four APIs do not mean the same thing on both. The NoSQLDB engine is qualified at 8.0.2 and 10.6.0 (see [Verification](#verification)); the two releases part on the grouped-totals and guarded-`$expr` rows below — 10.6.0 groups composite keys exactly and evaluates the guard, 8.0.2 does neither — and on whether a migration can create a partial index at all.
|
|
108
111
|
|
|
109
112
|
`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.
|
|
110
113
|
|
|
@@ -112,12 +115,12 @@ The document model runs on both NoSQLDB and MongoDB, but four APIs do not mean t
|
|
|
112
115
|
| --- | --- | --- |
|
|
113
116
|
| `getGroupedTotals()` / `getGroupedTotalsPage()` with one `groupBy` field | exact, including `sums` | exact |
|
|
114
117
|
| 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 |
|
|
115
|
-
| guarded `$expr` atomic filters (`$add`, `$lte`, `$ifNull`) |
|
|
118
|
+
| 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 |
|
|
116
119
|
| `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 |
|
|
117
|
-
| model-declared partial indexes (`partialFilterExpression`) | not expressible: the index-option type rejects it and the runtime refuses it with `invalid_configuration
|
|
120
|
+
| 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 creates 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.6.0; `toleratedIndexNames` accepts it and inspection reports its filter | not expressible, but a migration may own one; inspection reports its filter |
|
|
118
121
|
| 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 |
|
|
119
122
|
|
|
120
|
-
`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
|
|
123
|
+
`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 and guarded-`$expr` 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.6.0. The same boundary pins the rest of the engine's `$group` stage: a non-document accumulator is refused with `TypeMismatch` (14) on 10.6.0 while 8.0.2 answers it, and a `$cond` inside a composite key is evaluated per document on 10.6.0 while 8.0.2 answers its single literal row. It also pins whether a migration can create a partial index — 10.6.0 creates it and lists the filter, 8.0.2 refuses with 72. The `watch()` row is the contract refusal `ts/nosqldb/classes.collection.ts` states; the engine suite opens no change stream.
|
|
121
124
|
|
|
122
125
|
## Relational SQL
|
|
123
126
|
|
|
@@ -197,14 +200,14 @@ Qualified engines:
|
|
|
197
200
|
|
|
198
201
|
| Component | Qualified versions |
|
|
199
202
|
| --- | --- |
|
|
200
|
-
| NoSQLDB engine | **8.0.2 and 10.
|
|
203
|
+
| NoSQLDB engine | **8.0.2 and 10.6.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.6.0 |
|
|
201
204
|
| MongoDB | 8.0.26 replica sets |
|
|
202
205
|
| ObjectStorage | 10.1.0 |
|
|
203
206
|
| SQLDB | 0.2.3 |
|
|
204
207
|
| MariaDB | 11.8 |
|
|
205
208
|
| ClickHouse | 25.8 |
|
|
206
209
|
|
|
207
|
-
Both engine versions run the whole document suite. They part on
|
|
210
|
+
Both engine versions run the whole document suite. They part on asserted boundaries — 10.6.0 groups composite keys exactly and answers two-field grouped totals, evaluates guarded `$expr` filters and creates migration-owned partial indexes, 8.0.2 does none of these 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.
|
|
208
211
|
|
|
209
212
|
## License and Legal Information
|
|
210
213
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
getExpectedCollectionTopologyForSchema,
|
|
40
40
|
getIdentityIndexName,
|
|
41
41
|
isIdentityIndexFor,
|
|
42
|
+
isPlainIndexDocument,
|
|
42
43
|
compareSmartdataTopologyStrings,
|
|
43
44
|
} from './classes.collectiontopology.js';
|
|
44
45
|
|
|
@@ -210,6 +211,8 @@ export interface ISmartdataIndexInfo {
|
|
|
210
211
|
unique: boolean;
|
|
211
212
|
sparse: boolean;
|
|
212
213
|
expireAfterSeconds?: number;
|
|
214
|
+
/** The filter of a partial index exactly as the backend lists it; absent otherwise. */
|
|
215
|
+
partialFilterExpression?: Record<string, unknown>;
|
|
213
216
|
}
|
|
214
217
|
interface ISmartdataDecoratorMetadata {
|
|
215
218
|
globalSaveableProperties?: string[];
|
|
@@ -2814,6 +2817,9 @@ export class SmartdataCollection<T> {
|
|
|
2814
2817
|
typeof indexArg.expireAfterSeconds === 'number'
|
|
2815
2818
|
? indexArg.expireAfterSeconds
|
|
2816
2819
|
: undefined,
|
|
2820
|
+
...(isPlainIndexDocument(indexArg.partialFilterExpression)
|
|
2821
|
+
? { partialFilterExpression: indexArg.partialFilterExpression }
|
|
2822
|
+
: {}),
|
|
2817
2823
|
};
|
|
2818
2824
|
});
|
|
2819
2825
|
}
|
|
@@ -33,6 +33,13 @@ export interface ISmartdataCollectionTopologyIndex {
|
|
|
33
33
|
readonly unique: boolean;
|
|
34
34
|
readonly sparse: boolean;
|
|
35
35
|
readonly expireAfterSeconds: number | null;
|
|
36
|
+
/**
|
|
37
|
+
* The filter of a partial index exactly as the backend lists it, present
|
|
38
|
+
* only on a partial index. Plain documents and arrays inside it are frozen
|
|
39
|
+
* copies; BSON values keep the type the driver decoded. A model never
|
|
40
|
+
* declares one, so an expected index never carries it.
|
|
41
|
+
*/
|
|
42
|
+
readonly partialFilterExpression?: Readonly<Record<string, unknown>>;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
export interface ISmartdataExpectedCollectionTopology {
|
|
@@ -110,6 +117,7 @@ const ordinaryActualIndexKeys = new Set([
|
|
|
110
117
|
'unique',
|
|
111
118
|
'sparse',
|
|
112
119
|
'expireAfterSeconds',
|
|
120
|
+
'partialFilterExpression',
|
|
113
121
|
]);
|
|
114
122
|
const textActualIndexKeys = new Set([
|
|
115
123
|
...ordinaryActualIndexKeys,
|
|
@@ -141,6 +149,37 @@ export const compareSmartdataTopologyStrings = (
|
|
|
141
149
|
return leftCodePoints.length < rightCodePoints.length ? -1 : 1;
|
|
142
150
|
};
|
|
143
151
|
|
|
152
|
+
/** @internal Whether a listed index property is a plain BSON document. */
|
|
153
|
+
export const isPlainIndexDocument = (
|
|
154
|
+
valueArg: unknown,
|
|
155
|
+
): valueArg is Record<string, unknown> => {
|
|
156
|
+
if (typeof valueArg !== 'object' || valueArg === null || Array.isArray(valueArg)) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
const prototype = Object.getPrototypeOf(valueArg);
|
|
160
|
+
return prototype === Object.prototype || prototype === null;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Copies and freezes the documents and arrays of a listed index filter, so the
|
|
165
|
+
* reported filter is exactly what the backend listed and nobody can edit it
|
|
166
|
+
* afterwards. BSON values — ObjectIds, dates, decimals — are returned as the
|
|
167
|
+
* driver decoded them.
|
|
168
|
+
*/
|
|
169
|
+
const snapshotIndexFilterValue = (valueArg: unknown): unknown => {
|
|
170
|
+
if (Array.isArray(valueArg)) {
|
|
171
|
+
return Object.freeze(valueArg.map((entryArg) => snapshotIndexFilterValue(entryArg)));
|
|
172
|
+
}
|
|
173
|
+
if (isPlainIndexDocument(valueArg)) {
|
|
174
|
+
const copy: Record<string, unknown> = {};
|
|
175
|
+
for (const [key, entry] of Object.entries(valueArg)) {
|
|
176
|
+
copy[key] = snapshotIndexFilterValue(entry);
|
|
177
|
+
}
|
|
178
|
+
return Object.freeze(copy);
|
|
179
|
+
}
|
|
180
|
+
return valueArg;
|
|
181
|
+
};
|
|
182
|
+
|
|
144
183
|
function freezeIndex(
|
|
145
184
|
indexArg: {
|
|
146
185
|
name: string;
|
|
@@ -152,6 +191,7 @@ function freezeIndex(
|
|
|
152
191
|
unique: boolean;
|
|
153
192
|
sparse: boolean;
|
|
154
193
|
expireAfterSeconds: number | null;
|
|
194
|
+
partialFilterExpression?: Readonly<Record<string, unknown>>;
|
|
155
195
|
},
|
|
156
196
|
): ISmartdataCollectionTopologyIndex {
|
|
157
197
|
return Object.freeze({
|
|
@@ -162,6 +202,15 @@ function freezeIndex(
|
|
|
162
202
|
unique: indexArg.unique,
|
|
163
203
|
sparse: indexArg.sparse,
|
|
164
204
|
expireAfterSeconds: indexArg.expireAfterSeconds,
|
|
205
|
+
// Absent rather than null on an ordinary index, so every index that is
|
|
206
|
+
// not partial reads exactly as it did before filters were reported.
|
|
207
|
+
...(indexArg.partialFilterExpression === undefined
|
|
208
|
+
? {}
|
|
209
|
+
: {
|
|
210
|
+
partialFilterExpression: snapshotIndexFilterValue(
|
|
211
|
+
indexArg.partialFilterExpression,
|
|
212
|
+
) as Readonly<Record<string, unknown>>,
|
|
213
|
+
}),
|
|
165
214
|
});
|
|
166
215
|
}
|
|
167
216
|
|
|
@@ -390,6 +439,13 @@ const normalizeActualIndex = (
|
|
|
390
439
|
if (rawIndex.sparse !== undefined && typeof rawIndex.sparse !== 'boolean') {
|
|
391
440
|
supported = false;
|
|
392
441
|
}
|
|
442
|
+
const partialFilterExpression = rawIndex.partialFilterExpression;
|
|
443
|
+
if (
|
|
444
|
+
partialFilterExpression !== undefined &&
|
|
445
|
+
!isPlainIndexDocument(partialFilterExpression)
|
|
446
|
+
) {
|
|
447
|
+
supported = false;
|
|
448
|
+
}
|
|
393
449
|
const expireAfterSeconds = rawIndex.expireAfterSeconds;
|
|
394
450
|
if (
|
|
395
451
|
expireAfterSeconds !== undefined &&
|
|
@@ -495,6 +551,9 @@ const normalizeActualIndex = (
|
|
|
495
551
|
expireAfterSeconds >= 0
|
|
496
552
|
? expireAfterSeconds
|
|
497
553
|
: null,
|
|
554
|
+
...(isPlainIndexDocument(partialFilterExpression)
|
|
555
|
+
? { partialFilterExpression }
|
|
556
|
+
: {}),
|
|
498
557
|
});
|
|
499
558
|
if (
|
|
500
559
|
name === '_id_' &&
|
|
@@ -504,7 +563,8 @@ const normalizeActualIndex = (
|
|
|
504
563
|
normalized.keys[0].weight === null &&
|
|
505
564
|
(rawIndex.unique === undefined || rawIndex.unique === true) &&
|
|
506
565
|
normalized.sparse === false &&
|
|
507
|
-
normalized.expireAfterSeconds === null
|
|
566
|
+
normalized.expireAfterSeconds === null &&
|
|
567
|
+
normalized.partialFilterExpression === undefined
|
|
508
568
|
) {
|
|
509
569
|
normalized = fixedIdIndex;
|
|
510
570
|
}
|
package/ts/nosqldb/classes.db.ts
CHANGED
|
@@ -37,6 +37,35 @@ import type { ICapabilities } from '../core/interfaces.js';
|
|
|
37
37
|
*/
|
|
38
38
|
export type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed';
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* How a `SmartdataDb` connects. The first four fields locate and authenticate
|
|
42
|
+
* the database — the same shape as `IMongoDescriptor`, so every descriptor is
|
|
43
|
+
* valid options — and the pool fields tune the driver's connection pool.
|
|
44
|
+
*/
|
|
45
|
+
export interface ISmartdataDbOptions {
|
|
46
|
+
/**
|
|
47
|
+
* The connection URL. `<USERNAME>`/`<USER>`, `<PASSWORD>` and `<DBNAME>`
|
|
48
|
+
* (upper or lower case) are replaced with the URL-encoded `mongoDbUser`,
|
|
49
|
+
* `mongoDbPass` and `mongoDbName`.
|
|
50
|
+
*/
|
|
51
|
+
mongoDbUrl: string;
|
|
52
|
+
/** The database to use. */
|
|
53
|
+
mongoDbName?: string;
|
|
54
|
+
mongoDbUser?: string;
|
|
55
|
+
mongoDbPass?: string;
|
|
56
|
+
/** Upper bound of pooled connections per server. Default 100. */
|
|
57
|
+
maxPoolSize?: number;
|
|
58
|
+
/** Milliseconds an idle pooled connection is kept before it is closed. Default 300000. */
|
|
59
|
+
maxIdleTimeMS?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Milliseconds to wait for a suitable server. Default 30000. A bounded
|
|
62
|
+
* `init({ timeoutMs })` replaces it with the remaining init budget.
|
|
63
|
+
*/
|
|
64
|
+
serverSelectionTimeoutMS?: number;
|
|
65
|
+
/** Milliseconds a socket may stay inactive before it is closed. Default 30000. */
|
|
66
|
+
socketTimeoutMS?: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
40
69
|
export interface ISmartdataReadinessOptions {
|
|
41
70
|
timeoutMs?: number;
|
|
42
71
|
signal?: AbortSignal;
|
|
@@ -138,7 +167,7 @@ const assertExactDataObject = (
|
|
|
138
167
|
};
|
|
139
168
|
|
|
140
169
|
export class SmartdataDb {
|
|
141
|
-
smartdataOptions:
|
|
170
|
+
smartdataOptions: ISmartdataDbOptions;
|
|
142
171
|
mongoDbClient!: plugins.mongodb.MongoClient;
|
|
143
172
|
mongoDb!: plugins.mongodb.Db;
|
|
144
173
|
status: TConnectionStatus;
|
|
@@ -151,7 +180,7 @@ export class SmartdataDb {
|
|
|
151
180
|
private engineIdentityState: ISmartdataEngineIdentity = unidentifiedSmartdataEngine;
|
|
152
181
|
private capabilitiesState: ICapabilities | undefined;
|
|
153
182
|
|
|
154
|
-
constructor(smartdataOptions:
|
|
183
|
+
constructor(smartdataOptions: ISmartdataDbOptions) {
|
|
155
184
|
this.smartdataOptions = smartdataOptions;
|
|
156
185
|
this.status = 'initial';
|
|
157
186
|
void this.statusConnectedDeferred.promise.catch(() => {});
|
|
@@ -219,9 +248,7 @@ export class SmartdataDb {
|
|
|
219
248
|
.replace('<DBNAME>', this.smartdataOptions.mongoDbName || '')
|
|
220
249
|
.replace('<dbname>', this.smartdataOptions.mongoDbName || '');
|
|
221
250
|
|
|
222
|
-
const descriptor = this.smartdataOptions
|
|
223
|
-
Pick<plugins.mongodb.MongoClientOptions, 'maxPoolSize' | 'maxIdleTimeMS' |
|
|
224
|
-
'serverSelectionTimeoutMS' | 'socketTimeoutMS'>;
|
|
251
|
+
const descriptor = this.smartdataOptions;
|
|
225
252
|
const clientOptions: plugins.mongodb.MongoClientOptions = {
|
|
226
253
|
maxPoolSize: descriptor.maxPoolSize ?? 100,
|
|
227
254
|
maxIdleTimeMS: descriptor.maxIdleTimeMS ?? 300000,
|
|
@@ -5774,9 +5774,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5774
5774
|
}
|
|
5775
5775
|
|
|
5776
5776
|
/**
|
|
5777
|
-
*
|
|
5777
|
+
* Saves this instance, optionally within a transaction. `session` takes the
|
|
5778
|
+
* handle from `db.createSession()` — leased for the one write, like every
|
|
5779
|
+
* other model API — or a raw driver session.
|
|
5778
5780
|
*/
|
|
5779
|
-
public async save(opts?: { session?:
|
|
5781
|
+
public async save(opts?: { session?: TSmartdataOrdinarySession }) {
|
|
5780
5782
|
if (getOrdinaryPersistencePolicy(this.constructor)) {
|
|
5781
5783
|
throw new SmartdataPersistenceError('unsupported_operation',
|
|
5782
5784
|
'Validated ordinary models use insert() or transactional postimage updates.');
|
|
@@ -5980,9 +5982,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5980
5982
|
}
|
|
5981
5983
|
|
|
5982
5984
|
/**
|
|
5983
|
-
*
|
|
5985
|
+
* Deletes this instance's document, optionally within a transaction.
|
|
5986
|
+
* `session` takes the handle from `db.createSession()` — leased for the one
|
|
5987
|
+
* write, like every other model API — or a raw driver session.
|
|
5984
5988
|
*/
|
|
5985
|
-
public async delete(opts?: { session?:
|
|
5989
|
+
public async delete(opts?: { session?: TSmartdataOrdinarySession }) {
|
|
5986
5990
|
const exactPersistencePolicy = (this.constructor as any)[
|
|
5987
5991
|
exactPersistencePolicySymbol
|
|
5988
5992
|
] as { forbiddenDelete?: () => Promise<never> } | undefined;
|