@atscript/db-mongo 0.1.154 → 0.1.156
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 +124 -13
- package/dist/index.d.cts +22 -5
- package/dist/index.d.mts +22 -5
- package/dist/index.mjs +124 -13
- 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;
|
|
@@ -1733,6 +1770,27 @@ async function dropColumnsImpl(host, columns) {
|
|
|
1733
1770
|
await host.collection.updateMany({}, { $unset: unsetSpec }, host._getSessionOpts());
|
|
1734
1771
|
}
|
|
1735
1772
|
/**
|
|
1773
|
+
* Drops the managed indexes over any of `columns` (or a path under one).
|
|
1774
|
+
* Schema sync calls it before {@link dropColumnsImpl}: a unique index on a
|
|
1775
|
+
* required field indexes a `$unset` document as `null`, so the second one
|
|
1776
|
+
* collides (E11000) — e.g. the old key field's `__pk` index when a `@meta.id`
|
|
1777
|
+
* move removes that field. `syncIndexesImpl` then builds what the model wants.
|
|
1778
|
+
*/
|
|
1779
|
+
async function dropIndexesForColumnsImpl(host, columns) {
|
|
1780
|
+
const dropped = new Set(columns);
|
|
1781
|
+
let existing;
|
|
1782
|
+
try {
|
|
1783
|
+
existing = await host.collection.listIndexes().toArray();
|
|
1784
|
+
} catch (error) {
|
|
1785
|
+
if (error.code === 26) return;
|
|
1786
|
+
throw error;
|
|
1787
|
+
}
|
|
1788
|
+
for (const remote of existing) if (remote.name.startsWith("atscript__") && coversAny(remote.key, remote.weights, dropped)) {
|
|
1789
|
+
host._log("dropIndex", remote.name);
|
|
1790
|
+
await host.collection.dropIndex(remote.name);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1736
1794
|
* The segments of a field's physical document path with `$[]` after every
|
|
1737
1795
|
* segment whose logical prefix is an array in the flatMap — Mongo's
|
|
1738
1796
|
* all-positional operator walks every element. `physicalPath` defaults to
|
|
@@ -1766,7 +1824,23 @@ function resolveSyncDefault(field) {
|
|
|
1766
1824
|
if (!field.defaultValue) return;
|
|
1767
1825
|
if (field.defaultValue.kind === "value") return field.designType === "string" ? field.defaultValue.value : JSON.parse(field.defaultValue.value);
|
|
1768
1826
|
}
|
|
1769
|
-
|
|
1827
|
+
/**
|
|
1828
|
+
* Whether an index's fields include one of `paths` or a path under one —
|
|
1829
|
+
* a text index lists its fields in `weights` (its key is `_fts` / `_ftsx`).
|
|
1830
|
+
*/
|
|
1831
|
+
function coversAny(key, weights, paths) {
|
|
1832
|
+
return [...Object.keys(key), ...Object.keys(weights ?? {})].some((f) => paths.has(f) || hasAncestorIn(f, paths));
|
|
1833
|
+
}
|
|
1834
|
+
/** The `__pk` unique index of non-`_id` `@meta.id` fields. */
|
|
1835
|
+
const PK_INDEX = mongoIndexKey("unique", "__pk");
|
|
1836
|
+
/**
|
|
1837
|
+
* Reconciles the managed indexes with the model. `opts` (schema sync, safe
|
|
1838
|
+
* mode) names the indexes that stay as they are — neither dropped, replaced
|
|
1839
|
+
* nor created — because the change they depend on was skipped: the `__pk`
|
|
1840
|
+
* index of a skipped key rebuild, the indexes over a column whose type change
|
|
1841
|
+
* is pending (its present-only filter is typed).
|
|
1842
|
+
*/
|
|
1843
|
+
async function syncIndexesImpl(host, opts) {
|
|
1770
1844
|
await host.ensureCollectionExists();
|
|
1771
1845
|
const allIndexes = /* @__PURE__ */ new Map();
|
|
1772
1846
|
for (const [key, index] of host._table.indexes.entries()) {
|
|
@@ -1807,6 +1881,12 @@ async function syncIndexesImpl(host) {
|
|
|
1807
1881
|
} else allIndexes.set(key, index);
|
|
1808
1882
|
const existingIndexes = await host.collection.listIndexes().toArray();
|
|
1809
1883
|
const indexesToCreate = new Map(allIndexes);
|
|
1884
|
+
const keepColumns = new Set(opts?.keepColumns ?? []);
|
|
1885
|
+
const isKept = (name, key, weights) => opts?.keepPrimaryKey === true && name === PK_INDEX || coversAny(key, weights, keepColumns);
|
|
1886
|
+
const kept = /* @__PURE__ */ new Set();
|
|
1887
|
+
for (const index of allIndexes.values()) if (isPlainIndex(index) && isKept(index.key, index.fields, index.weights)) kept.add(index.key);
|
|
1888
|
+
for (const remote of existingIndexes) if (isKept(remote.name, remote.key, remote.weights)) kept.add(remote.name);
|
|
1889
|
+
for (const name of kept) indexesToCreate.delete(name);
|
|
1810
1890
|
const { attempt, throwIfAny } = (0, _atscript_db.createFailureCollector)("index sync");
|
|
1811
1891
|
let defaultCollation;
|
|
1812
1892
|
const collectionDefaultCollation = async () => {
|
|
@@ -1814,7 +1894,7 @@ async function syncIndexesImpl(host) {
|
|
|
1814
1894
|
return defaultCollation ?? void 0;
|
|
1815
1895
|
};
|
|
1816
1896
|
for (const remote of existingIndexes) {
|
|
1817
|
-
if (!remote.name.startsWith("atscript__")) continue;
|
|
1897
|
+
if (!remote.name.startsWith("atscript__") || kept.has(remote.name)) continue;
|
|
1818
1898
|
if (indexesToCreate.has(remote.name)) {
|
|
1819
1899
|
const local = indexesToCreate.get(remote.name);
|
|
1820
1900
|
if (isPlainIndex(local)) {
|
|
@@ -2154,6 +2234,8 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2154
2234
|
_hasExplicitId = false;
|
|
2155
2235
|
/** Unique fields accumulated during onFieldScanned, returned via getMetadataOverrides. */
|
|
2156
2236
|
_pendingUniqueFields = [];
|
|
2237
|
+
/** {@link _patcherFlatMap}'s memo. */
|
|
2238
|
+
_patcherFlatMapMemo;
|
|
2157
2239
|
constructor(db, client, options = {}) {
|
|
2158
2240
|
super();
|
|
2159
2241
|
this.db = db;
|
|
@@ -2439,11 +2521,32 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2439
2521
|
/** Returns the context object used by CollectionPatcher. */
|
|
2440
2522
|
getPatcherContext() {
|
|
2441
2523
|
return {
|
|
2442
|
-
flatMap: this.
|
|
2524
|
+
flatMap: this._patcherFlatMap(),
|
|
2443
2525
|
prepareId: (id) => this.prepareIdFromIdType(id),
|
|
2444
2526
|
createValidator: (opts) => this._table.createValidator(opts)
|
|
2445
2527
|
};
|
|
2446
2528
|
}
|
|
2529
|
+
/**
|
|
2530
|
+
* The table's flat map keyed by document path: a patch reaches the patcher
|
|
2531
|
+
* with `@db.column` names already applied (`translatePatchKeys`), so a
|
|
2532
|
+
* renamed union / `@db.json` field is found — and replaced, not merged —
|
|
2533
|
+
* under its stored name. Derived fields are left out (they map to their
|
|
2534
|
+
* source's path). Built once per flat map.
|
|
2535
|
+
*/
|
|
2536
|
+
_patcherFlatMap() {
|
|
2537
|
+
const src = this._table.flatMap;
|
|
2538
|
+
let memo = this._patcherFlatMapMemo;
|
|
2539
|
+
if (memo?.src !== src) {
|
|
2540
|
+
const meta = this._table.getMetadata();
|
|
2541
|
+
const map = /* @__PURE__ */ new Map();
|
|
2542
|
+
for (const [path, type] of src) if (!meta.derivedFields.has(path)) map.set(meta.documentPath(path), type);
|
|
2543
|
+
memo = this._patcherFlatMapMemo = {
|
|
2544
|
+
src,
|
|
2545
|
+
map
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
return memo.map;
|
|
2549
|
+
}
|
|
2447
2550
|
async nativePatch(filter, patch, ops, expectedVersion, opts) {
|
|
2448
2551
|
const mongoFilter = await this._buildCasFilter(filter, expectedVersion, "nativePatch");
|
|
2449
2552
|
if (!mongoFilter) return {
|
|
@@ -2487,7 +2590,7 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
2487
2590
|
}
|
|
2488
2591
|
onFieldScanned(field, _type, metadata) {
|
|
2489
2592
|
if (field === "_id") this._hasExplicitId = true;
|
|
2490
|
-
if (field !== "_id" && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2593
|
+
if (field !== "_id" && !field.includes(".") && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2491
2594
|
for (const index of metadata.get("db.mongo.search.text") || []) this._pendingSearchFields.push({
|
|
2492
2595
|
indexName: index.indexName,
|
|
2493
2596
|
field,
|
|
@@ -3101,14 +3204,19 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
3101
3204
|
async getObjectKind(name) {
|
|
3102
3205
|
return getObjectKindImpl(this, name);
|
|
3103
3206
|
}
|
|
3207
|
+
async countKeyViolations(fields, tableName) {
|
|
3208
|
+
return countKeyViolationsImpl(this, fields, tableName);
|
|
3209
|
+
}
|
|
3104
3210
|
/**
|
|
3105
3211
|
* No physical primary key on MongoDB (`_id` is fixed): a `@meta.id` move is
|
|
3106
|
-
* an index change that `syncIndexes` reconciles.
|
|
3107
|
-
*
|
|
3212
|
+
* an index change that `syncIndexes` reconciles. Like on the other adapters,
|
|
3213
|
+
* schema sync refuses it on a populated collection whose documents do not
|
|
3214
|
+
* satisfy the new key. An old key field removed in the same sync loses its
|
|
3215
|
+
* `__pk` index first (`dropIndexesForColumns`).
|
|
3108
3216
|
*/
|
|
3109
3217
|
async rebuildPrimaryKey(_change) {}
|
|
3110
|
-
async syncIndexes() {
|
|
3111
|
-
return syncIndexesImpl(this);
|
|
3218
|
+
async syncIndexes(opts) {
|
|
3219
|
+
return syncIndexesImpl(this, opts);
|
|
3112
3220
|
}
|
|
3113
3221
|
async syncColumns(diff) {
|
|
3114
3222
|
return syncColumnsImpl(this, diff);
|
|
@@ -3116,6 +3224,9 @@ var MongoAdapter = class MongoAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
3116
3224
|
async dropColumns(columns) {
|
|
3117
3225
|
return dropColumnsImpl(this, columns);
|
|
3118
3226
|
}
|
|
3227
|
+
async dropIndexesForColumns(columns) {
|
|
3228
|
+
return dropIndexesForColumnsImpl(this, columns);
|
|
3229
|
+
}
|
|
3119
3230
|
async renameTable(oldName) {
|
|
3120
3231
|
return renameTableImpl(this, oldName);
|
|
3121
3232
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as buildMongoFilter, c as mongoFilterStages, i as TMongoFilterPlan, l as planStages, n as TMongoFieldCollation, o as buildMongoQuery, r as TMongoFilterOptions, s as collationOfAdapter, t as REL_FILTER_TEMP_PREFIX } from "./mongo-filter-CGd9ryOD.cjs";
|
|
2
|
-
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbCollation, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertIgnoreSlot, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateOptions, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TTableResolver, TViewCapability, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
|
|
2
|
+
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbCollation, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertIgnoreSlot, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateOptions, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TSyncIndexesOptions, TTableResolver, TViewCapability, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
|
|
3
3
|
import { AggregateOptions, AggregationCursor, ClientSession, Collection, Db, Document, Filter, MongoClient, ObjectId, UpdateFilter, UpdateOptions } from "mongodb";
|
|
4
4
|
import { TAtscriptAnnotatedType, TMetadataMap, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
|
|
5
5
|
import { AggregateFn, BucketUnit } from "@uniqu/core";
|
|
@@ -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,15 +587,19 @@ 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. An old key field removed in the same sync loses its
|
|
596
|
+
* `__pk` index first (`dropIndexesForColumns`).
|
|
581
597
|
*/
|
|
582
598
|
rebuildPrimaryKey(_change: TPrimaryKeyChange): Promise<void>;
|
|
583
|
-
syncIndexes(): Promise<void>;
|
|
599
|
+
syncIndexes(opts?: TSyncIndexesOptions): Promise<void>;
|
|
584
600
|
syncColumns(diff: TColumnDiff): Promise<TSyncColumnResult>;
|
|
585
601
|
dropColumns(columns: string[]): Promise<void>;
|
|
602
|
+
dropIndexesForColumns(columns: string[]): Promise<void>;
|
|
586
603
|
renameTable(oldName: string): Promise<void>;
|
|
587
604
|
recreateTable(): Promise<void>;
|
|
588
605
|
dropTable(): Promise<void>;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as buildMongoFilter, c as mongoFilterStages, i as TMongoFilterPlan, l as planStages, n as TMongoFieldCollation, o as buildMongoQuery, r as TMongoFilterOptions, s as collationOfAdapter, t as REL_FILTER_TEMP_PREFIX } from "./mongo-filter-CGd9ryOD.mjs";
|
|
2
|
-
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbCollation, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertIgnoreSlot, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateOptions, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TTableResolver, TViewCapability, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
|
|
2
|
+
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbCollation, TDbDeleteResult, TDbFieldMeta, TDbForeignKey, TDbInsertIgnoreSlot, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbRelation, TDbUpdateOptions, TDbUpdateResult, TExistingTableOption, TFieldOps, TMetadataOverrides, TPrimaryKeyChange, TSearchIndexInfo, TSyncColumnResult, TSyncIndexesOptions, TTableResolver, TViewCapability, TableMetadata, WithRelation, getKeyProps } from "@atscript/db";
|
|
3
3
|
import { AggregateOptions, AggregationCursor, ClientSession, Collection, Db, Document, Filter, MongoClient, ObjectId, UpdateFilter, UpdateOptions } from "mongodb";
|
|
4
4
|
import { AggregateFn, BucketUnit } from "@uniqu/core";
|
|
5
5
|
import { TAtscriptAnnotatedType, TMetadataMap, TValidatorOptions, TValidatorPlugin, Validator } from "@atscript/typescript/utils";
|
|
@@ -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,15 +587,19 @@ 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. An old key field removed in the same sync loses its
|
|
596
|
+
* `__pk` index first (`dropIndexesForColumns`).
|
|
581
597
|
*/
|
|
582
598
|
rebuildPrimaryKey(_change: TPrimaryKeyChange): Promise<void>;
|
|
583
|
-
syncIndexes(): Promise<void>;
|
|
599
|
+
syncIndexes(opts?: TSyncIndexesOptions): Promise<void>;
|
|
584
600
|
syncColumns(diff: TColumnDiff): Promise<TSyncColumnResult>;
|
|
585
601
|
dropColumns(columns: string[]): Promise<void>;
|
|
602
|
+
dropIndexesForColumns(columns: string[]): Promise<void>;
|
|
586
603
|
renameTable(oldName: string): Promise<void>;
|
|
587
604
|
recreateTable(): Promise<void>;
|
|
588
605
|
dropTable(): 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;
|
|
@@ -1732,6 +1769,27 @@ async function dropColumnsImpl(host, columns) {
|
|
|
1732
1769
|
await host.collection.updateMany({}, { $unset: unsetSpec }, host._getSessionOpts());
|
|
1733
1770
|
}
|
|
1734
1771
|
/**
|
|
1772
|
+
* Drops the managed indexes over any of `columns` (or a path under one).
|
|
1773
|
+
* Schema sync calls it before {@link dropColumnsImpl}: a unique index on a
|
|
1774
|
+
* required field indexes a `$unset` document as `null`, so the second one
|
|
1775
|
+
* collides (E11000) — e.g. the old key field's `__pk` index when a `@meta.id`
|
|
1776
|
+
* move removes that field. `syncIndexesImpl` then builds what the model wants.
|
|
1777
|
+
*/
|
|
1778
|
+
async function dropIndexesForColumnsImpl(host, columns) {
|
|
1779
|
+
const dropped = new Set(columns);
|
|
1780
|
+
let existing;
|
|
1781
|
+
try {
|
|
1782
|
+
existing = await host.collection.listIndexes().toArray();
|
|
1783
|
+
} catch (error) {
|
|
1784
|
+
if (error.code === 26) return;
|
|
1785
|
+
throw error;
|
|
1786
|
+
}
|
|
1787
|
+
for (const remote of existing) if (remote.name.startsWith("atscript__") && coversAny(remote.key, remote.weights, dropped)) {
|
|
1788
|
+
host._log("dropIndex", remote.name);
|
|
1789
|
+
await host.collection.dropIndex(remote.name);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1735
1793
|
* The segments of a field's physical document path with `$[]` after every
|
|
1736
1794
|
* segment whose logical prefix is an array in the flatMap — Mongo's
|
|
1737
1795
|
* all-positional operator walks every element. `physicalPath` defaults to
|
|
@@ -1765,7 +1823,23 @@ function resolveSyncDefault(field) {
|
|
|
1765
1823
|
if (!field.defaultValue) return;
|
|
1766
1824
|
if (field.defaultValue.kind === "value") return field.designType === "string" ? field.defaultValue.value : JSON.parse(field.defaultValue.value);
|
|
1767
1825
|
}
|
|
1768
|
-
|
|
1826
|
+
/**
|
|
1827
|
+
* Whether an index's fields include one of `paths` or a path under one —
|
|
1828
|
+
* a text index lists its fields in `weights` (its key is `_fts` / `_ftsx`).
|
|
1829
|
+
*/
|
|
1830
|
+
function coversAny(key, weights, paths) {
|
|
1831
|
+
return [...Object.keys(key), ...Object.keys(weights ?? {})].some((f) => paths.has(f) || hasAncestorIn(f, paths));
|
|
1832
|
+
}
|
|
1833
|
+
/** The `__pk` unique index of non-`_id` `@meta.id` fields. */
|
|
1834
|
+
const PK_INDEX = mongoIndexKey("unique", "__pk");
|
|
1835
|
+
/**
|
|
1836
|
+
* Reconciles the managed indexes with the model. `opts` (schema sync, safe
|
|
1837
|
+
* mode) names the indexes that stay as they are — neither dropped, replaced
|
|
1838
|
+
* nor created — because the change they depend on was skipped: the `__pk`
|
|
1839
|
+
* index of a skipped key rebuild, the indexes over a column whose type change
|
|
1840
|
+
* is pending (its present-only filter is typed).
|
|
1841
|
+
*/
|
|
1842
|
+
async function syncIndexesImpl(host, opts) {
|
|
1769
1843
|
await host.ensureCollectionExists();
|
|
1770
1844
|
const allIndexes = /* @__PURE__ */ new Map();
|
|
1771
1845
|
for (const [key, index] of host._table.indexes.entries()) {
|
|
@@ -1806,6 +1880,12 @@ async function syncIndexesImpl(host) {
|
|
|
1806
1880
|
} else allIndexes.set(key, index);
|
|
1807
1881
|
const existingIndexes = await host.collection.listIndexes().toArray();
|
|
1808
1882
|
const indexesToCreate = new Map(allIndexes);
|
|
1883
|
+
const keepColumns = new Set(opts?.keepColumns ?? []);
|
|
1884
|
+
const isKept = (name, key, weights) => opts?.keepPrimaryKey === true && name === PK_INDEX || coversAny(key, weights, keepColumns);
|
|
1885
|
+
const kept = /* @__PURE__ */ new Set();
|
|
1886
|
+
for (const index of allIndexes.values()) if (isPlainIndex(index) && isKept(index.key, index.fields, index.weights)) kept.add(index.key);
|
|
1887
|
+
for (const remote of existingIndexes) if (isKept(remote.name, remote.key, remote.weights)) kept.add(remote.name);
|
|
1888
|
+
for (const name of kept) indexesToCreate.delete(name);
|
|
1809
1889
|
const { attempt, throwIfAny } = createFailureCollector("index sync");
|
|
1810
1890
|
let defaultCollation;
|
|
1811
1891
|
const collectionDefaultCollation = async () => {
|
|
@@ -1813,7 +1893,7 @@ async function syncIndexesImpl(host) {
|
|
|
1813
1893
|
return defaultCollation ?? void 0;
|
|
1814
1894
|
};
|
|
1815
1895
|
for (const remote of existingIndexes) {
|
|
1816
|
-
if (!remote.name.startsWith("atscript__")) continue;
|
|
1896
|
+
if (!remote.name.startsWith("atscript__") || kept.has(remote.name)) continue;
|
|
1817
1897
|
if (indexesToCreate.has(remote.name)) {
|
|
1818
1898
|
const local = indexesToCreate.get(remote.name);
|
|
1819
1899
|
if (isPlainIndex(local)) {
|
|
@@ -2153,6 +2233,8 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
2153
2233
|
_hasExplicitId = false;
|
|
2154
2234
|
/** Unique fields accumulated during onFieldScanned, returned via getMetadataOverrides. */
|
|
2155
2235
|
_pendingUniqueFields = [];
|
|
2236
|
+
/** {@link _patcherFlatMap}'s memo. */
|
|
2237
|
+
_patcherFlatMapMemo;
|
|
2156
2238
|
constructor(db, client, options = {}) {
|
|
2157
2239
|
super();
|
|
2158
2240
|
this.db = db;
|
|
@@ -2438,11 +2520,32 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
2438
2520
|
/** Returns the context object used by CollectionPatcher. */
|
|
2439
2521
|
getPatcherContext() {
|
|
2440
2522
|
return {
|
|
2441
|
-
flatMap: this.
|
|
2523
|
+
flatMap: this._patcherFlatMap(),
|
|
2442
2524
|
prepareId: (id) => this.prepareIdFromIdType(id),
|
|
2443
2525
|
createValidator: (opts) => this._table.createValidator(opts)
|
|
2444
2526
|
};
|
|
2445
2527
|
}
|
|
2528
|
+
/**
|
|
2529
|
+
* The table's flat map keyed by document path: a patch reaches the patcher
|
|
2530
|
+
* with `@db.column` names already applied (`translatePatchKeys`), so a
|
|
2531
|
+
* renamed union / `@db.json` field is found — and replaced, not merged —
|
|
2532
|
+
* under its stored name. Derived fields are left out (they map to their
|
|
2533
|
+
* source's path). Built once per flat map.
|
|
2534
|
+
*/
|
|
2535
|
+
_patcherFlatMap() {
|
|
2536
|
+
const src = this._table.flatMap;
|
|
2537
|
+
let memo = this._patcherFlatMapMemo;
|
|
2538
|
+
if (memo?.src !== src) {
|
|
2539
|
+
const meta = this._table.getMetadata();
|
|
2540
|
+
const map = /* @__PURE__ */ new Map();
|
|
2541
|
+
for (const [path, type] of src) if (!meta.derivedFields.has(path)) map.set(meta.documentPath(path), type);
|
|
2542
|
+
memo = this._patcherFlatMapMemo = {
|
|
2543
|
+
src,
|
|
2544
|
+
map
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
return memo.map;
|
|
2548
|
+
}
|
|
2446
2549
|
async nativePatch(filter, patch, ops, expectedVersion, opts) {
|
|
2447
2550
|
const mongoFilter = await this._buildCasFilter(filter, expectedVersion, "nativePatch");
|
|
2448
2551
|
if (!mongoFilter) return {
|
|
@@ -2486,7 +2589,7 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
2486
2589
|
}
|
|
2487
2590
|
onFieldScanned(field, _type, metadata) {
|
|
2488
2591
|
if (field === "_id") this._hasExplicitId = true;
|
|
2489
|
-
if (field !== "_id" && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2592
|
+
if (field !== "_id" && !field.includes(".") && metadata.has("meta.id")) this._pendingUniqueFields.push(field);
|
|
2490
2593
|
for (const index of metadata.get("db.mongo.search.text") || []) this._pendingSearchFields.push({
|
|
2491
2594
|
indexName: index.indexName,
|
|
2492
2595
|
field,
|
|
@@ -3100,14 +3203,19 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
3100
3203
|
async getObjectKind(name) {
|
|
3101
3204
|
return getObjectKindImpl(this, name);
|
|
3102
3205
|
}
|
|
3206
|
+
async countKeyViolations(fields, tableName) {
|
|
3207
|
+
return countKeyViolationsImpl(this, fields, tableName);
|
|
3208
|
+
}
|
|
3103
3209
|
/**
|
|
3104
3210
|
* No physical primary key on MongoDB (`_id` is fixed): a `@meta.id` move is
|
|
3105
|
-
* an index change that `syncIndexes` reconciles.
|
|
3106
|
-
*
|
|
3211
|
+
* an index change that `syncIndexes` reconciles. Like on the other adapters,
|
|
3212
|
+
* schema sync refuses it on a populated collection whose documents do not
|
|
3213
|
+
* satisfy the new key. An old key field removed in the same sync loses its
|
|
3214
|
+
* `__pk` index first (`dropIndexesForColumns`).
|
|
3107
3215
|
*/
|
|
3108
3216
|
async rebuildPrimaryKey(_change) {}
|
|
3109
|
-
async syncIndexes() {
|
|
3110
|
-
return syncIndexesImpl(this);
|
|
3217
|
+
async syncIndexes(opts) {
|
|
3218
|
+
return syncIndexesImpl(this, opts);
|
|
3111
3219
|
}
|
|
3112
3220
|
async syncColumns(diff) {
|
|
3113
3221
|
return syncColumnsImpl(this, diff);
|
|
@@ -3115,6 +3223,9 @@ var MongoAdapter = class MongoAdapter extends BaseDbAdapter {
|
|
|
3115
3223
|
async dropColumns(columns) {
|
|
3116
3224
|
return dropColumnsImpl(this, columns);
|
|
3117
3225
|
}
|
|
3226
|
+
async dropIndexesForColumns(columns) {
|
|
3227
|
+
return dropIndexesForColumnsImpl(this, columns);
|
|
3228
|
+
}
|
|
3118
3229
|
async renameTable(oldName) {
|
|
3119
3230
|
return renameTableImpl(this, oldName);
|
|
3120
3231
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-mongo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.156",
|
|
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.106",
|
|
50
|
+
"@atscript/typescript": "^0.1.106",
|
|
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.106"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@atscript/core": "^0.1.
|
|
58
|
-
"@atscript/typescript": "^0.1.
|
|
57
|
+
"@atscript/core": "^0.1.106",
|
|
58
|
+
"@atscript/typescript": "^0.1.106",
|
|
59
59
|
"@uniqu/core": "^0.1.15",
|
|
60
60
|
"mongodb": "^6.17.0",
|
|
61
|
-
"@atscript/db": "^0.1.
|
|
61
|
+
"@atscript/db": "^0.1.156"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"postinstall": "asc -f dts",
|