@atscript/mongo 0.1.27 → 0.1.28
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 +63 -82
- package/dist/index.mjs +63 -82
- package/package.json +11 -5
- package/scripts/setup-skills.js +78 -0
- package/skills/atscript-mongo/.gitkeep +0 -0
- package/skills/atscript-mongo/SKILL.md +45 -0
- package/skills/atscript-mongo/annotations.md +168 -0
- package/skills/atscript-mongo/collections.md +141 -0
- package/skills/atscript-mongo/core.md +83 -0
- package/skills/atscript-mongo/patches.md +205 -0
package/dist/index.cjs
CHANGED
|
@@ -43,15 +43,10 @@ const analyzers = [
|
|
|
43
43
|
"lucene.russian",
|
|
44
44
|
"lucene.arabic"
|
|
45
45
|
];
|
|
46
|
-
const annotations = {
|
|
46
|
+
const annotations = {
|
|
47
47
|
collection: new __atscript_core.AnnotationSpec({
|
|
48
|
-
description: "
|
|
48
|
+
description: "Marks an interface as a **MongoDB collection**.\n\n- Use together with `@db.table \"name\"` which provides the collection name.\n- Automatically injects a **non-optional** `_id` field if not explicitly defined.\n- `_id` must be of type **`string`**, **`number`**, or **`mongo.objectId`**.\n\n**Example:**\n```atscript\n@db.table \"users\"\n@db.mongo.collection\nexport interface User {\n _id: mongo.objectId\n email: string.email\n}\n```\n",
|
|
49
49
|
nodeType: ["interface"],
|
|
50
|
-
argument: {
|
|
51
|
-
name: "name",
|
|
52
|
-
type: "string",
|
|
53
|
-
description: "The **name of the MongoDB collection**."
|
|
54
|
-
},
|
|
55
50
|
validate(token, args, doc) {
|
|
56
51
|
const parent = token.parentNode;
|
|
57
52
|
const struc = parent?.getDefinition();
|
|
@@ -60,7 +55,7 @@ const annotations = { mongo: {
|
|
|
60
55
|
const _id = parent.props.get("_id");
|
|
61
56
|
const isOptional = !!_id.token("optional");
|
|
62
57
|
if (isOptional) errors.push({
|
|
63
|
-
message: `[mongo] _id can't be optional in Mongo Collection`,
|
|
58
|
+
message: `[db.mongo] _id can't be optional in Mongo Collection`,
|
|
64
59
|
severity: 1,
|
|
65
60
|
range: _id.token("identifier").range
|
|
66
61
|
});
|
|
@@ -72,7 +67,7 @@ const annotations = { mongo: {
|
|
|
72
67
|
if ((0, __atscript_core.isPrimitive)(def) && !["string", "number"].includes(def.config.type)) wrongType = true;
|
|
73
68
|
} else wrongType = true;
|
|
74
69
|
if (wrongType) errors.push({
|
|
75
|
-
message: `[mongo] _id must be of type string, number or mongo.objectId`,
|
|
70
|
+
message: `[db.mongo] _id must be of type string, number or mongo.objectId`,
|
|
76
71
|
severity: 1,
|
|
77
72
|
range: _id.token("identifier").range
|
|
78
73
|
});
|
|
@@ -98,43 +93,19 @@ const annotations = { mongo: {
|
|
|
98
93
|
description: "On/Off the automatic index creation"
|
|
99
94
|
}
|
|
100
95
|
}),
|
|
101
|
-
index: {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
}),
|
|
113
|
-
unique: new __atscript_core.AnnotationSpec({
|
|
114
|
-
description: "Creates a **unique index** on a field to ensure no duplicate values exist.\n\n- Enforces uniqueness at the database level.\n- Automatically prevents duplicate entries.\n- Typically used for **emails, usernames, and IDs**.\n\n**Example:**\n```atscript\n@mongo.index.unique \"uniqueEmailIndex\"\nemail: string.email\n```\n",
|
|
115
|
-
multiple: true,
|
|
116
|
-
nodeType: ["prop"],
|
|
117
|
-
argument: {
|
|
118
|
-
optional: true,
|
|
119
|
-
name: "indexName",
|
|
120
|
-
type: "string",
|
|
121
|
-
description: "The **name of the unique index** (optional). If omitted, property name is used."
|
|
122
|
-
}
|
|
123
|
-
}),
|
|
124
|
-
text: new __atscript_core.AnnotationSpec({
|
|
125
|
-
description: "Creates a **legacy MongoDB text index** for full-text search.\n\n**⚠ WARNING:** *Text indexes slow down database operations. Use `@mongo.defineTextSearch` instead for better performance.*\n\n- Allows **basic full-text search** on a field.\n- Does **not support fuzzy matching or ranking**.\n- **Replaced by MongoDB Atlas Search Indexes (`@mongo.searchIndex.text`).**\n\n**Example:**\n```atscript\n@mongo.index.text 5\nbio: string\n```\n",
|
|
126
|
-
nodeType: ["prop"],
|
|
127
|
-
argument: {
|
|
128
|
-
optional: true,
|
|
129
|
-
name: "weight",
|
|
130
|
-
type: "number",
|
|
131
|
-
description: "Field importance in search results (higher = more relevant). Defaults to `1`."
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
},
|
|
96
|
+
index: { text: new __atscript_core.AnnotationSpec({
|
|
97
|
+
description: "Creates a **legacy MongoDB text index** for full-text search with optional **weight** specification.\n\nUse this when you need per-field weight control. For simple full-text indexing without weights, use the generic `@db.index.fulltext` instead.\n\n**Example:**\n```atscript\n@db.mongo.index.text 5\nbio: string\n```\n",
|
|
98
|
+
nodeType: ["prop"],
|
|
99
|
+
argument: {
|
|
100
|
+
optional: true,
|
|
101
|
+
name: "weight",
|
|
102
|
+
type: "number",
|
|
103
|
+
description: "Field importance in search results (higher = more relevant). Defaults to `1`."
|
|
104
|
+
}
|
|
105
|
+
}) },
|
|
135
106
|
search: {
|
|
136
107
|
dynamic: new __atscript_core.AnnotationSpec({
|
|
137
|
-
description: "Creates a **dynamic MongoDB Search Index** that applies to the entire collection.\n\n- **Indexes all text fields automatically** (no need to specify fields).\n- Supports **language analyzers** for text tokenization.\n- Enables **fuzzy search** (typo tolerance) if needed.\n\n**Example:**\n```atscript\n@mongo.search.dynamic \"lucene.english\", 1\nexport interface MongoCollection {}\n```\n",
|
|
108
|
+
description: "Creates a **dynamic MongoDB Search Index** that applies to the entire collection.\n\n- **Indexes all text fields automatically** (no need to specify fields).\n- Supports **language analyzers** for text tokenization.\n- Enables **fuzzy search** (typo tolerance) if needed.\n\n**Example:**\n```atscript\n@db.mongo.search.dynamic \"lucene.english\", 1\nexport interface MongoCollection {}\n```\n",
|
|
138
109
|
nodeType: ["interface"],
|
|
139
110
|
multiple: false,
|
|
140
111
|
argument: [{
|
|
@@ -151,7 +122,7 @@ const annotations = { mongo: {
|
|
|
151
122
|
}]
|
|
152
123
|
}),
|
|
153
124
|
static: new __atscript_core.AnnotationSpec({
|
|
154
|
-
description: "Defines a **MongoDB Atlas Search Index** for the collection. The props can refer to this index using `@mongo.search.text` annotation.\n\n- **Creates a named search index** for full-text search.\n- **Specify analyzers and fuzzy search** behavior at the index level.\n- **Fields must explicitly use `@mongo.
|
|
125
|
+
description: "Defines a **MongoDB Atlas Search Index** for the collection. The props can refer to this index using `@db.mongo.search.text` annotation.\n\n- **Creates a named search index** for full-text search.\n- **Specify analyzers and fuzzy search** behavior at the index level.\n- **Fields must explicitly use `@db.mongo.search.text`** to be included in this search index.\n\n**Example:**\n```atscript\n@db.mongo.search.static \"lucene.english\", 1, \"mySearchIndex\"\nexport interface MongoCollection {}\n```\n",
|
|
155
126
|
nodeType: ["interface"],
|
|
156
127
|
multiple: true,
|
|
157
128
|
argument: [
|
|
@@ -172,12 +143,12 @@ const annotations = { mongo: {
|
|
|
172
143
|
optional: true,
|
|
173
144
|
name: "indexName",
|
|
174
145
|
type: "string",
|
|
175
|
-
description: "The name of the search index. Fields must reference this name using `@mongo.search.text`. If not set, defaults to `\"DEFAULT\"`."
|
|
146
|
+
description: "The name of the search index. Fields must reference this name using `@db.mongo.search.text`. If not set, defaults to `\"DEFAULT\"`."
|
|
176
147
|
}
|
|
177
148
|
]
|
|
178
149
|
}),
|
|
179
150
|
text: new __atscript_core.AnnotationSpec({
|
|
180
|
-
description: "Marks a field to be **included in a MongoDB Atlas Search Index** defined by `@mongo.search.static`.\n\n- **The field has to reference an existing search index name**.\n- If index name is not defined, a new search index with default attributes will be created.\n\n**Example:**\n```atscript\n@mongo.search.text \"lucene.english\", \"mySearchIndex\"\nfirstName: string\n```\n",
|
|
151
|
+
description: "Marks a field to be **included in a MongoDB Atlas Search Index** defined by `@db.mongo.search.static`.\n\n- **The field has to reference an existing search index name**.\n- If index name is not defined, a new search index with default attributes will be created.\n\n**Example:**\n```atscript\n@db.mongo.search.text \"lucene.english\", \"mySearchIndex\"\nfirstName: string\n```\n",
|
|
181
152
|
nodeType: ["prop"],
|
|
182
153
|
multiple: true,
|
|
183
154
|
argument: [{
|
|
@@ -190,11 +161,11 @@ const annotations = { mongo: {
|
|
|
190
161
|
optional: true,
|
|
191
162
|
name: "indexName",
|
|
192
163
|
type: "string",
|
|
193
|
-
description: "The **name of the search index** defined in `@mongo.
|
|
164
|
+
description: "The **name of the search index** defined in `@db.mongo.search.static`. This links the field to the correct index. If not set, defaults to `\"DEFAULT\"`."
|
|
194
165
|
}]
|
|
195
166
|
}),
|
|
196
167
|
vector: new __atscript_core.AnnotationSpec({
|
|
197
|
-
description: "Creates a **MongoDB Vector Search Index** for **semantic search, embeddings, and AI-powered search**.\n\n- Each field that stores vector embeddings **must define its own vector index**.\n- Supports **cosine similarity, Euclidean distance, and dot product similarity**.\n- Vector fields must be an **array of numbers**.\n\n**Example:**\n```atscript\n@mongo.search.vector 512, \"cosine\"\nembedding: mongo.vector\n```\n",
|
|
168
|
+
description: "Creates a **MongoDB Vector Search Index** for **semantic search, embeddings, and AI-powered search**.\n\n- Each field that stores vector embeddings **must define its own vector index**.\n- Supports **cosine similarity, Euclidean distance, and dot product similarity**.\n- Vector fields must be an **array of numbers**.\n\n**Example:**\n```atscript\n@db.mongo.search.vector 512, \"cosine\"\nembedding: mongo.vector\n```\n",
|
|
198
169
|
nodeType: ["prop"],
|
|
199
170
|
multiple: false,
|
|
200
171
|
argument: [
|
|
@@ -232,7 +203,7 @@ const annotations = { mongo: {
|
|
|
232
203
|
]
|
|
233
204
|
}),
|
|
234
205
|
filter: new __atscript_core.AnnotationSpec({
|
|
235
|
-
description: "Assigns a field as a **filter field** for a **MongoDB Vector Search Index**.\n\n- The assigned field **must be indexed** for efficient filtering.\n- Filters allow vector search queries to return results **only within a specific category, user group, or tag**.\n- The vector index must be defined using `@mongo.search.vector`.\n\n**Example:**\n```atscript\n@mongo.search.vector 512, \"cosine\"\nembedding: number[]\n\n@mongo.search.filter \"embedding\"\ncategory: string\n```\n",
|
|
206
|
+
description: "Assigns a field as a **filter field** for a **MongoDB Vector Search Index**.\n\n- The assigned field **must be indexed** for efficient filtering.\n- Filters allow vector search queries to return results **only within a specific category, user group, or tag**.\n- The vector index must be defined using `@db.mongo.search.vector`.\n\n**Example:**\n```atscript\n@db.mongo.search.vector 512, \"cosine\"\nembedding: number[]\n\n@db.mongo.search.filter \"embedding\"\ncategory: string\n```\n",
|
|
236
207
|
nodeType: ["prop"],
|
|
237
208
|
multiple: true,
|
|
238
209
|
argument: [{
|
|
@@ -244,7 +215,7 @@ const annotations = { mongo: {
|
|
|
244
215
|
})
|
|
245
216
|
},
|
|
246
217
|
patch: { strategy: new __atscript_core.AnnotationSpec({
|
|
247
|
-
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",
|
|
218
|
+
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@db.mongo.patch.strategy \"merge\"\nsettings: {\n notifications: boolean\n preferences: {\n theme: string\n }\n}\n```\n",
|
|
248
219
|
nodeType: ["prop"],
|
|
249
220
|
multiple: false,
|
|
250
221
|
argument: {
|
|
@@ -264,7 +235,7 @@ const annotations = { mongo: {
|
|
|
264
235
|
if (!(0, __atscript_core.isStructure)(def) && !(0, __atscript_core.isInterface)(def) && !(0, __atscript_core.isArray)(def)) wrongType = true;
|
|
265
236
|
} else if (!(0, __atscript_core.isStructure)(definition) && !(0, __atscript_core.isInterface)(definition) && !(0, __atscript_core.isArray)(definition)) wrongType = true;
|
|
266
237
|
if (wrongType) errors.push({
|
|
267
|
-
message: `[mongo] type of object or array expected when using @mongo.patch.strategy`,
|
|
238
|
+
message: `[db.mongo] type of object or array expected when using @db.mongo.patch.strategy`,
|
|
268
239
|
severity: 1,
|
|
269
240
|
range: token.range
|
|
270
241
|
});
|
|
@@ -272,7 +243,7 @@ const annotations = { mongo: {
|
|
|
272
243
|
}
|
|
273
244
|
}) },
|
|
274
245
|
array: { uniqueItems: new __atscript_core.AnnotationSpec({
|
|
275
|
-
description: "Marks an **array field** as containing *globally unique items* when handling **patch `$insert` operations**.\n\n- Forces the patcher to use **set-semantics** (`$setUnion`) instead of a plain append, so duplicates are silently skipped.\n- Has **no effect** on `$replace`, `$update`, or `$remove`.\n- If the array
|
|
246
|
+
description: "Marks an **array field** as containing *globally unique items* when handling **patch `$insert` operations**.\n\n- Forces the patcher to use **set-semantics** (`$setUnion`) instead of a plain append, so duplicates are silently skipped.\n- Has **no effect** on `$replace`, `$update`, or `$remove`.\n- If the array's element type already defines one or more `@expect.array.key` properties, *uniqueness is implied* and this annotation is unnecessary (but harmless).\n\n**Example:**\n```atscript\n@db.mongo.array.uniqueItems\ntags: string[]\n\n// Later in a patch payload …\n{\n $insert: {\n tags: [\"mongo\", \"mongo\"] // second \"mongo\" is ignored\n }\n}\n```\n",
|
|
276
247
|
nodeType: ["prop"],
|
|
277
248
|
multiple: false,
|
|
278
249
|
validate(token, args, doc) {
|
|
@@ -286,14 +257,14 @@ const annotations = { mongo: {
|
|
|
286
257
|
if (!(0, __atscript_core.isArray)(def)) wrongType = true;
|
|
287
258
|
} else if (!(0, __atscript_core.isArray)(definition)) wrongType = true;
|
|
288
259
|
if (wrongType) errors.push({
|
|
289
|
-
message: `[mongo] type of array expected when using @mongo.array.uniqueItems`,
|
|
260
|
+
message: `[db.mongo] type of array expected when using @db.mongo.array.uniqueItems`,
|
|
290
261
|
severity: 1,
|
|
291
262
|
range: token.range
|
|
292
263
|
});
|
|
293
264
|
return errors;
|
|
294
265
|
}
|
|
295
266
|
}) }
|
|
296
|
-
}
|
|
267
|
+
};
|
|
297
268
|
|
|
298
269
|
//#endregion
|
|
299
270
|
//#region packages/mongo/src/plugin/primitives.ts
|
|
@@ -301,7 +272,7 @@ const primitives = { mongo: { extensions: {
|
|
|
301
272
|
objectId: {
|
|
302
273
|
type: "string",
|
|
303
274
|
documentation: "Represents a **MongoDB ObjectId**.\n\n- Stored as a **string** but can be converted to an ObjectId at runtime.\n- Useful for handling `_id` fields and queries that require ObjectId conversion.\n- Automatically converts string `_id` values into **MongoDB ObjectId** when needed.\n\n**Example:**\n```atscript\nuserId: mongo.objectId\n```\n",
|
|
304
|
-
expect: { pattern:
|
|
275
|
+
annotations: { "expect.pattern": { pattern: "^[a-fA-F0-9]{24}$" } }
|
|
305
276
|
},
|
|
306
277
|
vector: {
|
|
307
278
|
type: {
|
|
@@ -319,7 +290,7 @@ const MongoPlugin = () => ({
|
|
|
319
290
|
config() {
|
|
320
291
|
return {
|
|
321
292
|
primitives,
|
|
322
|
-
annotations
|
|
293
|
+
annotations: { db: { mongo: annotations } }
|
|
323
294
|
};
|
|
324
295
|
}
|
|
325
296
|
});
|
|
@@ -330,7 +301,7 @@ const validateMongoIdPlugin = (ctx, def, value) => {
|
|
|
330
301
|
if (ctx.path === "_id" && def.type.tags.has("objectId")) return ctx.validateAnnotatedType(def, value instanceof mongodb.ObjectId ? value.toString() : value);
|
|
331
302
|
};
|
|
332
303
|
const validateMongoUniqueArrayItemsPlugin = (ctx, def, value) => {
|
|
333
|
-
if (def.metadata.has("mongo.array.uniqueItems") && def.type.kind === "array") {
|
|
304
|
+
if (def.metadata.has("db.mongo.array.uniqueItems") && def.type.kind === "array") {
|
|
334
305
|
if (Array.isArray(value)) {
|
|
335
306
|
const separator = "▼↩";
|
|
336
307
|
const seen = new Set();
|
|
@@ -364,7 +335,7 @@ else obj[key] = value;
|
|
|
364
335
|
}
|
|
365
336
|
var CollectionPatcher = class CollectionPatcher {
|
|
366
337
|
/**
|
|
367
|
-
* Extract a set of *key properties* (annotated with `@
|
|
338
|
+
* Extract a set of *key properties* (annotated with `@expect.array.key`) from an
|
|
368
339
|
* array‐of‐objects type definition. These keys uniquely identify an element
|
|
369
340
|
* inside the array and are later used for `$update`, `$remove` and `$upsert`.
|
|
370
341
|
*
|
|
@@ -374,7 +345,7 @@ var CollectionPatcher = class CollectionPatcher {
|
|
|
374
345
|
if (def.type.of.type.kind === "object") {
|
|
375
346
|
const objType = def.type.of.type;
|
|
376
347
|
const keyProps = new Set();
|
|
377
|
-
for (const [key, val] of objType.props.entries()) if (val.metadata.get("
|
|
348
|
+
for (const [key, val] of objType.props.entries()) if (val.metadata.get("expect.array.key")) keyProps.add(key);
|
|
378
349
|
return keyProps;
|
|
379
350
|
}
|
|
380
351
|
return new Set();
|
|
@@ -383,7 +354,7 @@ var CollectionPatcher = class CollectionPatcher {
|
|
|
383
354
|
* Build a runtime *Validator* that understands the extended patch payload.
|
|
384
355
|
*
|
|
385
356
|
* * Adds per‑array *patch* wrappers (the `$replace`, `$insert`, … fields).
|
|
386
|
-
* * Honors `mongo.patch.strategy === "merge"` metadata.
|
|
357
|
+
* * Honors `db.mongo.patch.strategy === "merge"` metadata.
|
|
387
358
|
*
|
|
388
359
|
* @param collection Target collection wrapper
|
|
389
360
|
* @returns Atscript Validator
|
|
@@ -396,12 +367,12 @@ var CollectionPatcher = class CollectionPatcher {
|
|
|
396
367
|
for (const [prop, type] of def.type.props.entries()) obj.prop(prop, (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(type).copyMetadata(type.metadata).optional(prop !== "_id").$type);
|
|
397
368
|
return obj.$type;
|
|
398
369
|
}
|
|
399
|
-
if (def.type.kind === "array" && collection.flatMap.get(path)?.metadata.get("mongo.__topLevelArray") && !def.metadata.has("mongo.__patchArrayValue")) {
|
|
370
|
+
if (def.type.kind === "array" && collection.flatMap.get(path)?.metadata.get("db.mongo.__topLevelArray") && !def.metadata.has("db.mongo.__patchArrayValue")) {
|
|
400
371
|
const defArray = def;
|
|
401
|
-
const mergeStrategy = defArray.metadata.get("mongo.patch.strategy") === "merge";
|
|
372
|
+
const mergeStrategy = defArray.metadata.get("db.mongo.patch.strategy") === "merge";
|
|
402
373
|
function getPatchType() {
|
|
403
374
|
const isPrimitive$1 = (0, __atscript_typescript_utils.isAnnotatedTypeOfPrimitive)(defArray.type.of);
|
|
404
|
-
if (isPrimitive$1) return (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(def).copyMetadata(def.metadata).annotate("mongo.__patchArrayValue").optional().$type;
|
|
375
|
+
if (isPrimitive$1) return (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(def).copyMetadata(def.metadata).annotate("db.mongo.__patchArrayValue").optional().$type;
|
|
405
376
|
if (defArray.type.of.type.kind === "object") {
|
|
406
377
|
const objType = defArray.type.of.type;
|
|
407
378
|
const t = (0, __atscript_typescript_utils.defineAnnotatedType)("object").copyMetadata(defArray.type.of.metadata);
|
|
@@ -409,17 +380,17 @@ var CollectionPatcher = class CollectionPatcher {
|
|
|
409
380
|
for (const [key, val] of objType.props.entries()) if (keyProps.size > 0) if (keyProps.has(key)) t.prop(key, (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(val).copyMetadata(def.metadata).$type);
|
|
410
381
|
else t.prop(key, (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(val).copyMetadata(def.metadata).optional().$type);
|
|
411
382
|
else t.prop(key, (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(val).copyMetadata(def.metadata).optional(!!val.optional).$type);
|
|
412
|
-
return (0, __atscript_typescript_utils.defineAnnotatedType)("array").of(t.$type).copyMetadata(def.metadata).annotate("mongo.__patchArrayValue").optional().$type;
|
|
383
|
+
return (0, __atscript_typescript_utils.defineAnnotatedType)("array").of(t.$type).copyMetadata(def.metadata).annotate("db.mongo.__patchArrayValue").optional().$type;
|
|
413
384
|
}
|
|
414
385
|
return undefined;
|
|
415
386
|
}
|
|
416
|
-
const fullType = (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(def).copyMetadata(def.metadata).annotate("mongo.__patchArrayValue").optional().$type;
|
|
387
|
+
const fullType = (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(def).copyMetadata(def.metadata).annotate("db.mongo.__patchArrayValue").optional().$type;
|
|
417
388
|
const patchType = getPatchType();
|
|
418
389
|
return patchType ? (0, __atscript_typescript_utils.defineAnnotatedType)("object").prop("$replace", fullType).prop("$insert", fullType).prop("$upsert", fullType).prop("$update", mergeStrategy ? patchType : fullType).prop("$remove", patchType).optional().$type : (0, __atscript_typescript_utils.defineAnnotatedType)("object").prop("$replace", fullType).prop("$insert", fullType).optional().$type;
|
|
419
390
|
}
|
|
420
391
|
return def;
|
|
421
392
|
},
|
|
422
|
-
partial: (def, path) => path !== "" && def.metadata.get("mongo.patch.strategy") === "merge"
|
|
393
|
+
partial: (def, path) => path !== "" && def.metadata.get("db.mongo.patch.strategy") === "merge"
|
|
423
394
|
});
|
|
424
395
|
}
|
|
425
396
|
/**
|
|
@@ -470,9 +441,9 @@ else t.prop(key, (0, __atscript_typescript_utils.defineAnnotatedType)().refTo(va
|
|
|
470
441
|
for (const [_key, value] of Object.entries(payload)) {
|
|
471
442
|
const key = evalKey(_key);
|
|
472
443
|
const flatType = this.collection.flatMap.get(key);
|
|
473
|
-
const topLevelArray = flatType?.metadata?.get("mongo.__topLevelArray");
|
|
444
|
+
const topLevelArray = flatType?.metadata?.get("db.mongo.__topLevelArray");
|
|
474
445
|
if (typeof value === "object" && topLevelArray) this.parseArrayPatch(key, value);
|
|
475
|
-
else if (typeof value === "object" && this.collection.flatMap.get(key)?.metadata?.get("mongo.patch.strategy") === "merge") this.flattenPayload(value, key);
|
|
446
|
+
else if (typeof value === "object" && this.collection.flatMap.get(key)?.metadata?.get("db.mongo.patch.strategy") === "merge") this.flattenPayload(value, key);
|
|
476
447
|
else if (key !== "_id") this._set(key, value);
|
|
477
448
|
}
|
|
478
449
|
return this.updatePipeline;
|
|
@@ -526,7 +497,7 @@ else if (key !== "_id") this._set(key, value);
|
|
|
526
497
|
* - unique / keyed → delegate to _upsert (insert-or-update)
|
|
527
498
|
*/ _insert(key, input, keyProps) {
|
|
528
499
|
if (!input?.length) return;
|
|
529
|
-
const uniqueItems = this.collection.flatMap.get(key)?.metadata?.has("mongo.array.uniqueItems");
|
|
500
|
+
const uniqueItems = this.collection.flatMap.get(key)?.metadata?.has("db.mongo.array.uniqueItems");
|
|
530
501
|
if (uniqueItems || keyProps.size > 0) this._upsert(key, input, keyProps);
|
|
531
502
|
else this._set(key, { $concatArrays: [{ $ifNull: [`$${key}`, []] }, input] });
|
|
532
503
|
}
|
|
@@ -564,7 +535,7 @@ else this._set(key, { $concatArrays: [{ $ifNull: [`$${key}`, []] }, input] });
|
|
|
564
535
|
*/ _update(key, input, keyProps) {
|
|
565
536
|
if (!input?.length) return;
|
|
566
537
|
if (keyProps.size > 0) {
|
|
567
|
-
const mergeStrategy = this.collection.flatMap.get(key)?.metadata?.get("mongo.patch.strategy") === "merge";
|
|
538
|
+
const mergeStrategy = this.collection.flatMap.get(key)?.metadata?.get("db.mongo.patch.strategy") === "merge";
|
|
568
539
|
const keys = [...keyProps];
|
|
569
540
|
this._set(key, { $reduce: {
|
|
570
541
|
input,
|
|
@@ -773,13 +744,13 @@ else {
|
|
|
773
744
|
}
|
|
774
745
|
_prepareIndexesForCollection() {
|
|
775
746
|
const typeMeta = this.type.metadata;
|
|
776
|
-
const dynamicText = typeMeta.get("mongo.search.dynamic");
|
|
747
|
+
const dynamicText = typeMeta.get("db.mongo.search.dynamic");
|
|
777
748
|
if (dynamicText) this._setSearchIndex("dynamic_text", "_", {
|
|
778
749
|
mappings: { dynamic: true },
|
|
779
750
|
analyzer: dynamicText.analyzer,
|
|
780
751
|
text: { fuzzy: { maxEdits: dynamicText.fuzzy || 0 } }
|
|
781
752
|
});
|
|
782
|
-
for (const textSearch of typeMeta.get("mongo.search.static") || []) this._setSearchIndex("search_text", textSearch.indexName, {
|
|
753
|
+
for (const textSearch of typeMeta.get("db.mongo.search.static") || []) this._setSearchIndex("search_text", textSearch.indexName, {
|
|
783
754
|
mappings: { fields: {} },
|
|
784
755
|
analyzer: textSearch.analyzer,
|
|
785
756
|
text: { fuzzy: { maxEdits: textSearch.fuzzy || 0 } }
|
|
@@ -802,25 +773,35 @@ else {
|
|
|
802
773
|
}
|
|
803
774
|
}
|
|
804
775
|
_prepareIndexesForField(fieldName, metadata) {
|
|
805
|
-
for (const index of metadata.get("
|
|
806
|
-
|
|
807
|
-
|
|
776
|
+
for (const index of metadata.get("db.index.plain") || []) {
|
|
777
|
+
const name = index === true ? fieldName : index.name || fieldName;
|
|
778
|
+
this._addIndexField("plain", name, fieldName);
|
|
779
|
+
}
|
|
780
|
+
for (const index of metadata.get("db.index.unique") || []) {
|
|
781
|
+
const name = index === true ? fieldName : index.name || fieldName;
|
|
782
|
+
this._addIndexField("unique", name, fieldName);
|
|
783
|
+
}
|
|
784
|
+
for (const index of metadata.get("db.index.fulltext") || []) {
|
|
785
|
+
const name = index === true ? "" : index.name || "";
|
|
786
|
+
this._addIndexField("text", name, fieldName, 1);
|
|
787
|
+
}
|
|
788
|
+
const textWeight = metadata.get("db.mongo.index.text");
|
|
808
789
|
if (textWeight) this._addIndexField("text", "", fieldName, textWeight === true ? 1 : textWeight);
|
|
809
|
-
for (const index of metadata.get("mongo.search.text") || []) this._addFieldToSearchIndex("search_text", index.indexName, fieldName, index.analyzer);
|
|
810
|
-
const vectorIndex = metadata.get("mongo.search.vector");
|
|
790
|
+
for (const index of metadata.get("db.mongo.search.text") || []) this._addFieldToSearchIndex("search_text", index.indexName, fieldName, index.analyzer);
|
|
791
|
+
const vectorIndex = metadata.get("db.mongo.search.vector");
|
|
811
792
|
if (vectorIndex) this._setSearchIndex("vector", vectorIndex.indexName || fieldName, { fields: [{
|
|
812
793
|
type: "vector",
|
|
813
794
|
path: fieldName,
|
|
814
795
|
similarity: vectorIndex.similarity || "dotProduct",
|
|
815
796
|
numDimensions: vectorIndex.dimensions
|
|
816
797
|
}] });
|
|
817
|
-
for (const index of metadata.get("mongo.search.filter") || []) this._vectorFilters.set(indexKey("vector", index.indexName), fieldName);
|
|
798
|
+
for (const index of metadata.get("db.mongo.search.filter") || []) this._vectorFilters.set(indexKey("vector", index.indexName), fieldName);
|
|
818
799
|
}
|
|
819
800
|
_flatten() {
|
|
820
801
|
if (!this._flatMap) {
|
|
821
802
|
this._prepareIndexesForCollection();
|
|
822
803
|
this._flatMap = (0, __atscript_typescript_utils.flattenAnnotatedType)(this.type, {
|
|
823
|
-
topLevelArrayTag: "mongo.__topLevelArray",
|
|
804
|
+
topLevelArrayTag: "db.mongo.__topLevelArray",
|
|
824
805
|
excludePhantomTypes: true,
|
|
825
806
|
onField: (path, _type, metadata) => this._prepareIndexesForField(path, metadata)
|
|
826
807
|
});
|
|
@@ -1032,8 +1013,8 @@ else if (this.idType !== "objectId") throw new Error("Missing \"_id\" field");
|
|
|
1032
1013
|
this._vectorFilters = new Map();
|
|
1033
1014
|
this._uniqueProps = new Set();
|
|
1034
1015
|
if (!(0, __atscript_typescript_utils.isAnnotatedType)(_type)) throw new Error("Atscript Annotated Type expected");
|
|
1035
|
-
const name = _type.metadata.get("
|
|
1036
|
-
if (!name) throw new Error("@
|
|
1016
|
+
const name = _type.metadata.get("db.table");
|
|
1017
|
+
if (!name) throw new Error("@db.table annotation expected with collection name");
|
|
1037
1018
|
if (_type.type.kind !== "object") throw new Error("Mongo collection must be an object type");
|
|
1038
1019
|
this.name = name;
|
|
1039
1020
|
this.collection = asMongo.db.collection(name);
|