@atscript/mongo 0.0.16 → 0.0.17
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 +125 -4
- package/dist/index.d.ts +14 -5
- package/dist/index.mjs +127 -6
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -250,7 +250,35 @@ const annotations = { mongo: {
|
|
|
250
250
|
description: "The **name of the vector search index** this field should be used as a filter for."
|
|
251
251
|
}]
|
|
252
252
|
})
|
|
253
|
-
}
|
|
253
|
+
},
|
|
254
|
+
patch: { strategy: new __atscript_core.AnnotationSpec({
|
|
255
|
+
description: "Defines the **patching strategy** for updating MongoDB documents.\n\n- **\"replace\"** → The field or object will be **fully replaced**.\n- **\"merge\"** → The field or object will be **merged recursively** (applies only to objects, not arrays).\n\n**Example:**\n```atscript\n@mongo.patch.strategy \"merge\"\nsettings: {\n notifications: boolean\n preferences: {\n theme: string\n }\n}\n```\n",
|
|
256
|
+
nodeType: ["prop"],
|
|
257
|
+
multiple: false,
|
|
258
|
+
argument: {
|
|
259
|
+
name: "strategy",
|
|
260
|
+
type: "string",
|
|
261
|
+
description: "The **patch strategy** for this field: `\"replace\"` (default) or `\"merge\"`.",
|
|
262
|
+
values: ["replace", "merge"]
|
|
263
|
+
},
|
|
264
|
+
validate(token, args, doc) {
|
|
265
|
+
const field = token.parentNode;
|
|
266
|
+
const errors = [];
|
|
267
|
+
const definition = field.getDefinition();
|
|
268
|
+
if (!definition) return errors;
|
|
269
|
+
let wrongType = false;
|
|
270
|
+
if ((0, __atscript_core.isRef)(definition)) {
|
|
271
|
+
const def = doc.unwindType(definition.id, definition.chain)?.def;
|
|
272
|
+
if (!(0, __atscript_core.isStructure)(def) && !(0, __atscript_core.isInterface)(def) && !(0, __atscript_core.isArray)(def)) wrongType = true;
|
|
273
|
+
} else if (!(0, __atscript_core.isStructure)(definition) && !(0, __atscript_core.isInterface)(definition) && !(0, __atscript_core.isArray)(definition)) wrongType = true;
|
|
274
|
+
if (wrongType) errors.push({
|
|
275
|
+
message: `[mongo] type of object or array expected when using @mongo.patch.strategy`,
|
|
276
|
+
severity: 1,
|
|
277
|
+
range: token.range
|
|
278
|
+
});
|
|
279
|
+
return errors;
|
|
280
|
+
}
|
|
281
|
+
}) }
|
|
254
282
|
} };
|
|
255
283
|
|
|
256
284
|
//#endregion
|
|
@@ -289,9 +317,14 @@ function _define_property$1(obj, key, value) {
|
|
|
289
317
|
else obj[key] = value;
|
|
290
318
|
return obj;
|
|
291
319
|
}
|
|
292
|
-
const INDEX_PREFIX = "
|
|
320
|
+
const INDEX_PREFIX = "atscript__";
|
|
293
321
|
const DEFAULT_INDEX_NAME = "DEFAULT";
|
|
294
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Generates a key for mongo index
|
|
324
|
+
* @param type index type
|
|
325
|
+
* @param name index name
|
|
326
|
+
* @returns index key
|
|
327
|
+
*/ function indexKey(type, name) {
|
|
295
328
|
const cleanName = name.replace(/[^a-z0-9_.-]/gi, "_").replace(/_+/g, "_").slice(0, 127 - INDEX_PREFIX.length - type.length - 2);
|
|
296
329
|
return `${INDEX_PREFIX}${type}__${cleanName}`;
|
|
297
330
|
}
|
|
@@ -303,6 +336,57 @@ var AsCollection = class {
|
|
|
303
336
|
const exists = await this.exists();
|
|
304
337
|
if (!exists) await this.asMongo.db.createCollection(this.name, { comment: "Created by Atscript Mongo Collection" });
|
|
305
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* Returns the a type definition of the "_id" prop.
|
|
341
|
+
*/ get idType() {
|
|
342
|
+
const idProp = this.type.type.props.get("_id");
|
|
343
|
+
const idTags = idProp?.type.tags;
|
|
344
|
+
if (idTags?.has("objectId") && idTags?.has("mongo")) return "objectId";
|
|
345
|
+
if (idProp?.type.kind === "") return idProp.type.designType;
|
|
346
|
+
return "objectId";
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Transforms an "_id" value to the expected type (`ObjectId`, `number`, or `string`).
|
|
350
|
+
* Assumes input has already been validated.
|
|
351
|
+
*
|
|
352
|
+
* @param {string | number | ObjectId} id - The validated ID.
|
|
353
|
+
* @returns {string | number | ObjectId} - The transformed ID.
|
|
354
|
+
* @throws {Error} If the `_id` type is unknown.
|
|
355
|
+
*/ prepareId(id) {
|
|
356
|
+
switch (this.idType) {
|
|
357
|
+
case "objectId": return id instanceof mongodb.ObjectId ? id : new mongodb.ObjectId(id);
|
|
358
|
+
case "number": return Number(id);
|
|
359
|
+
case "string": return String(id);
|
|
360
|
+
default: throw new Error("Unknown \"_id\" type");
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Retrieves a validator for a given purpose. If the validator is not already cached,
|
|
365
|
+
* it creates and stores a new one based on the purpose.
|
|
366
|
+
*
|
|
367
|
+
* @param {TValidatorPurpose} purpose - The validation purpose (`input`, `update`, `patch`).
|
|
368
|
+
* @returns {Validator} The corresponding validator instance.
|
|
369
|
+
* @throws {Error} If an unknown purpose is provided.
|
|
370
|
+
*/ getValidator(purpose) {
|
|
371
|
+
if (!this.validators.has(purpose)) switch (purpose) {
|
|
372
|
+
case "insert": {
|
|
373
|
+
this.validators.set(purpose, this.type.validator(this.idType === "objectId" ? { skipList: new Set(["_id"]) } : {}));
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
case "update": {
|
|
377
|
+
this.validators.set(purpose, this.type.validator());
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case "patch": {
|
|
381
|
+
this.validators.set(purpose, this.type.validator({ partial: (def, path) => {
|
|
382
|
+
return path === "" || def.metadata.get("mongo.patch.strategy") === "merge";
|
|
383
|
+
} }));
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
default: throw new Error(`Unknown validator purpose: ${purpose}`);
|
|
387
|
+
}
|
|
388
|
+
return this.validators.get(purpose);
|
|
389
|
+
}
|
|
306
390
|
get type() {
|
|
307
391
|
return this._type;
|
|
308
392
|
}
|
|
@@ -350,11 +434,13 @@ else {
|
|
|
350
434
|
_flattenType(type, prefix) {
|
|
351
435
|
switch (type.type.kind) {
|
|
352
436
|
case "object":
|
|
437
|
+
this._flatMap?.set(prefix || "", type);
|
|
353
438
|
const items = Array.from(type.type.props.entries());
|
|
354
439
|
for (const [key, value] of items) this._flattenType(value, prefix ? `${prefix}.${key}` : key);
|
|
355
440
|
break;
|
|
356
441
|
case "array":
|
|
357
|
-
this.
|
|
442
|
+
this._flatMap?.set(prefix || "", type);
|
|
443
|
+
if (type.type.of.type.kind) this._flattenType(type.type.of, prefix);
|
|
358
444
|
break;
|
|
359
445
|
case "intersection":
|
|
360
446
|
case "tuple":
|
|
@@ -502,18 +588,53 @@ else toUpdate.add(remote.name);
|
|
|
502
588
|
default:
|
|
503
589
|
}
|
|
504
590
|
}
|
|
591
|
+
prepareInsert(payload) {
|
|
592
|
+
const v = this.getValidator("insert");
|
|
593
|
+
if (v.validate(payload)) {
|
|
594
|
+
const data = { ...payload };
|
|
595
|
+
if (data._id) data._id = this.prepareId(data._id);
|
|
596
|
+
else if (this.idType !== "objectId") throw new Error("Missing \"_id\" field");
|
|
597
|
+
return data;
|
|
598
|
+
}
|
|
599
|
+
throw new Error("Invalid payload");
|
|
600
|
+
}
|
|
601
|
+
prepareUpdate(payload) {
|
|
602
|
+
const v = this.getValidator("insert");
|
|
603
|
+
if (v.validate(payload)) {
|
|
604
|
+
const data = { ...payload };
|
|
605
|
+
data._id = this.prepareId(data._id);
|
|
606
|
+
return data;
|
|
607
|
+
}
|
|
608
|
+
throw new Error("Invalid payload");
|
|
609
|
+
}
|
|
610
|
+
preparePatch(payload) {
|
|
611
|
+
const v = this.getValidator("patch");
|
|
612
|
+
if (v.validate(payload)) return { $set: this._flattenPayload(payload) };
|
|
613
|
+
throw new Error("Invalid payload");
|
|
614
|
+
}
|
|
615
|
+
_flattenPayload(payload, prefix = "", obj = {}) {
|
|
616
|
+
const evalKey = (k) => prefix ? `${prefix}.${k}` : k;
|
|
617
|
+
for (const [_key, value] of Object.entries(payload)) {
|
|
618
|
+
const key = evalKey(_key);
|
|
619
|
+
if (typeof value === "object" && this.flatMap.get(key)?.metadata?.get("mongo.patch.strategy") === "merge") this._flattenPayload(value, key, obj);
|
|
620
|
+
else obj[key] = value;
|
|
621
|
+
}
|
|
622
|
+
return obj;
|
|
623
|
+
}
|
|
505
624
|
constructor(asMongo, _type, logger = NoopLogger) {
|
|
506
625
|
_define_property$1(this, "asMongo", void 0);
|
|
507
626
|
_define_property$1(this, "_type", void 0);
|
|
508
627
|
_define_property$1(this, "logger", void 0);
|
|
509
628
|
_define_property$1(this, "name", void 0);
|
|
510
629
|
_define_property$1(this, "collection", void 0);
|
|
630
|
+
_define_property$1(this, "validators", void 0);
|
|
511
631
|
_define_property$1(this, "_indexes", void 0);
|
|
512
632
|
_define_property$1(this, "_vectorFilters", void 0);
|
|
513
633
|
_define_property$1(this, "_flatMap", void 0);
|
|
514
634
|
this.asMongo = asMongo;
|
|
515
635
|
this._type = _type;
|
|
516
636
|
this.logger = logger;
|
|
637
|
+
this.validators = new Map();
|
|
517
638
|
this._indexes = new Map();
|
|
518
639
|
this._vectorFilters = new Map();
|
|
519
640
|
if (!(0, __atscript_typescript.isAnnotatedType)(_type)) throw new Error("Atscript Annotated Type expected");
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TAtscriptPlugin } from '@atscript/core';
|
|
2
2
|
import { TAtscriptAnnotatedTypeConstructor, TAtscriptAnnotatedType, TAtscriptTypeObject, TMetadataMap } from '@atscript/typescript';
|
|
3
3
|
import * as mongodb from 'mongodb';
|
|
4
|
-
import { MongoClient, Collection } from 'mongodb';
|
|
4
|
+
import { MongoClient, Collection, ObjectId, WithId, UpdateFilter, MatchKeysAndValues } from 'mongodb';
|
|
5
5
|
|
|
6
6
|
declare const MongoPlugin: () => TAtscriptPlugin;
|
|
7
7
|
|
|
@@ -34,30 +34,39 @@ type TSearchIndex = {
|
|
|
34
34
|
definition: TMongoSearchIndexDefinition;
|
|
35
35
|
};
|
|
36
36
|
type TIndex = TPlainIndex | TSearchIndex;
|
|
37
|
+
type TValidatorPurpose = 'insert' | 'update' | 'patch';
|
|
37
38
|
declare class AsCollection<T extends TAtscriptAnnotatedTypeConstructor> {
|
|
38
39
|
protected readonly asMongo: AsMongo;
|
|
39
40
|
protected readonly _type: T;
|
|
40
41
|
protected readonly logger: TGenericLogger;
|
|
41
42
|
readonly name: string;
|
|
42
43
|
readonly collection: Collection<InstanceType<T>>;
|
|
44
|
+
protected readonly validators: Map<TValidatorPurpose, Validator<T>>;
|
|
45
|
+
protected _indexes: Map<string, TIndex>;
|
|
46
|
+
protected _vectorFilters: Map<string, string>;
|
|
47
|
+
protected _flatMap?: Map<string, TAtscriptAnnotatedType>;
|
|
43
48
|
constructor(asMongo: AsMongo, _type: T, logger?: TGenericLogger);
|
|
44
49
|
exists(): Promise<boolean>;
|
|
45
50
|
ensureExists(): Promise<void>;
|
|
51
|
+
get idType(): 'string' | 'number' | 'objectId';
|
|
52
|
+
prepareId<D = string | number | ObjectId>(id: string | number | ObjectId): D;
|
|
53
|
+
getValidator(purpose: TValidatorPurpose): any;
|
|
46
54
|
get type(): TAtscriptAnnotatedType<TAtscriptTypeObject>;
|
|
47
|
-
protected _indexes: Map<string, TIndex>;
|
|
48
|
-
protected _vectorFilters: Map<string, string>;
|
|
49
55
|
get indexes(): Map<string, TIndex>;
|
|
50
56
|
protected _addIndexField(type: TPlainIndex['type'], name: string, field: string, weight?: number): void;
|
|
51
57
|
protected _setSearchIndex(type: TSearchIndex['type'], name: string | undefined, definition: TMongoSearchIndexDefinition): void;
|
|
52
58
|
protected _addFieldToSearchIndex(type: TSearchIndex['type'], _name: string | undefined, fieldName: string, analyzer?: string): void;
|
|
53
|
-
protected _flatMap?: Map<string, TAtscriptAnnotatedType>;
|
|
54
59
|
protected _flattenType(type: TAtscriptAnnotatedType, prefix?: string): void;
|
|
55
60
|
protected _prepareIndexesForCollection(): void;
|
|
56
61
|
protected _finalizeIndexesForCollection(): void;
|
|
57
62
|
protected _prepareIndexesForField(fieldName: string, metadata: TMetadataMap<AtscriptMetadata>): void;
|
|
58
63
|
protected _flatten(): void;
|
|
59
|
-
get flatMap(): Map<string, TAtscriptAnnotatedType
|
|
64
|
+
get flatMap(): Map<string, TAtscriptAnnotatedType>;
|
|
60
65
|
syncIndexes(): Promise<void>;
|
|
66
|
+
prepareInsert(payload: any): InstanceType<T>;
|
|
67
|
+
prepareUpdate(payload: any): WithId<InstanceType<T>>;
|
|
68
|
+
preparePatch(payload: any): UpdateFilter<InstanceType<T>>;
|
|
69
|
+
protected _flattenPayload(payload: T, prefix?: string, obj?: MatchKeysAndValues<InstanceType<T>>): MatchKeysAndValues<InstanceType<T>>;
|
|
61
70
|
}
|
|
62
71
|
type TVectorSimilarity = 'cosine' | 'euclidean' | 'dotProduct';
|
|
63
72
|
type TMongoSearchIndexDefinition = {
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AnnotationSpec, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
|
|
1
|
+
import { AnnotationSpec, isArray, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
|
|
2
2
|
import { isAnnotatedType } from "@atscript/typescript";
|
|
3
|
-
import { MongoClient } from "mongodb";
|
|
3
|
+
import { MongoClient, ObjectId } from "mongodb";
|
|
4
4
|
|
|
5
5
|
//#region packages/mongo/src/plugin/primitives.ts
|
|
6
6
|
const primitives = { mongo: { extensions: {
|
|
@@ -226,7 +226,35 @@ const annotations = { mongo: {
|
|
|
226
226
|
description: "The **name of the vector search index** this field should be used as a filter for."
|
|
227
227
|
}]
|
|
228
228
|
})
|
|
229
|
-
}
|
|
229
|
+
},
|
|
230
|
+
patch: { strategy: new AnnotationSpec({
|
|
231
|
+
description: "Defines the **patching strategy** for updating MongoDB documents.\n\n- **\"replace\"** → The field or object will be **fully replaced**.\n- **\"merge\"** → The field or object will be **merged recursively** (applies only to objects, not arrays).\n\n**Example:**\n```atscript\n@mongo.patch.strategy \"merge\"\nsettings: {\n notifications: boolean\n preferences: {\n theme: string\n }\n}\n```\n",
|
|
232
|
+
nodeType: ["prop"],
|
|
233
|
+
multiple: false,
|
|
234
|
+
argument: {
|
|
235
|
+
name: "strategy",
|
|
236
|
+
type: "string",
|
|
237
|
+
description: "The **patch strategy** for this field: `\"replace\"` (default) or `\"merge\"`.",
|
|
238
|
+
values: ["replace", "merge"]
|
|
239
|
+
},
|
|
240
|
+
validate(token, args, doc) {
|
|
241
|
+
const field = token.parentNode;
|
|
242
|
+
const errors = [];
|
|
243
|
+
const definition = field.getDefinition();
|
|
244
|
+
if (!definition) return errors;
|
|
245
|
+
let wrongType = false;
|
|
246
|
+
if (isRef(definition)) {
|
|
247
|
+
const def = doc.unwindType(definition.id, definition.chain)?.def;
|
|
248
|
+
if (!isStructure(def) && !isInterface(def) && !isArray(def)) wrongType = true;
|
|
249
|
+
} else if (!isStructure(definition) && !isInterface(definition) && !isArray(definition)) wrongType = true;
|
|
250
|
+
if (wrongType) errors.push({
|
|
251
|
+
message: `[mongo] type of object or array expected when using @mongo.patch.strategy`,
|
|
252
|
+
severity: 1,
|
|
253
|
+
range: token.range
|
|
254
|
+
});
|
|
255
|
+
return errors;
|
|
256
|
+
}
|
|
257
|
+
}) }
|
|
230
258
|
} };
|
|
231
259
|
|
|
232
260
|
//#endregion
|
|
@@ -265,9 +293,14 @@ function _define_property$1(obj, key, value) {
|
|
|
265
293
|
else obj[key] = value;
|
|
266
294
|
return obj;
|
|
267
295
|
}
|
|
268
|
-
const INDEX_PREFIX = "
|
|
296
|
+
const INDEX_PREFIX = "atscript__";
|
|
269
297
|
const DEFAULT_INDEX_NAME = "DEFAULT";
|
|
270
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Generates a key for mongo index
|
|
300
|
+
* @param type index type
|
|
301
|
+
* @param name index name
|
|
302
|
+
* @returns index key
|
|
303
|
+
*/ function indexKey(type, name) {
|
|
271
304
|
const cleanName = name.replace(/[^a-z0-9_.-]/gi, "_").replace(/_+/g, "_").slice(0, 127 - INDEX_PREFIX.length - type.length - 2);
|
|
272
305
|
return `${INDEX_PREFIX}${type}__${cleanName}`;
|
|
273
306
|
}
|
|
@@ -279,6 +312,57 @@ var AsCollection = class {
|
|
|
279
312
|
const exists = await this.exists();
|
|
280
313
|
if (!exists) await this.asMongo.db.createCollection(this.name, { comment: "Created by Atscript Mongo Collection" });
|
|
281
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Returns the a type definition of the "_id" prop.
|
|
317
|
+
*/ get idType() {
|
|
318
|
+
const idProp = this.type.type.props.get("_id");
|
|
319
|
+
const idTags = idProp?.type.tags;
|
|
320
|
+
if (idTags?.has("objectId") && idTags?.has("mongo")) return "objectId";
|
|
321
|
+
if (idProp?.type.kind === "") return idProp.type.designType;
|
|
322
|
+
return "objectId";
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Transforms an "_id" value to the expected type (`ObjectId`, `number`, or `string`).
|
|
326
|
+
* Assumes input has already been validated.
|
|
327
|
+
*
|
|
328
|
+
* @param {string | number | ObjectId} id - The validated ID.
|
|
329
|
+
* @returns {string | number | ObjectId} - The transformed ID.
|
|
330
|
+
* @throws {Error} If the `_id` type is unknown.
|
|
331
|
+
*/ prepareId(id) {
|
|
332
|
+
switch (this.idType) {
|
|
333
|
+
case "objectId": return id instanceof ObjectId ? id : new ObjectId(id);
|
|
334
|
+
case "number": return Number(id);
|
|
335
|
+
case "string": return String(id);
|
|
336
|
+
default: throw new Error("Unknown \"_id\" type");
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Retrieves a validator for a given purpose. If the validator is not already cached,
|
|
341
|
+
* it creates and stores a new one based on the purpose.
|
|
342
|
+
*
|
|
343
|
+
* @param {TValidatorPurpose} purpose - The validation purpose (`input`, `update`, `patch`).
|
|
344
|
+
* @returns {Validator} The corresponding validator instance.
|
|
345
|
+
* @throws {Error} If an unknown purpose is provided.
|
|
346
|
+
*/ getValidator(purpose) {
|
|
347
|
+
if (!this.validators.has(purpose)) switch (purpose) {
|
|
348
|
+
case "insert": {
|
|
349
|
+
this.validators.set(purpose, this.type.validator(this.idType === "objectId" ? { skipList: new Set(["_id"]) } : {}));
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
case "update": {
|
|
353
|
+
this.validators.set(purpose, this.type.validator());
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case "patch": {
|
|
357
|
+
this.validators.set(purpose, this.type.validator({ partial: (def, path) => {
|
|
358
|
+
return path === "" || def.metadata.get("mongo.patch.strategy") === "merge";
|
|
359
|
+
} }));
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
default: throw new Error(`Unknown validator purpose: ${purpose}`);
|
|
363
|
+
}
|
|
364
|
+
return this.validators.get(purpose);
|
|
365
|
+
}
|
|
282
366
|
get type() {
|
|
283
367
|
return this._type;
|
|
284
368
|
}
|
|
@@ -326,11 +410,13 @@ else {
|
|
|
326
410
|
_flattenType(type, prefix) {
|
|
327
411
|
switch (type.type.kind) {
|
|
328
412
|
case "object":
|
|
413
|
+
this._flatMap?.set(prefix || "", type);
|
|
329
414
|
const items = Array.from(type.type.props.entries());
|
|
330
415
|
for (const [key, value] of items) this._flattenType(value, prefix ? `${prefix}.${key}` : key);
|
|
331
416
|
break;
|
|
332
417
|
case "array":
|
|
333
|
-
this.
|
|
418
|
+
this._flatMap?.set(prefix || "", type);
|
|
419
|
+
if (type.type.of.type.kind) this._flattenType(type.type.of, prefix);
|
|
334
420
|
break;
|
|
335
421
|
case "intersection":
|
|
336
422
|
case "tuple":
|
|
@@ -478,18 +564,53 @@ else toUpdate.add(remote.name);
|
|
|
478
564
|
default:
|
|
479
565
|
}
|
|
480
566
|
}
|
|
567
|
+
prepareInsert(payload) {
|
|
568
|
+
const v = this.getValidator("insert");
|
|
569
|
+
if (v.validate(payload)) {
|
|
570
|
+
const data = { ...payload };
|
|
571
|
+
if (data._id) data._id = this.prepareId(data._id);
|
|
572
|
+
else if (this.idType !== "objectId") throw new Error("Missing \"_id\" field");
|
|
573
|
+
return data;
|
|
574
|
+
}
|
|
575
|
+
throw new Error("Invalid payload");
|
|
576
|
+
}
|
|
577
|
+
prepareUpdate(payload) {
|
|
578
|
+
const v = this.getValidator("insert");
|
|
579
|
+
if (v.validate(payload)) {
|
|
580
|
+
const data = { ...payload };
|
|
581
|
+
data._id = this.prepareId(data._id);
|
|
582
|
+
return data;
|
|
583
|
+
}
|
|
584
|
+
throw new Error("Invalid payload");
|
|
585
|
+
}
|
|
586
|
+
preparePatch(payload) {
|
|
587
|
+
const v = this.getValidator("patch");
|
|
588
|
+
if (v.validate(payload)) return { $set: this._flattenPayload(payload) };
|
|
589
|
+
throw new Error("Invalid payload");
|
|
590
|
+
}
|
|
591
|
+
_flattenPayload(payload, prefix = "", obj = {}) {
|
|
592
|
+
const evalKey = (k) => prefix ? `${prefix}.${k}` : k;
|
|
593
|
+
for (const [_key, value] of Object.entries(payload)) {
|
|
594
|
+
const key = evalKey(_key);
|
|
595
|
+
if (typeof value === "object" && this.flatMap.get(key)?.metadata?.get("mongo.patch.strategy") === "merge") this._flattenPayload(value, key, obj);
|
|
596
|
+
else obj[key] = value;
|
|
597
|
+
}
|
|
598
|
+
return obj;
|
|
599
|
+
}
|
|
481
600
|
constructor(asMongo, _type, logger = NoopLogger) {
|
|
482
601
|
_define_property$1(this, "asMongo", void 0);
|
|
483
602
|
_define_property$1(this, "_type", void 0);
|
|
484
603
|
_define_property$1(this, "logger", void 0);
|
|
485
604
|
_define_property$1(this, "name", void 0);
|
|
486
605
|
_define_property$1(this, "collection", void 0);
|
|
606
|
+
_define_property$1(this, "validators", void 0);
|
|
487
607
|
_define_property$1(this, "_indexes", void 0);
|
|
488
608
|
_define_property$1(this, "_vectorFilters", void 0);
|
|
489
609
|
_define_property$1(this, "_flatMap", void 0);
|
|
490
610
|
this.asMongo = asMongo;
|
|
491
611
|
this._type = _type;
|
|
492
612
|
this.logger = logger;
|
|
613
|
+
this.validators = new Map();
|
|
493
614
|
this._indexes = new Map();
|
|
494
615
|
this._vectorFilters = new Map();
|
|
495
616
|
if (!isAnnotatedType(_type)) throw new Error("Atscript Annotated Type expected");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/mongo",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "Mongodb plugin for atscript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"license": "ISC",
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"mongodb": "^6.13.0",
|
|
38
|
-
"@atscript/core": "^0.0.
|
|
39
|
-
"@atscript/typescript": "^0.0.
|
|
38
|
+
"@atscript/core": "^0.0.17",
|
|
39
|
+
"@atscript/typescript": "^0.0.17"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"vitest": "^3.0.0"
|