@atscript/db-mongo 0.1.110 → 0.1.112

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 CHANGED
@@ -352,6 +352,9 @@ var CollectionPatcher = class {
352
352
  const INDEX_PREFIX = "atscript__";
353
353
  const DEFAULT_INDEX_NAME = "DEFAULT";
354
354
  const JOINED_PREFIX = "__joined_";
355
+ function isPlainIndex(index) {
356
+ return index.type === "plain" || index.type === "unique" || index.type === "text" || index.type === "2dsphere";
357
+ }
355
358
  function mongoIndexKey(type, name) {
356
359
  return `${INDEX_PREFIX}${type}__${name.replace(/[^a-z0-9_.-]/gi, "_").replace(/_+/g, "_").slice(0, 117 - type.length - 2)}`;
357
360
  }
@@ -1312,61 +1315,60 @@ async function syncIndexesImpl(host) {
1312
1315
  } else allIndexes.set(key, index);
1313
1316
  const existingIndexes = await host.collection.listIndexes().toArray();
1314
1317
  const indexesToCreate = new Map(allIndexes);
1318
+ const { attempt, throwIfAny } = (0, _atscript_db.createFailureCollector)("index sync");
1315
1319
  for (const remote of existingIndexes) {
1316
1320
  if (!remote.name.startsWith("atscript__")) continue;
1317
1321
  if (indexesToCreate.has(remote.name)) {
1318
1322
  const local = indexesToCreate.get(remote.name);
1319
- switch (local.type) {
1320
- case "plain":
1321
- case "unique":
1322
- case "text":
1323
- case "2dsphere": {
1324
- const fieldsMatch = local.type === "text" || objMatch(local.fields, remote.key);
1325
- const weightsMatch = objMatch(local.weights || {}, remote.weights || {});
1326
- const optionsMatch = local.type === "text" || local.type === "unique" === (remote.unique === true) && partialFilterEqual(local.partialFilterExpression, remote.partialFilterExpression);
1327
- if (fieldsMatch && weightsMatch && optionsMatch) indexesToCreate.delete(remote.name);
1328
- else {
1329
- host._log("dropIndex", remote.name);
1330
- await host.collection.dropIndex(remote.name);
1331
- }
1332
- break;
1323
+ if (isPlainIndex(local)) {
1324
+ const fieldsMatch = local.type === "text" || objMatch(local.fields, remote.key);
1325
+ const weightsMatch = objMatch(local.weights || {}, remote.weights || {});
1326
+ const optionsMatch = local.type === "text" || local.type === "unique" === (remote.unique === true) && partialFilterEqual(local.partialFilterExpression, remote.partialFilterExpression);
1327
+ if (fieldsMatch && weightsMatch && optionsMatch) indexesToCreate.delete(remote.name);
1328
+ else {
1329
+ host._log("dropIndex", remote.name);
1330
+ await attempt(`drop index "${remote.name}"`, () => host.collection.dropIndex(remote.name));
1333
1331
  }
1334
- default:
1335
1332
  }
1336
1333
  } else {
1337
1334
  host._log("dropIndex", remote.name);
1338
- await host.collection.dropIndex(remote.name);
1335
+ await attempt(`drop index "${remote.name}"`, () => host.collection.dropIndex(remote.name));
1339
1336
  }
1340
1337
  }
1341
- for (const [key, value] of allIndexes.entries()) switch (value.type) {
1342
- case "plain":
1343
- if (!indexesToCreate.has(key)) continue;
1344
- host._log("createIndex", key, value.fields);
1345
- await host.collection.createIndex(value.fields, { name: key });
1346
- break;
1347
- case "unique":
1348
- if (!indexesToCreate.has(key)) continue;
1349
- host._log("createIndex (unique)", key, value.fields, value.partialFilterExpression);
1350
- await host.collection.createIndex(value.fields, {
1351
- name: key,
1352
- unique: true,
1353
- ...value.partialFilterExpression ? { partialFilterExpression: value.partialFilterExpression } : {}
1354
- });
1355
- break;
1356
- case "text":
1357
- if (!indexesToCreate.has(key)) continue;
1358
- host._log("createIndex (text)", key, value.fields);
1359
- await host.collection.createIndex(value.fields, {
1360
- weights: value.weights,
1361
- name: key
1362
- });
1363
- break;
1364
- case "2dsphere":
1365
- if (!indexesToCreate.has(key)) continue;
1366
- host._log("createIndex (2dsphere)", key, value.fields);
1367
- await host.collection.createIndex(value.fields, { name: key });
1368
- break;
1369
- default:
1338
+ for (const [key, value] of allIndexes.entries()) {
1339
+ if (!isPlainIndex(value) || !indexesToCreate.has(key)) continue;
1340
+ let label;
1341
+ let indexOptions;
1342
+ switch (value.type) {
1343
+ case "plain":
1344
+ host._log("createIndex", key, value.fields);
1345
+ label = `create index "${key}"`;
1346
+ indexOptions = { name: key };
1347
+ break;
1348
+ case "unique":
1349
+ host._log("createIndex (unique)", key, value.fields, value.partialFilterExpression);
1350
+ label = `create unique index "${key}"`;
1351
+ indexOptions = {
1352
+ name: key,
1353
+ unique: true,
1354
+ ...value.partialFilterExpression ? { partialFilterExpression: value.partialFilterExpression } : {}
1355
+ };
1356
+ break;
1357
+ case "text":
1358
+ host._log("createIndex (text)", key, value.fields);
1359
+ label = `create text index "${key}"`;
1360
+ indexOptions = {
1361
+ weights: value.weights,
1362
+ name: key
1363
+ };
1364
+ break;
1365
+ case "2dsphere":
1366
+ host._log("createIndex (2dsphere)", key, value.fields);
1367
+ label = `create 2dsphere index "${key}"`;
1368
+ indexOptions = { name: key };
1369
+ break;
1370
+ }
1371
+ await attempt(label, () => host.collection.createIndex(value.fields, indexOptions));
1370
1372
  }
1371
1373
  try {
1372
1374
  const toUpdate = /* @__PURE__ */ new Set();
@@ -1414,6 +1416,7 @@ async function syncIndexesImpl(host) {
1414
1416
  default:
1415
1417
  }
1416
1418
  } catch {}
1419
+ throwIfAny();
1417
1420
  }
1418
1421
  /**
1419
1422
  * Maps an engine-agnostic design type to the MongoDB BSON `$type` alias(es)
@@ -2414,7 +2417,9 @@ function createAdapter(connection, _options) {
2414
2417
  }
2415
2418
  //#endregion
2416
2419
  exports.CollectionPatcher = CollectionPatcher;
2420
+ exports.INDEX_PREFIX = INDEX_PREFIX;
2417
2421
  exports.MongoAdapter = MongoAdapter;
2418
2422
  exports.buildMongoFilter = require_mongo_filter.buildMongoFilter;
2419
2423
  exports.createAdapter = createAdapter;
2424
+ exports.mongoIndexKey = mongoIndexKey;
2420
2425
  exports.validateMongoIdPlugin = validateMongoIdPlugin;
package/dist/index.d.cts CHANGED
@@ -145,6 +145,7 @@ declare class CollectionPatcher {
145
145
  }
146
146
  //#endregion
147
147
  //#region src/lib/mongo-types.d.ts
148
+ declare const INDEX_PREFIX = "atscript__";
148
149
  interface TPlainIndex {
149
150
  key: string;
150
151
  name: string;
@@ -185,6 +186,7 @@ interface TSearchIndex {
185
186
  strategy?: "compound" | "autocomplete" | "text";
186
187
  }
187
188
  type TMongoIndex = TPlainIndex | TSearchIndex;
189
+ declare function mongoIndexKey(type: TMongoIndex["type"], name: string): string;
188
190
  type TVectorSimilarity = "cosine" | "euclidean" | "dotProduct";
189
191
  /**
190
192
  * One Atlas Search field-type mapping. `type: "string"` is plain word matching;
@@ -457,4 +459,4 @@ declare const validateMongoIdPlugin: TValidatorPlugin;
457
459
  //#region src/lib/index.d.ts
458
460
  declare function createAdapter(connection: string, _options?: Record<string, unknown>): DbSpace;
459
461
  //#endregion
460
- export { CollectionPatcher, MongoAdapter, TCollectionPatcherContext, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, createAdapter, validateMongoIdPlugin };
462
+ export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, TCollectionPatcherContext, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, createAdapter, mongoIndexKey, validateMongoIdPlugin };
package/dist/index.d.mts CHANGED
@@ -145,6 +145,7 @@ declare class CollectionPatcher {
145
145
  }
146
146
  //#endregion
147
147
  //#region src/lib/mongo-types.d.ts
148
+ declare const INDEX_PREFIX = "atscript__";
148
149
  interface TPlainIndex {
149
150
  key: string;
150
151
  name: string;
@@ -185,6 +186,7 @@ interface TSearchIndex {
185
186
  strategy?: "compound" | "autocomplete" | "text";
186
187
  }
187
188
  type TMongoIndex = TPlainIndex | TSearchIndex;
189
+ declare function mongoIndexKey(type: TMongoIndex["type"], name: string): string;
188
190
  type TVectorSimilarity = "cosine" | "euclidean" | "dotProduct";
189
191
  /**
190
192
  * One Atlas Search field-type mapping. `type: "string"` is plain word matching;
@@ -457,4 +459,4 @@ declare const validateMongoIdPlugin: TValidatorPlugin;
457
459
  //#region src/lib/index.d.ts
458
460
  declare function createAdapter(connection: string, _options?: Record<string, unknown>): DbSpace;
459
461
  //#endregion
460
- export { CollectionPatcher, MongoAdapter, TCollectionPatcherContext, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, createAdapter, validateMongoIdPlugin };
462
+ export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, TCollectionPatcherContext, type TMongoIndex, type TMongoSearchIndexDefinition, type TPlainIndex, type TSearchIndex, buildMongoFilter, createAdapter, mongoIndexKey, validateMongoIdPlugin };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as buildMongoFilter } from "./mongo-filter-DceAGI-S.mjs";
2
- import { AtscriptDbView, BaseDbAdapter, DbError, DbSpace, computeInsights, getDbFieldOp, getKeyProps, resolveDesignType } from "@atscript/db";
2
+ import { AtscriptDbView, BaseDbAdapter, DbError, DbSpace, computeInsights, createFailureCollector, getDbFieldOp, getKeyProps, resolveDesignType } from "@atscript/db";
3
3
  import { MongoClient, MongoServerError, ObjectId } from "mongodb";
4
4
  //#region src/lib/path-utils.ts
5
5
  function joinPath(prefix, segment) {
@@ -351,6 +351,9 @@ var CollectionPatcher = class {
351
351
  const INDEX_PREFIX = "atscript__";
352
352
  const DEFAULT_INDEX_NAME = "DEFAULT";
353
353
  const JOINED_PREFIX = "__joined_";
354
+ function isPlainIndex(index) {
355
+ return index.type === "plain" || index.type === "unique" || index.type === "text" || index.type === "2dsphere";
356
+ }
354
357
  function mongoIndexKey(type, name) {
355
358
  return `${INDEX_PREFIX}${type}__${name.replace(/[^a-z0-9_.-]/gi, "_").replace(/_+/g, "_").slice(0, 117 - type.length - 2)}`;
356
359
  }
@@ -1311,61 +1314,60 @@ async function syncIndexesImpl(host) {
1311
1314
  } else allIndexes.set(key, index);
1312
1315
  const existingIndexes = await host.collection.listIndexes().toArray();
1313
1316
  const indexesToCreate = new Map(allIndexes);
1317
+ const { attempt, throwIfAny } = createFailureCollector("index sync");
1314
1318
  for (const remote of existingIndexes) {
1315
1319
  if (!remote.name.startsWith("atscript__")) continue;
1316
1320
  if (indexesToCreate.has(remote.name)) {
1317
1321
  const local = indexesToCreate.get(remote.name);
1318
- switch (local.type) {
1319
- case "plain":
1320
- case "unique":
1321
- case "text":
1322
- case "2dsphere": {
1323
- const fieldsMatch = local.type === "text" || objMatch(local.fields, remote.key);
1324
- const weightsMatch = objMatch(local.weights || {}, remote.weights || {});
1325
- const optionsMatch = local.type === "text" || local.type === "unique" === (remote.unique === true) && partialFilterEqual(local.partialFilterExpression, remote.partialFilterExpression);
1326
- if (fieldsMatch && weightsMatch && optionsMatch) indexesToCreate.delete(remote.name);
1327
- else {
1328
- host._log("dropIndex", remote.name);
1329
- await host.collection.dropIndex(remote.name);
1330
- }
1331
- break;
1322
+ if (isPlainIndex(local)) {
1323
+ const fieldsMatch = local.type === "text" || objMatch(local.fields, remote.key);
1324
+ const weightsMatch = objMatch(local.weights || {}, remote.weights || {});
1325
+ const optionsMatch = local.type === "text" || local.type === "unique" === (remote.unique === true) && partialFilterEqual(local.partialFilterExpression, remote.partialFilterExpression);
1326
+ if (fieldsMatch && weightsMatch && optionsMatch) indexesToCreate.delete(remote.name);
1327
+ else {
1328
+ host._log("dropIndex", remote.name);
1329
+ await attempt(`drop index "${remote.name}"`, () => host.collection.dropIndex(remote.name));
1332
1330
  }
1333
- default:
1334
1331
  }
1335
1332
  } else {
1336
1333
  host._log("dropIndex", remote.name);
1337
- await host.collection.dropIndex(remote.name);
1334
+ await attempt(`drop index "${remote.name}"`, () => host.collection.dropIndex(remote.name));
1338
1335
  }
1339
1336
  }
1340
- for (const [key, value] of allIndexes.entries()) switch (value.type) {
1341
- case "plain":
1342
- if (!indexesToCreate.has(key)) continue;
1343
- host._log("createIndex", key, value.fields);
1344
- await host.collection.createIndex(value.fields, { name: key });
1345
- break;
1346
- case "unique":
1347
- if (!indexesToCreate.has(key)) continue;
1348
- host._log("createIndex (unique)", key, value.fields, value.partialFilterExpression);
1349
- await host.collection.createIndex(value.fields, {
1350
- name: key,
1351
- unique: true,
1352
- ...value.partialFilterExpression ? { partialFilterExpression: value.partialFilterExpression } : {}
1353
- });
1354
- break;
1355
- case "text":
1356
- if (!indexesToCreate.has(key)) continue;
1357
- host._log("createIndex (text)", key, value.fields);
1358
- await host.collection.createIndex(value.fields, {
1359
- weights: value.weights,
1360
- name: key
1361
- });
1362
- break;
1363
- case "2dsphere":
1364
- if (!indexesToCreate.has(key)) continue;
1365
- host._log("createIndex (2dsphere)", key, value.fields);
1366
- await host.collection.createIndex(value.fields, { name: key });
1367
- break;
1368
- default:
1337
+ for (const [key, value] of allIndexes.entries()) {
1338
+ if (!isPlainIndex(value) || !indexesToCreate.has(key)) continue;
1339
+ let label;
1340
+ let indexOptions;
1341
+ switch (value.type) {
1342
+ case "plain":
1343
+ host._log("createIndex", key, value.fields);
1344
+ label = `create index "${key}"`;
1345
+ indexOptions = { name: key };
1346
+ break;
1347
+ case "unique":
1348
+ host._log("createIndex (unique)", key, value.fields, value.partialFilterExpression);
1349
+ label = `create unique index "${key}"`;
1350
+ indexOptions = {
1351
+ name: key,
1352
+ unique: true,
1353
+ ...value.partialFilterExpression ? { partialFilterExpression: value.partialFilterExpression } : {}
1354
+ };
1355
+ break;
1356
+ case "text":
1357
+ host._log("createIndex (text)", key, value.fields);
1358
+ label = `create text index "${key}"`;
1359
+ indexOptions = {
1360
+ weights: value.weights,
1361
+ name: key
1362
+ };
1363
+ break;
1364
+ case "2dsphere":
1365
+ host._log("createIndex (2dsphere)", key, value.fields);
1366
+ label = `create 2dsphere index "${key}"`;
1367
+ indexOptions = { name: key };
1368
+ break;
1369
+ }
1370
+ await attempt(label, () => host.collection.createIndex(value.fields, indexOptions));
1369
1371
  }
1370
1372
  try {
1371
1373
  const toUpdate = /* @__PURE__ */ new Set();
@@ -1413,6 +1415,7 @@ async function syncIndexesImpl(host) {
1413
1415
  default:
1414
1416
  }
1415
1417
  } catch {}
1418
+ throwIfAny();
1416
1419
  }
1417
1420
  /**
1418
1421
  * Maps an engine-agnostic design type to the MongoDB BSON `$type` alias(es)
@@ -2412,4 +2415,4 @@ function createAdapter(connection, _options) {
2412
2415
  return new DbSpace(() => new MongoAdapter(db, client));
2413
2416
  }
2414
2417
  //#endregion
2415
- export { CollectionPatcher, MongoAdapter, buildMongoFilter, createAdapter, validateMongoIdPlugin };
2418
+ export { CollectionPatcher, INDEX_PREFIX, MongoAdapter, buildMongoFilter, createAdapter, mongoIndexKey, validateMongoIdPlugin };
package/dist/plugin.cjs CHANGED
@@ -158,6 +158,7 @@ const annotations = {
158
158
  text: new _atscript_core.AnnotationSpec({
159
159
  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",
160
160
  nodeType: ["prop"],
161
+ passedWhenReferred: false,
161
162
  multiple: true,
162
163
  argument: [{
163
164
  optional: true,
@@ -175,6 +176,7 @@ const annotations = {
175
176
  autocomplete: new _atscript_core.AnnotationSpec({
176
177
  description: "Marks a field for **prefix / typeahead (as-you-type)** matching in a MongoDB Atlas Search Index.\n\n- Indexes the field as the Atlas **`autocomplete`** type, **and** double-maps it as `string` so exact-word hits still rank.\n- Lets `search()` match partial words: with the default `edgeGram` tokenization, `\"art\"` matches `\"Artem\"` **as you type** (no whole word required).\n- Use `nGram` tokenization for true mid-word (infix/substring) matching at higher index cost.\n- Like `@db.mongo.search.text`, the field joins the index named by `indexName` (or the default index).\n\n**Example:**\n```atscript\n@db.mongo.search.autocomplete \"users\"\nusername: string\n```\n",
177
178
  nodeType: ["prop"],
179
+ passedWhenReferred: false,
178
180
  multiple: true,
179
181
  argument: [
180
182
  {
package/dist/plugin.mjs CHANGED
@@ -154,6 +154,7 @@ const annotations = {
154
154
  text: new AnnotationSpec({
155
155
  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",
156
156
  nodeType: ["prop"],
157
+ passedWhenReferred: false,
157
158
  multiple: true,
158
159
  argument: [{
159
160
  optional: true,
@@ -171,6 +172,7 @@ const annotations = {
171
172
  autocomplete: new AnnotationSpec({
172
173
  description: "Marks a field for **prefix / typeahead (as-you-type)** matching in a MongoDB Atlas Search Index.\n\n- Indexes the field as the Atlas **`autocomplete`** type, **and** double-maps it as `string` so exact-word hits still rank.\n- Lets `search()` match partial words: with the default `edgeGram` tokenization, `\"art\"` matches `\"Artem\"` **as you type** (no whole word required).\n- Use `nGram` tokenization for true mid-word (infix/substring) matching at higher index cost.\n- Like `@db.mongo.search.text`, the field joins the index named by `indexName` (or the default index).\n\n**Example:**\n```atscript\n@db.mongo.search.autocomplete \"users\"\nusername: string\n```\n",
173
174
  nodeType: ["prop"],
175
+ passedWhenReferred: false,
174
176
  multiple: true,
175
177
  argument: [
176
178
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-mongo",
3
- "version": "0.1.110",
3
+ "version": "0.1.112",
4
4
  "description": "Mongodb plugin for atscript.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -46,17 +46,17 @@
46
46
  "access": "public"
47
47
  },
48
48
  "devDependencies": {
49
- "@atscript/core": "^0.1.78",
50
- "@atscript/typescript": "^0.1.78",
49
+ "@atscript/core": "^0.1.80",
50
+ "@atscript/typescript": "^0.1.80",
51
51
  "mongodb": "^6.17.0",
52
52
  "mongodb-memory-server-core": "^10.0.0",
53
- "unplugin-atscript": "^0.1.78"
53
+ "unplugin-atscript": "^0.1.80"
54
54
  },
55
55
  "peerDependencies": {
56
- "@atscript/core": "^0.1.78",
57
- "@atscript/typescript": "^0.1.78",
56
+ "@atscript/core": "^0.1.80",
57
+ "@atscript/typescript": "^0.1.80",
58
58
  "mongodb": "^6.17.0",
59
- "@atscript/db": "^0.1.110"
59
+ "@atscript/db": "^0.1.112"
60
60
  },
61
61
  "scripts": {
62
62
  "postinstall": "asc -f dts",