@atscript/db-mongo 0.1.154 → 0.1.155
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/index.cjs +73 -9
- package/dist/index.d.cts +18 -3
- package/dist/index.d.mts +18 -3
- package/dist/index.mjs +73 -9
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -162,11 +162,14 @@ var CollectionPatcher = class {
|
|
|
162
162
|
this.currentSetStage = { $set: { [key]: val } };
|
|
163
163
|
this.updatePipeline.push(this.currentSetStage);
|
|
164
164
|
}
|
|
165
|
-
/**
|
|
166
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Set a leaf, lifting an `$inc`/`$mul` field op into an aggregation expression if present.
|
|
167
|
+
* `type`: the field's type, when known.
|
|
168
|
+
*/
|
|
169
|
+
_setLeaf(key, value, type) {
|
|
167
170
|
const fieldOp = (0, _atscript_db.getDbFieldOp)(value);
|
|
168
171
|
if (fieldOp) this._set(key, this._fieldOpExpr(key, fieldOp.op, fieldOp.value));
|
|
169
|
-
else if (containsAggregationExpr(value)) this._set(key, { $literal: value });
|
|
172
|
+
else if (containsAggregationExpr(value) || replacesWhole(value, type)) this._set(key, { $literal: value });
|
|
170
173
|
else this._set(key, value);
|
|
171
174
|
}
|
|
172
175
|
/**
|
|
@@ -187,7 +190,7 @@ var CollectionPatcher = class {
|
|
|
187
190
|
if (isObjectValue && topLevelArray && !flatType?.metadata?.has("db.json")) this.parseArrayPatch(key, value, flatType);
|
|
188
191
|
else if (isObjectValue && flatType?.metadata?.get("db.patch.strategy") === "merge") this.flattenPayload(value, key);
|
|
189
192
|
else if (isObjectValue && flatType?.type.kind === "object" && !flatType.metadata?.has("db.json")) this._flattenReplaceObject(value, key, flatType);
|
|
190
|
-
else if (key !== "_id") this._setLeaf(key, value);
|
|
193
|
+
else if (key !== "_id") this._setLeaf(key, value, flatType);
|
|
191
194
|
}
|
|
192
195
|
return this.updatePipeline;
|
|
193
196
|
}
|
|
@@ -213,7 +216,7 @@ var CollectionPatcher = class {
|
|
|
213
216
|
else this._flattenReplaceObject(childValue, childKey, propType);
|
|
214
217
|
continue;
|
|
215
218
|
}
|
|
216
|
-
this._setLeaf(childKey, childValue);
|
|
219
|
+
this._setLeaf(childKey, childValue, propType);
|
|
217
220
|
}
|
|
218
221
|
}
|
|
219
222
|
/**
|
|
@@ -361,6 +364,16 @@ var CollectionPatcher = class {
|
|
|
361
364
|
else this._set(key, { $setDifference: [{ $ifNull: [`$${key}`, []] }, input] });
|
|
362
365
|
}
|
|
363
366
|
};
|
|
367
|
+
/**
|
|
368
|
+
* Whether a plain-object patch value replaces the stored object instead of
|
|
369
|
+
* merging into it: a `@db.json` object, or a union of objects / `T | null`
|
|
370
|
+
* whose member may switch (since 0.1.155). A field the patcher cannot type
|
|
371
|
+
* (e.g. under a `@db.column` name) keeps the merge.
|
|
372
|
+
*/
|
|
373
|
+
function replacesWhole(value, type) {
|
|
374
|
+
if (!type || !(0, _atscript_db.isPlainObject)(value)) return false;
|
|
375
|
+
return type.metadata?.has("db.json") || type.type.kind === "union";
|
|
376
|
+
}
|
|
364
377
|
//#endregion
|
|
365
378
|
//#region src/lib/mongo-types.ts
|
|
366
379
|
const INDEX_PREFIX = "atscript__";
|
|
@@ -1624,6 +1637,30 @@ async function hasRowsImpl(host, tableName) {
|
|
|
1624
1637
|
...host._getSessionOpts()
|
|
1625
1638
|
}) !== null;
|
|
1626
1639
|
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Documents `fields` cannot identify (see `BaseDbAdapter.countKeyViolations`):
|
|
1642
|
+
* those missing one of them or holding `null`, plus every document sharing
|
|
1643
|
+
* its values with another — one `$facet` aggregation.
|
|
1644
|
+
*/
|
|
1645
|
+
async function countKeyViolationsImpl(host, fields, tableName) {
|
|
1646
|
+
const key = Object.fromEntries(fields.map((f, i) => [`k${i}`, `$${f}`]));
|
|
1647
|
+
const [result] = await host.db.collection(tableName ?? host.resolveTableName(false)).aggregate([{ $facet: {
|
|
1648
|
+
nulls: [{ $match: { $or: fields.map((f) => ({ [f]: null })) } }, { $count: "n" }],
|
|
1649
|
+
dups: [
|
|
1650
|
+
{ $match: { $and: fields.map((f) => ({ [f]: { $ne: null } })) } },
|
|
1651
|
+
{ $group: {
|
|
1652
|
+
_id: key,
|
|
1653
|
+
n: { $sum: 1 }
|
|
1654
|
+
} },
|
|
1655
|
+
{ $match: { n: { $gt: 1 } } },
|
|
1656
|
+
{ $group: {
|
|
1657
|
+
_id: null,
|
|
1658
|
+
n: { $sum: "$n" }
|
|
1659
|
+
} }
|
|
1660
|
+
]
|
|
1661
|
+
} }], host._getSessionOpts()).toArray();
|
|
1662
|
+
return (result?.nulls[0]?.n ?? 0) + (result?.dups[0]?.n ?? 0);
|
|
1663
|
+
}
|
|
1627
1664
|
/** Kind of the object stored under `name` (`listCollections` reports views as `"view"`). */
|
|
1628
1665
|
async function getObjectKindImpl(host, name) {
|
|
1629
1666
|
const type = (await host.db.listCollections({ name }, { nameOnly: true }).toArray())[0]?.type;
|
|
@@ -2154,6 +2191,8 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2154
2191
|
_hasExplicitId = false;
|
|
2155
2192
|
/** Unique fields accumulated during onFieldScanned, returned via getMetadataOverrides. */
|
|
2156
2193
|
_pendingUniqueFields = [];
|
|
2194
|
+
/** {@link _patcherFlatMap}'s memo. */
|
|
2195
|
+
_patcherFlatMapMemo;
|
|
2157
2196
|
constructor(db, client, options = {}) {
|
|
2158
2197
|
super();
|
|
2159
2198
|
this.db = db;
|
|
@@ -2439,11 +2478,32 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2439
2478
|
/** Returns the context object used by CollectionPatcher. */
|
|
2440
2479
|
getPatcherContext() {
|
|
2441
2480
|
return {
|
|
2442
|
-
flatMap: this.
|
|
2481
|
+
flatMap: this._patcherFlatMap(),
|
|
2443
2482
|
prepareId: (id) => this.prepareIdFromIdType(id),
|
|
2444
2483
|
createValidator: (opts) => this._table.createValidator(opts)
|
|
2445
2484
|
};
|
|
2446
2485
|
}
|
|
2486
|
+
/**
|
|
2487
|
+
* The table's flat map keyed by document path: a patch reaches the patcher
|
|
2488
|
+
* with `@db.column` names already applied (`translatePatchKeys`), so a
|
|
2489
|
+
* renamed union / `@db.json` field is found — and replaced, not merged —
|
|
2490
|
+
* under its stored name. Derived fields are left out (they map to their
|
|
2491
|
+
* source's path). Built once per flat map.
|
|
2492
|
+
*/
|
|
2493
|
+
_patcherFlatMap() {
|
|
2494
|
+
const src = this._table.flatMap;
|
|
2495
|
+
let memo = this._patcherFlatMapMemo;
|
|
2496
|
+
if (memo?.src !== src) {
|
|
2497
|
+
const meta = this._table.getMetadata();
|
|
2498
|
+
const map = /* @__PURE__ */ new Map();
|
|
2499
|
+
for (const [path, type] of src) if (!meta.derivedFields.has(path)) map.set(meta.documentPath(path), type);
|
|
2500
|
+
memo = this._patcherFlatMapMemo = {
|
|
2501
|
+
src,
|
|
2502
|
+
map
|
|
2503
|
+
};
|
|
2504
|
+
}
|
|
2505
|
+
return memo.map;
|
|
2506
|
+
}
|
|
2447
2507
|
async nativePatch(filter, patch, ops, expectedVersion, opts) {
|
|
2448
2508
|
const mongoFilter = await this._buildCasFilter(filter, expectedVersion, "nativePatch");
|
|
2449
2509
|
if (!mongoFilter) return {
|
|
@@ -2487,7 +2547,7 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2487
2547
|
}
|
|
2488
2548
|
onFieldScanned(field, _type, metadata) {
|
|
2489
2549
|
if (field === "_id") this._hasExplicitId = true;
|
|
2490
|
-
if (field !== "_id" && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2550
|
+
if (field !== "_id" && !field.includes(".") && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2491
2551
|
for (const index of metadata.get("db.mongo.search.text") || []) this._pendingSearchFields.push({
|
|
2492
2552
|
indexName: index.indexName,
|
|
2493
2553
|
field,
|
|
@@ -3101,10 +3161,14 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
3101
3161
|
async getObjectKind(name) {
|
|
3102
3162
|
return getObjectKindImpl(this, name);
|
|
3103
3163
|
}
|
|
3164
|
+
async countKeyViolations(fields, tableName) {
|
|
3165
|
+
return countKeyViolationsImpl(this, fields, tableName);
|
|
3166
|
+
}
|
|
3104
3167
|
/**
|
|
3105
3168
|
* No physical primary key on MongoDB (`_id` is fixed): a `@meta.id` move is
|
|
3106
|
-
* an index change that `syncIndexes` reconciles.
|
|
3107
|
-
*
|
|
3169
|
+
* an index change that `syncIndexes` reconciles. Like on the other adapters,
|
|
3170
|
+
* schema sync refuses it on a populated collection whose documents do not
|
|
3171
|
+
* satisfy the new key.
|
|
3108
3172
|
*/
|
|
3109
3173
|
async rebuildPrimaryKey(_change) {}
|
|
3110
3174
|
async syncIndexes() {
|
package/dist/index.d.cts
CHANGED
|
@@ -74,7 +74,10 @@ declare class CollectionPatcher {
|
|
|
74
74
|
* @private
|
|
75
75
|
*/
|
|
76
76
|
private _set;
|
|
77
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Set a leaf, lifting an `$inc`/`$mul` field op into an aggregation expression if present.
|
|
79
|
+
* `type`: the field's type, when known.
|
|
80
|
+
*/
|
|
78
81
|
private _setLeaf;
|
|
79
82
|
/**
|
|
80
83
|
* Recursively walk through the patch *payload* and convert it into `$set`/…
|
|
@@ -301,6 +304,8 @@ declare class MongoAdapter extends BaseDbAdapter {
|
|
|
301
304
|
protected _hasExplicitId: boolean;
|
|
302
305
|
/** Unique fields accumulated during onFieldScanned, returned via getMetadataOverrides. */
|
|
303
306
|
private _pendingUniqueFields;
|
|
307
|
+
/** {@link _patcherFlatMap}'s memo. */
|
|
308
|
+
private _patcherFlatMapMemo?;
|
|
304
309
|
constructor(db: Db, client?: MongoClient | undefined, options?: TMongoAdapterOptions);
|
|
305
310
|
private get _client();
|
|
306
311
|
/** Every adapter over this client (or database handle) shares one session (since 0.1.128). */
|
|
@@ -435,6 +440,14 @@ declare class MongoAdapter extends BaseDbAdapter {
|
|
|
435
440
|
loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[], relations: ReadonlyMap<string, TDbRelation>, foreignKeys: ReadonlyMap<string, TDbForeignKey>, tableResolver?: TTableResolver): Promise<void>;
|
|
436
441
|
/** Returns the context object used by CollectionPatcher. */
|
|
437
442
|
getPatcherContext(): TCollectionPatcherContext;
|
|
443
|
+
/**
|
|
444
|
+
* The table's flat map keyed by document path: a patch reaches the patcher
|
|
445
|
+
* with `@db.column` names already applied (`translatePatchKeys`), so a
|
|
446
|
+
* renamed union / `@db.json` field is found — and replaced, not merged —
|
|
447
|
+
* under its stored name. Derived fields are left out (they map to their
|
|
448
|
+
* source's path). Built once per flat map.
|
|
449
|
+
*/
|
|
450
|
+
private _patcherFlatMap;
|
|
438
451
|
nativePatch(filter: FilterExpr, patch: unknown, ops?: TFieldOps, expectedVersion?: number, opts?: TDbUpdateOptions): Promise<TDbUpdateResult>;
|
|
439
452
|
onBeforeFlatten(_type: unknown): void;
|
|
440
453
|
onFieldScanned(field: string, _type: unknown, metadata: TMetadataMap<AtscriptMetadata>): void;
|
|
@@ -574,10 +587,12 @@ declare class MongoAdapter extends BaseDbAdapter {
|
|
|
574
587
|
ensureTable(): Promise<void>;
|
|
575
588
|
hasRows(tableName?: string): Promise<boolean>;
|
|
576
589
|
getObjectKind(name: string): Promise<TDbObjectKind | undefined>;
|
|
590
|
+
countKeyViolations(fields: readonly string[], tableName?: string): Promise<number>;
|
|
577
591
|
/**
|
|
578
592
|
* No physical primary key on MongoDB (`_id` is fixed): a `@meta.id` move is
|
|
579
|
-
* an index change that `syncIndexes` reconciles.
|
|
580
|
-
*
|
|
593
|
+
* an index change that `syncIndexes` reconciles. Like on the other adapters,
|
|
594
|
+
* schema sync refuses it on a populated collection whose documents do not
|
|
595
|
+
* satisfy the new key.
|
|
581
596
|
*/
|
|
582
597
|
rebuildPrimaryKey(_change: TPrimaryKeyChange): Promise<void>;
|
|
583
598
|
syncIndexes(): Promise<void>;
|
package/dist/index.d.mts
CHANGED
|
@@ -74,7 +74,10 @@ declare class CollectionPatcher {
|
|
|
74
74
|
* @private
|
|
75
75
|
*/
|
|
76
76
|
private _set;
|
|
77
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* Set a leaf, lifting an `$inc`/`$mul` field op into an aggregation expression if present.
|
|
79
|
+
* `type`: the field's type, when known.
|
|
80
|
+
*/
|
|
78
81
|
private _setLeaf;
|
|
79
82
|
/**
|
|
80
83
|
* Recursively walk through the patch *payload* and convert it into `$set`/…
|
|
@@ -301,6 +304,8 @@ declare class MongoAdapter extends BaseDbAdapter {
|
|
|
301
304
|
protected _hasExplicitId: boolean;
|
|
302
305
|
/** Unique fields accumulated during onFieldScanned, returned via getMetadataOverrides. */
|
|
303
306
|
private _pendingUniqueFields;
|
|
307
|
+
/** {@link _patcherFlatMap}'s memo. */
|
|
308
|
+
private _patcherFlatMapMemo?;
|
|
304
309
|
constructor(db: Db, client?: MongoClient | undefined, options?: TMongoAdapterOptions);
|
|
305
310
|
private get _client();
|
|
306
311
|
/** Every adapter over this client (or database handle) shares one session (since 0.1.128). */
|
|
@@ -435,6 +440,14 @@ declare class MongoAdapter extends BaseDbAdapter {
|
|
|
435
440
|
loadRelations(rows: Array<Record<string, unknown>>, withRelations: WithRelation[], relations: ReadonlyMap<string, TDbRelation>, foreignKeys: ReadonlyMap<string, TDbForeignKey>, tableResolver?: TTableResolver): Promise<void>;
|
|
436
441
|
/** Returns the context object used by CollectionPatcher. */
|
|
437
442
|
getPatcherContext(): TCollectionPatcherContext;
|
|
443
|
+
/**
|
|
444
|
+
* The table's flat map keyed by document path: a patch reaches the patcher
|
|
445
|
+
* with `@db.column` names already applied (`translatePatchKeys`), so a
|
|
446
|
+
* renamed union / `@db.json` field is found — and replaced, not merged —
|
|
447
|
+
* under its stored name. Derived fields are left out (they map to their
|
|
448
|
+
* source's path). Built once per flat map.
|
|
449
|
+
*/
|
|
450
|
+
private _patcherFlatMap;
|
|
438
451
|
nativePatch(filter: FilterExpr, patch: unknown, ops?: TFieldOps, expectedVersion?: number, opts?: TDbUpdateOptions): Promise<TDbUpdateResult>;
|
|
439
452
|
onBeforeFlatten(_type: unknown): void;
|
|
440
453
|
onFieldScanned(field: string, _type: unknown, metadata: TMetadataMap<AtscriptMetadata>): void;
|
|
@@ -574,10 +587,12 @@ declare class MongoAdapter extends BaseDbAdapter {
|
|
|
574
587
|
ensureTable(): Promise<void>;
|
|
575
588
|
hasRows(tableName?: string): Promise<boolean>;
|
|
576
589
|
getObjectKind(name: string): Promise<TDbObjectKind | undefined>;
|
|
590
|
+
countKeyViolations(fields: readonly string[], tableName?: string): Promise<number>;
|
|
577
591
|
/**
|
|
578
592
|
* No physical primary key on MongoDB (`_id` is fixed): a `@meta.id` move is
|
|
579
|
-
* an index change that `syncIndexes` reconciles.
|
|
580
|
-
*
|
|
593
|
+
* an index change that `syncIndexes` reconciles. Like on the other adapters,
|
|
594
|
+
* schema sync refuses it on a populated collection whose documents do not
|
|
595
|
+
* satisfy the new key.
|
|
581
596
|
*/
|
|
582
597
|
rebuildPrimaryKey(_change: TPrimaryKeyChange): Promise<void>;
|
|
583
598
|
syncIndexes(): Promise<void>;
|
package/dist/index.mjs
CHANGED
|
@@ -161,11 +161,14 @@ var CollectionPatcher = class {
|
|
|
161
161
|
this.currentSetStage = { $set: { [key]: val } };
|
|
162
162
|
this.updatePipeline.push(this.currentSetStage);
|
|
163
163
|
}
|
|
164
|
-
/**
|
|
165
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Set a leaf, lifting an `$inc`/`$mul` field op into an aggregation expression if present.
|
|
166
|
+
* `type`: the field's type, when known.
|
|
167
|
+
*/
|
|
168
|
+
_setLeaf(key, value, type) {
|
|
166
169
|
const fieldOp = getDbFieldOp(value);
|
|
167
170
|
if (fieldOp) this._set(key, this._fieldOpExpr(key, fieldOp.op, fieldOp.value));
|
|
168
|
-
else if (containsAggregationExpr(value)) this._set(key, { $literal: value });
|
|
171
|
+
else if (containsAggregationExpr(value) || replacesWhole(value, type)) this._set(key, { $literal: value });
|
|
169
172
|
else this._set(key, value);
|
|
170
173
|
}
|
|
171
174
|
/**
|
|
@@ -186,7 +189,7 @@ var CollectionPatcher = class {
|
|
|
186
189
|
if (isObjectValue && topLevelArray && !flatType?.metadata?.has("db.json")) this.parseArrayPatch(key, value, flatType);
|
|
187
190
|
else if (isObjectValue && flatType?.metadata?.get("db.patch.strategy") === "merge") this.flattenPayload(value, key);
|
|
188
191
|
else if (isObjectValue && flatType?.type.kind === "object" && !flatType.metadata?.has("db.json")) this._flattenReplaceObject(value, key, flatType);
|
|
189
|
-
else if (key !== "_id") this._setLeaf(key, value);
|
|
192
|
+
else if (key !== "_id") this._setLeaf(key, value, flatType);
|
|
190
193
|
}
|
|
191
194
|
return this.updatePipeline;
|
|
192
195
|
}
|
|
@@ -212,7 +215,7 @@ var CollectionPatcher = class {
|
|
|
212
215
|
else this._flattenReplaceObject(childValue, childKey, propType);
|
|
213
216
|
continue;
|
|
214
217
|
}
|
|
215
|
-
this._setLeaf(childKey, childValue);
|
|
218
|
+
this._setLeaf(childKey, childValue, propType);
|
|
216
219
|
}
|
|
217
220
|
}
|
|
218
221
|
/**
|
|
@@ -360,6 +363,16 @@ var CollectionPatcher = class {
|
|
|
360
363
|
else this._set(key, { $setDifference: [{ $ifNull: [`$${key}`, []] }, input] });
|
|
361
364
|
}
|
|
362
365
|
};
|
|
366
|
+
/**
|
|
367
|
+
* Whether a plain-object patch value replaces the stored object instead of
|
|
368
|
+
* merging into it: a `@db.json` object, or a union of objects / `T | null`
|
|
369
|
+
* whose member may switch (since 0.1.155). A field the patcher cannot type
|
|
370
|
+
* (e.g. under a `@db.column` name) keeps the merge.
|
|
371
|
+
*/
|
|
372
|
+
function replacesWhole(value, type) {
|
|
373
|
+
if (!type || !isPlainObject(value)) return false;
|
|
374
|
+
return type.metadata?.has("db.json") || type.type.kind === "union";
|
|
375
|
+
}
|
|
363
376
|
//#endregion
|
|
364
377
|
//#region src/lib/mongo-types.ts
|
|
365
378
|
const INDEX_PREFIX = "atscript__";
|
|
@@ -1623,6 +1636,30 @@ async function hasRowsImpl(host, tableName) {
|
|
|
1623
1636
|
...host._getSessionOpts()
|
|
1624
1637
|
}) !== null;
|
|
1625
1638
|
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Documents `fields` cannot identify (see `BaseDbAdapter.countKeyViolations`):
|
|
1641
|
+
* those missing one of them or holding `null`, plus every document sharing
|
|
1642
|
+
* its values with another — one `$facet` aggregation.
|
|
1643
|
+
*/
|
|
1644
|
+
async function countKeyViolationsImpl(host, fields, tableName) {
|
|
1645
|
+
const key = Object.fromEntries(fields.map((f, i) => [`k${i}`, `$${f}`]));
|
|
1646
|
+
const [result] = await host.db.collection(tableName ?? host.resolveTableName(false)).aggregate([{ $facet: {
|
|
1647
|
+
nulls: [{ $match: { $or: fields.map((f) => ({ [f]: null })) } }, { $count: "n" }],
|
|
1648
|
+
dups: [
|
|
1649
|
+
{ $match: { $and: fields.map((f) => ({ [f]: { $ne: null } })) } },
|
|
1650
|
+
{ $group: {
|
|
1651
|
+
_id: key,
|
|
1652
|
+
n: { $sum: 1 }
|
|
1653
|
+
} },
|
|
1654
|
+
{ $match: { n: { $gt: 1 } } },
|
|
1655
|
+
{ $group: {
|
|
1656
|
+
_id: null,
|
|
1657
|
+
n: { $sum: "$n" }
|
|
1658
|
+
} }
|
|
1659
|
+
]
|
|
1660
|
+
} }], host._getSessionOpts()).toArray();
|
|
1661
|
+
return (result?.nulls[0]?.n ?? 0) + (result?.dups[0]?.n ?? 0);
|
|
1662
|
+
}
|
|
1626
1663
|
/** Kind of the object stored under `name` (`listCollections` reports views as `"view"`). */
|
|
1627
1664
|
async function getObjectKindImpl(host, name) {
|
|
1628
1665
|
const type = (await host.db.listCollections({ name }, { nameOnly: true }).toArray())[0]?.type;
|
|
@@ -2153,6 +2190,8 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
2153
2190
|
_hasExplicitId = false;
|
|
2154
2191
|
/** Unique fields accumulated during onFieldScanned, returned via getMetadataOverrides. */
|
|
2155
2192
|
_pendingUniqueFields = [];
|
|
2193
|
+
/** {@link _patcherFlatMap}'s memo. */
|
|
2194
|
+
_patcherFlatMapMemo;
|
|
2156
2195
|
constructor(db, client, options = {}) {
|
|
2157
2196
|
super();
|
|
2158
2197
|
this.db = db;
|
|
@@ -2438,11 +2477,32 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
2438
2477
|
/** Returns the context object used by CollectionPatcher. */
|
|
2439
2478
|
getPatcherContext() {
|
|
2440
2479
|
return {
|
|
2441
|
-
flatMap: this.
|
|
2480
|
+
flatMap: this._patcherFlatMap(),
|
|
2442
2481
|
prepareId: (id) => this.prepareIdFromIdType(id),
|
|
2443
2482
|
createValidator: (opts) => this._table.createValidator(opts)
|
|
2444
2483
|
};
|
|
2445
2484
|
}
|
|
2485
|
+
/**
|
|
2486
|
+
* The table's flat map keyed by document path: a patch reaches the patcher
|
|
2487
|
+
* with `@db.column` names already applied (`translatePatchKeys`), so a
|
|
2488
|
+
* renamed union / `@db.json` field is found — and replaced, not merged —
|
|
2489
|
+
* under its stored name. Derived fields are left out (they map to their
|
|
2490
|
+
* source's path). Built once per flat map.
|
|
2491
|
+
*/
|
|
2492
|
+
_patcherFlatMap() {
|
|
2493
|
+
const src = this._table.flatMap;
|
|
2494
|
+
let memo = this._patcherFlatMapMemo;
|
|
2495
|
+
if (memo?.src !== src) {
|
|
2496
|
+
const meta = this._table.getMetadata();
|
|
2497
|
+
const map = /* @__PURE__ */ new Map();
|
|
2498
|
+
for (const [path, type] of src) if (!meta.derivedFields.has(path)) map.set(meta.documentPath(path), type);
|
|
2499
|
+
memo = this._patcherFlatMapMemo = {
|
|
2500
|
+
src,
|
|
2501
|
+
map
|
|
2502
|
+
};
|
|
2503
|
+
}
|
|
2504
|
+
return memo.map;
|
|
2505
|
+
}
|
|
2446
2506
|
async nativePatch(filter, patch, ops, expectedVersion, opts) {
|
|
2447
2507
|
const mongoFilter = await this._buildCasFilter(filter, expectedVersion, "nativePatch");
|
|
2448
2508
|
if (!mongoFilter) return {
|
|
@@ -2486,7 +2546,7 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
2486
2546
|
}
|
|
2487
2547
|
onFieldScanned(field, _type, metadata) {
|
|
2488
2548
|
if (field === "_id") this._hasExplicitId = true;
|
|
2489
|
-
if (field !== "_id" && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2549
|
+
if (field !== "_id" && !field.includes(".") && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2490
2550
|
for (const index of metadata.get("db.mongo.search.text") || []) this._pendingSearchFields.push({
|
|
2491
2551
|
indexName: index.indexName,
|
|
2492
2552
|
field,
|
|
@@ -3100,10 +3160,14 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
3100
3160
|
async getObjectKind(name) {
|
|
3101
3161
|
return getObjectKindImpl(this, name);
|
|
3102
3162
|
}
|
|
3163
|
+
async countKeyViolations(fields, tableName) {
|
|
3164
|
+
return countKeyViolationsImpl(this, fields, tableName);
|
|
3165
|
+
}
|
|
3103
3166
|
/**
|
|
3104
3167
|
* No physical primary key on MongoDB (`_id` is fixed): a `@meta.id` move is
|
|
3105
|
-
* an index change that `syncIndexes` reconciles.
|
|
3106
|
-
*
|
|
3168
|
+
* an index change that `syncIndexes` reconciles. Like on the other adapters,
|
|
3169
|
+
* schema sync refuses it on a populated collection whose documents do not
|
|
3170
|
+
* satisfy the new key.
|
|
3107
3171
|
*/
|
|
3108
3172
|
async rebuildPrimaryKey(_change) {}
|
|
3109
3173
|
async syncIndexes() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-mongo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.155",
|
|
4
4
|
"description": "Mongodb plugin for atscript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -46,19 +46,19 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@atscript/core": "^0.1.
|
|
50
|
-
"@atscript/typescript": "^0.1.
|
|
49
|
+
"@atscript/core": "^0.1.105",
|
|
50
|
+
"@atscript/typescript": "^0.1.105",
|
|
51
51
|
"@uniqu/core": "^0.1.15",
|
|
52
52
|
"mongodb": "^6.17.0",
|
|
53
53
|
"mongodb-memory-server-core": "^10.0.0",
|
|
54
|
-
"unplugin-atscript": "^0.1.
|
|
54
|
+
"unplugin-atscript": "^0.1.105"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@atscript/core": "^0.1.
|
|
58
|
-
"@atscript/typescript": "^0.1.
|
|
57
|
+
"@atscript/core": "^0.1.105",
|
|
58
|
+
"@atscript/typescript": "^0.1.105",
|
|
59
59
|
"@uniqu/core": "^0.1.15",
|
|
60
60
|
"mongodb": "^6.17.0",
|
|
61
|
-
"@atscript/db": "^0.1.
|
|
61
|
+
"@atscript/db": "^0.1.155"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"postinstall": "asc -f dts",
|