@orion-js/mongodb 4.2.1 → 4.2.4

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.d.cts CHANGED
@@ -317,11 +317,14 @@ interface DeleteUnusedIndexesResult {
317
317
  /**
318
318
  * Registry that tracks all collections created via createCollection().
319
319
  * Maps connection name to a map of collection name to collection instance.
320
+ * When the same collection is registered multiple times, indexes are merged.
320
321
  */
321
322
  declare const collectionsRegistry: Map<string, Map<string, Collection<ModelClassBase>>>;
322
323
  /**
323
324
  * Registers a collection in the registry.
324
325
  * Called automatically when a collection is created via createCollection().
326
+ * If the same collection name is registered multiple times, indexes are merged
327
+ * to support multiple createCollection() calls for the same collection.
325
328
  * @param connectionName - The name of the MongoDB connection
326
329
  * @param collection - The collection instance to register
327
330
  */
@@ -332,11 +335,23 @@ declare function registerCollection(connectionName: string, collection: Collecti
332
335
  * @returns Array of registered collections for the connection
333
336
  */
334
337
  declare function getRegisteredCollections(connectionName?: string): Array<Collection<ModelClassBase>>;
338
+ /**
339
+ * Gets the merged indexes for a specific collection from the registry.
340
+ * This includes all indexes from all createCollection() calls for the same collection name.
341
+ * @param connectionName - The name of the MongoDB connection
342
+ * @param collectionName - The name of the collection
343
+ * @returns Array of merged index definitions, or empty array if collection not registered
344
+ */
345
+ declare function getMergedIndexes(connectionName: string, collectionName: string): CollectionIndex[];
335
346
  /**
336
347
  * Deletes unused indexes from all registered collections for a connection.
337
348
  * Iterates over all collections registered via createCollection() and
338
349
  * removes indexes that exist in MongoDB but are not defined in the collection configuration.
339
350
  *
351
+ * **Important**: This function waits for all pending index creation to complete before
352
+ * deleting any indexes, to avoid race conditions where an index being created might
353
+ * be incorrectly identified as unused.
354
+ *
340
355
  * @param connectionName - The name of the MongoDB connection (defaults to 'main')
341
356
  * @returns Array of results for each collection that had indexes deleted
342
357
  *
@@ -373,4 +388,4 @@ declare const ENCRYPTION_ALGORITHMS: {
373
388
  RANDOM: string;
374
389
  };
375
390
 
376
- export { BaseCollection, Collection, type CollectionIndex, type CountDocuments, type CreateCollectionOptions, type CreateCollectionOptionsWithSchemaType, type CreateCollectionOptionsWithTypedSchema, DataLoader, type DeleteMany, type DeleteOne, type DistinctDocumentId, type DocumentWithId, ENCRYPTION_ALGORITHMS, type EstimatedDocumentCount, type Find, type FindCursor, type FindOne, type FindOneAndUpdate, type FindOneAndUpdateUpdateOptions, type InferIdType, type InferSchemaTypeWithId, type InitItem, type InsertAndFind, type InsertMany, type InsertManyOptions, type InsertOne, type InsertOptions, type ModelClassBase, type ModelToMongoSelector, MongoCollection, type MongoFilter, type MongoSelector, type OptionalId, Repository, type SchemaWithRequiredId, type TypedId, type UpdateAndFind, type UpdateItem, type UpdateMany, type UpdateOne, type UpdateOptions, type Upsert, allConnectionPromises, collectionsRegistry, configureConnection, connections, createCollection, createIndexesPromises, deleteAllUnusedIndexes, getDBName, getMongoConnection, getOrCreateEncryptionKey, getRegisteredCollections, registerCollection, typedId };
391
+ export { BaseCollection, Collection, type CollectionIndex, type CountDocuments, type CreateCollectionOptions, type CreateCollectionOptionsWithSchemaType, type CreateCollectionOptionsWithTypedSchema, DataLoader, type DeleteMany, type DeleteOne, type DistinctDocumentId, type DocumentWithId, ENCRYPTION_ALGORITHMS, type EstimatedDocumentCount, type Find, type FindCursor, type FindOne, type FindOneAndUpdate, type FindOneAndUpdateUpdateOptions, type InferIdType, type InferSchemaTypeWithId, type InitItem, type InsertAndFind, type InsertMany, type InsertManyOptions, type InsertOne, type InsertOptions, type ModelClassBase, type ModelToMongoSelector, MongoCollection, type MongoFilter, type MongoSelector, type OptionalId, Repository, type SchemaWithRequiredId, type TypedId, type UpdateAndFind, type UpdateItem, type UpdateMany, type UpdateOne, type UpdateOptions, type Upsert, allConnectionPromises, collectionsRegistry, configureConnection, connections, createCollection, createIndexesPromises, deleteAllUnusedIndexes, getDBName, getMergedIndexes, getMongoConnection, getOrCreateEncryptionKey, getRegisteredCollections, registerCollection, typedId };
package/dist/index.d.ts CHANGED
@@ -317,11 +317,14 @@ interface DeleteUnusedIndexesResult {
317
317
  /**
318
318
  * Registry that tracks all collections created via createCollection().
319
319
  * Maps connection name to a map of collection name to collection instance.
320
+ * When the same collection is registered multiple times, indexes are merged.
320
321
  */
321
322
  declare const collectionsRegistry: Map<string, Map<string, Collection<ModelClassBase>>>;
322
323
  /**
323
324
  * Registers a collection in the registry.
324
325
  * Called automatically when a collection is created via createCollection().
326
+ * If the same collection name is registered multiple times, indexes are merged
327
+ * to support multiple createCollection() calls for the same collection.
325
328
  * @param connectionName - The name of the MongoDB connection
326
329
  * @param collection - The collection instance to register
327
330
  */
@@ -332,11 +335,23 @@ declare function registerCollection(connectionName: string, collection: Collecti
332
335
  * @returns Array of registered collections for the connection
333
336
  */
334
337
  declare function getRegisteredCollections(connectionName?: string): Array<Collection<ModelClassBase>>;
338
+ /**
339
+ * Gets the merged indexes for a specific collection from the registry.
340
+ * This includes all indexes from all createCollection() calls for the same collection name.
341
+ * @param connectionName - The name of the MongoDB connection
342
+ * @param collectionName - The name of the collection
343
+ * @returns Array of merged index definitions, or empty array if collection not registered
344
+ */
345
+ declare function getMergedIndexes(connectionName: string, collectionName: string): CollectionIndex[];
335
346
  /**
336
347
  * Deletes unused indexes from all registered collections for a connection.
337
348
  * Iterates over all collections registered via createCollection() and
338
349
  * removes indexes that exist in MongoDB but are not defined in the collection configuration.
339
350
  *
351
+ * **Important**: This function waits for all pending index creation to complete before
352
+ * deleting any indexes, to avoid race conditions where an index being created might
353
+ * be incorrectly identified as unused.
354
+ *
340
355
  * @param connectionName - The name of the MongoDB connection (defaults to 'main')
341
356
  * @returns Array of results for each collection that had indexes deleted
342
357
  *
@@ -373,4 +388,4 @@ declare const ENCRYPTION_ALGORITHMS: {
373
388
  RANDOM: string;
374
389
  };
375
390
 
376
- export { BaseCollection, Collection, type CollectionIndex, type CountDocuments, type CreateCollectionOptions, type CreateCollectionOptionsWithSchemaType, type CreateCollectionOptionsWithTypedSchema, DataLoader, type DeleteMany, type DeleteOne, type DistinctDocumentId, type DocumentWithId, ENCRYPTION_ALGORITHMS, type EstimatedDocumentCount, type Find, type FindCursor, type FindOne, type FindOneAndUpdate, type FindOneAndUpdateUpdateOptions, type InferIdType, type InferSchemaTypeWithId, type InitItem, type InsertAndFind, type InsertMany, type InsertManyOptions, type InsertOne, type InsertOptions, type ModelClassBase, type ModelToMongoSelector, MongoCollection, type MongoFilter, type MongoSelector, type OptionalId, Repository, type SchemaWithRequiredId, type TypedId, type UpdateAndFind, type UpdateItem, type UpdateMany, type UpdateOne, type UpdateOptions, type Upsert, allConnectionPromises, collectionsRegistry, configureConnection, connections, createCollection, createIndexesPromises, deleteAllUnusedIndexes, getDBName, getMongoConnection, getOrCreateEncryptionKey, getRegisteredCollections, registerCollection, typedId };
391
+ export { BaseCollection, Collection, type CollectionIndex, type CountDocuments, type CreateCollectionOptions, type CreateCollectionOptionsWithSchemaType, type CreateCollectionOptionsWithTypedSchema, DataLoader, type DeleteMany, type DeleteOne, type DistinctDocumentId, type DocumentWithId, ENCRYPTION_ALGORITHMS, type EstimatedDocumentCount, type Find, type FindCursor, type FindOne, type FindOneAndUpdate, type FindOneAndUpdateUpdateOptions, type InferIdType, type InferSchemaTypeWithId, type InitItem, type InsertAndFind, type InsertMany, type InsertManyOptions, type InsertOne, type InsertOptions, type ModelClassBase, type ModelToMongoSelector, MongoCollection, type MongoFilter, type MongoSelector, type OptionalId, Repository, type SchemaWithRequiredId, type TypedId, type UpdateAndFind, type UpdateItem, type UpdateMany, type UpdateOne, type UpdateOptions, type Upsert, allConnectionPromises, collectionsRegistry, configureConnection, connections, createCollection, createIndexesPromises, deleteAllUnusedIndexes, getDBName, getMergedIndexes, getMongoConnection, getOrCreateEncryptionKey, getRegisteredCollections, registerCollection, typedId };
package/dist/index.js CHANGED
@@ -1146,7 +1146,7 @@ var generateId_default = getIdGenerator;
1146
1146
 
1147
1147
  // src/createCollection/createIndexes.ts
1148
1148
  import { MongoExpiredSessionError, MongoNotConnectedError } from "mongodb";
1149
- import { logger as logger3 } from "@orion-js/logger";
1149
+ import { logger as logger4 } from "@orion-js/logger";
1150
1150
 
1151
1151
  // src/createCollection/deleteUnusedIndexes.ts
1152
1152
  import { logger as logger2 } from "@orion-js/logger";
@@ -1168,6 +1168,15 @@ function getIndexName(indexDef) {
1168
1168
  }
1169
1169
 
1170
1170
  // src/createCollection/deleteUnusedIndexes.ts
1171
+ function isTextIndexDefinition(keys) {
1172
+ return Object.values(keys).some((value) => value === "text");
1173
+ }
1174
+ function isMongoDBTextIndex(key) {
1175
+ return "_fts" in key && "_ftsx" in key;
1176
+ }
1177
+ function generateIndexName(keys) {
1178
+ return Object.entries(keys).map(([field, value]) => `${field}_${value}`).join("_");
1179
+ }
1171
1180
  function keysMatch(definitionKeys, currentIndexKey) {
1172
1181
  const defEntries = Object.entries(definitionKeys);
1173
1182
  const curEntries = Object.entries(currentIndexKey);
@@ -1183,7 +1192,12 @@ function isIndexDefined(definedIndexes, currentIndex) {
1183
1192
  return definedIndexes.some((defIndex) => {
1184
1193
  const customName = getIndexName(defIndex);
1185
1194
  if (customName && customName === currentIndex.name) return true;
1186
- return keysMatch(defIndex.keys, currentIndex.key);
1195
+ const defKeys = defIndex.keys;
1196
+ if (isTextIndexDefinition(defKeys) && isMongoDBTextIndex(currentIndex.key)) {
1197
+ const expectedName = generateIndexName(defKeys);
1198
+ return currentIndex.name === expectedName;
1199
+ }
1200
+ return keysMatch(defKeys, currentIndex.key);
1187
1201
  });
1188
1202
  }
1189
1203
  async function deleteUnusedIndexes(collection) {
@@ -1221,6 +1235,85 @@ async function deleteUnusedIndexes(collection) {
1221
1235
  return result;
1222
1236
  }
1223
1237
 
1238
+ // src/createCollection/collectionsRegistry.ts
1239
+ import { logger as logger3 } from "@orion-js/logger";
1240
+ var collectionsRegistry = /* @__PURE__ */ new Map();
1241
+ function indexesAreEqual(indexA, indexB) {
1242
+ const nameA = getIndexName(indexA);
1243
+ const nameB = getIndexName(indexB);
1244
+ if (nameA && nameB) {
1245
+ return nameA === nameB;
1246
+ }
1247
+ return keysMatch(
1248
+ indexA.keys,
1249
+ indexB.keys
1250
+ );
1251
+ }
1252
+ function mergeIndexes(existingIndexes, newIndexes) {
1253
+ const merged = [...existingIndexes];
1254
+ for (const newIndex of newIndexes) {
1255
+ const isDuplicate = existingIndexes.some((existing) => indexesAreEqual(existing, newIndex));
1256
+ if (!isDuplicate) {
1257
+ merged.push(newIndex);
1258
+ }
1259
+ }
1260
+ return merged;
1261
+ }
1262
+ function registerCollection(connectionName, collection) {
1263
+ if (!collectionsRegistry.has(connectionName)) {
1264
+ collectionsRegistry.set(connectionName, /* @__PURE__ */ new Map());
1265
+ }
1266
+ const connectionMap = collectionsRegistry.get(connectionName);
1267
+ const existingCollection = connectionMap.get(collection.name);
1268
+ if (existingCollection) {
1269
+ existingCollection.indexes = mergeIndexes(existingCollection.indexes, collection.indexes);
1270
+ } else {
1271
+ connectionMap.set(collection.name, collection);
1272
+ }
1273
+ }
1274
+ function getRegisteredCollections(connectionName = "main") {
1275
+ const connectionCollections = collectionsRegistry.get(connectionName);
1276
+ if (!connectionCollections) {
1277
+ return [];
1278
+ }
1279
+ return Array.from(connectionCollections.values());
1280
+ }
1281
+ function getMergedIndexes(connectionName, collectionName) {
1282
+ const connectionCollections = collectionsRegistry.get(connectionName);
1283
+ if (!connectionCollections) {
1284
+ return [];
1285
+ }
1286
+ const collection = connectionCollections.get(collectionName);
1287
+ if (!collection) {
1288
+ return [];
1289
+ }
1290
+ return collection.indexes || [];
1291
+ }
1292
+ async function deleteAllUnusedIndexes(connectionName = "main") {
1293
+ const collections = getRegisteredCollections(connectionName);
1294
+ if (collections.length === 0) {
1295
+ logger3.warn(`No collections registered for connection "${connectionName}"`);
1296
+ return [];
1297
+ }
1298
+ if (createIndexesPromises.length > 0) {
1299
+ logger3.info("Waiting for pending index creation to complete before deleting unused indexes...");
1300
+ await Promise.all(createIndexesPromises);
1301
+ }
1302
+ logger3.info(
1303
+ `Deleting unused indexes from ${collections.length} collections on connection "${connectionName}"`
1304
+ );
1305
+ const results = [];
1306
+ for (const collection of collections) {
1307
+ const result = await collection.deleteUnusedIndexes();
1308
+ if (result.deletedIndexes.length > 0) {
1309
+ results.push(result);
1310
+ }
1311
+ }
1312
+ const totalDeleted = results.reduce((sum, r) => sum + r.deletedIndexes.length, 0);
1313
+ logger3.info(`Deleted ${totalDeleted} unused indexes from ${results.length} collections`);
1314
+ return results;
1315
+ }
1316
+
1224
1317
  // src/createCollection/createIndexes.ts
1225
1318
  async function checkIndexes(collection) {
1226
1319
  await collection.connectionPromise;
@@ -1231,14 +1324,15 @@ async function checkIndexes(collection) {
1231
1324
  if (error.codeName !== "NamespaceNotFound") throw error;
1232
1325
  return;
1233
1326
  }
1234
- if (!collection.indexes || collection.indexes.length === 0) {
1327
+ const mergedIndexes = getMergedIndexes(collection.connectionName, collection.name);
1328
+ if (mergedIndexes.length === 0) {
1235
1329
  return;
1236
1330
  }
1237
1331
  const unexpectedIndexes = currentIndexes.filter(
1238
- (index) => index.name !== "_id_" && !isIndexDefined(collection.indexes, index)
1332
+ (index) => index.name !== "_id_" && !isIndexDefined(mergedIndexes, index)
1239
1333
  );
1240
1334
  if (unexpectedIndexes.length > 0) {
1241
- logger3.warn(
1335
+ logger4.warn(
1242
1336
  `${unexpectedIndexes.length} unexpected indexes found in collection "${collection.name}": ${unexpectedIndexes.map((i) => i.name).join(", ")} | Delete the index or fix the collection definition`
1243
1337
  );
1244
1338
  }
@@ -1280,43 +1374,6 @@ async function loadIndexes(collection) {
1280
1374
  return results;
1281
1375
  }
1282
1376
 
1283
- // src/createCollection/collectionsRegistry.ts
1284
- import { logger as logger4 } from "@orion-js/logger";
1285
- var collectionsRegistry = /* @__PURE__ */ new Map();
1286
- function registerCollection(connectionName, collection) {
1287
- if (!collectionsRegistry.has(connectionName)) {
1288
- collectionsRegistry.set(connectionName, /* @__PURE__ */ new Map());
1289
- }
1290
- collectionsRegistry.get(connectionName).set(collection.name, collection);
1291
- }
1292
- function getRegisteredCollections(connectionName = "main") {
1293
- const connectionCollections = collectionsRegistry.get(connectionName);
1294
- if (!connectionCollections) {
1295
- return [];
1296
- }
1297
- return Array.from(connectionCollections.values());
1298
- }
1299
- async function deleteAllUnusedIndexes(connectionName = "main") {
1300
- const collections = getRegisteredCollections(connectionName);
1301
- if (collections.length === 0) {
1302
- logger4.warn(`No collections registered for connection "${connectionName}"`);
1303
- return [];
1304
- }
1305
- logger4.info(
1306
- `Deleting unused indexes from ${collections.length} collections on connection "${connectionName}"`
1307
- );
1308
- const results = [];
1309
- for (const collection of collections) {
1310
- const result = await collection.deleteUnusedIndexes();
1311
- if (result.deletedIndexes.length > 0) {
1312
- results.push(result);
1313
- }
1314
- }
1315
- const totalDeleted = results.reduce((sum, r) => sum + r.deletedIndexes.length, 0);
1316
- logger4.info(`Deleted ${totalDeleted} unused indexes from ${results.length} collections`);
1317
- return results;
1318
- }
1319
-
1320
1377
  // src/createCollection/getSchemaAndModel.ts
1321
1378
  import { clone as clone3 } from "@orion-js/helpers";
1322
1379
  Symbol.metadata ?? (Symbol.metadata = Symbol("Symbol.metadata"));
@@ -1597,6 +1654,7 @@ export {
1597
1654
  createIndexesPromises,
1598
1655
  deleteAllUnusedIndexes,
1599
1656
  getDBName,
1657
+ getMergedIndexes,
1600
1658
  getMongoConnection,
1601
1659
  getOrCreateEncryptionKey,
1602
1660
  getRegisteredCollections,