@orion-js/mongodb 4.1.10 → 4.2.0
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 +104 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +104 -18
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -73,8 +73,26 @@ type DocumentWithId<TSchema> = EnhancedOmit<TSchema, '_id'> & {
|
|
|
73
73
|
_id: InferIdType<TSchema>;
|
|
74
74
|
};
|
|
75
75
|
type ModelClassBase = DocumentWithId<MongoDB.Document>;
|
|
76
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Index definition for a MongoDB collection.
|
|
78
|
+
* Supports flat options (recommended) or nested options object (deprecated).
|
|
79
|
+
*
|
|
80
|
+
* @example New format (recommended):
|
|
81
|
+
* ```ts
|
|
82
|
+
* { keys: { email: 1 }, unique: true, sparse: true }
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @example Old format (deprecated):
|
|
86
|
+
* ```ts
|
|
87
|
+
* { keys: { email: 1 }, options: { unique: true, sparse: true } }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
interface CollectionIndex extends Partial<MongoDB.CreateIndexesOptions> {
|
|
77
91
|
keys: MongoDB.IndexSpecification;
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated Use flat options instead. Example: `{ keys: { email: 1 }, unique: true }`
|
|
94
|
+
* instead of `{ keys: { email: 1 }, options: { unique: true } }`
|
|
95
|
+
*/
|
|
78
96
|
options?: MongoDB.CreateIndexesOptions;
|
|
79
97
|
}
|
|
80
98
|
declare namespace DataLoader {
|
|
@@ -229,6 +247,15 @@ declare class BaseCollection<ModelClass extends ModelClassBase = ModelClassBase>
|
|
|
229
247
|
*/
|
|
230
248
|
createIndexes: () => Promise<string[]>;
|
|
231
249
|
createIndexesPromise: Promise<string[]>;
|
|
250
|
+
/**
|
|
251
|
+
* Deletes indexes that exist in MongoDB but are not defined in the collection configuration.
|
|
252
|
+
* This helps clean up stale indexes that are no longer needed.
|
|
253
|
+
* Always preserves the _id_ index.
|
|
254
|
+
*/
|
|
255
|
+
deleteUnusedIndexes: () => Promise<{
|
|
256
|
+
deletedIndexes: string[];
|
|
257
|
+
collectionName: string;
|
|
258
|
+
}>;
|
|
232
259
|
/**
|
|
233
260
|
* @deprecated Use startConnection() instead. This property is not guaranteed to be resolved if the connection is not started.
|
|
234
261
|
* When using async calls startConnection or connectionPromise is no longer needed. Orion will automatically start the connection if it is not already started.
|
package/dist/index.js
CHANGED
|
@@ -248,6 +248,12 @@ var BaseCollection = class {
|
|
|
248
248
|
*/
|
|
249
249
|
createIndexes;
|
|
250
250
|
createIndexesPromise;
|
|
251
|
+
/**
|
|
252
|
+
* Deletes indexes that exist in MongoDB but are not defined in the collection configuration.
|
|
253
|
+
* This helps clean up stale indexes that are no longer needed.
|
|
254
|
+
* Always preserves the _id_ index.
|
|
255
|
+
*/
|
|
256
|
+
deleteUnusedIndexes;
|
|
251
257
|
/**
|
|
252
258
|
* @deprecated Use startConnection() instead. This property is not guaranteed to be resolved if the connection is not started.
|
|
253
259
|
* When using async calls startConnection or connectionPromise is no longer needed. Orion will automatically start the connection if it is not already started.
|
|
@@ -1140,12 +1146,82 @@ var generateId_default = getIdGenerator;
|
|
|
1140
1146
|
|
|
1141
1147
|
// src/createCollection/createIndexes.ts
|
|
1142
1148
|
import { MongoExpiredSessionError, MongoNotConnectedError } from "mongodb";
|
|
1149
|
+
import { logger as logger3 } from "@orion-js/logger";
|
|
1150
|
+
|
|
1151
|
+
// src/createCollection/deleteUnusedIndexes.ts
|
|
1143
1152
|
import { logger as logger2 } from "@orion-js/logger";
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1153
|
+
|
|
1154
|
+
// src/createCollection/getIndexOptions.ts
|
|
1155
|
+
function getIndexOptions(indexDef) {
|
|
1156
|
+
const { keys: _keys, options: deprecatedOptions, ...flatOptions } = indexDef;
|
|
1157
|
+
if (deprecatedOptions) {
|
|
1158
|
+
return { ...deprecatedOptions, ...flatOptions };
|
|
1159
|
+
}
|
|
1160
|
+
return Object.keys(flatOptions).length > 0 ? flatOptions : void 0;
|
|
1148
1161
|
}
|
|
1162
|
+
function getIndexName(indexDef) {
|
|
1163
|
+
var _a;
|
|
1164
|
+
if (indexDef.name) {
|
|
1165
|
+
return indexDef.name;
|
|
1166
|
+
}
|
|
1167
|
+
return (_a = indexDef.options) == null ? void 0 : _a.name;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/createCollection/deleteUnusedIndexes.ts
|
|
1171
|
+
function keysMatch(definitionKeys, currentIndexKey) {
|
|
1172
|
+
const defEntries = Object.entries(definitionKeys);
|
|
1173
|
+
const curEntries = Object.entries(currentIndexKey);
|
|
1174
|
+
if (defEntries.length !== curEntries.length) return false;
|
|
1175
|
+
for (let i = 0; i < defEntries.length; i++) {
|
|
1176
|
+
const [defKey, defValue] = defEntries[i];
|
|
1177
|
+
const [curKey, curValue] = curEntries[i];
|
|
1178
|
+
if (defKey !== curKey || defValue !== curValue) return false;
|
|
1179
|
+
}
|
|
1180
|
+
return true;
|
|
1181
|
+
}
|
|
1182
|
+
function isIndexDefined(definedIndexes, currentIndex) {
|
|
1183
|
+
return definedIndexes.some((defIndex) => {
|
|
1184
|
+
const customName = getIndexName(defIndex);
|
|
1185
|
+
if (customName && customName === currentIndex.name) return true;
|
|
1186
|
+
return keysMatch(defIndex.keys, currentIndex.key);
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
async function deleteUnusedIndexes(collection) {
|
|
1190
|
+
await collection.connectionPromise;
|
|
1191
|
+
const result = {
|
|
1192
|
+
deletedIndexes: [],
|
|
1193
|
+
collectionName: collection.name
|
|
1194
|
+
};
|
|
1195
|
+
let currentIndexes = [];
|
|
1196
|
+
try {
|
|
1197
|
+
currentIndexes = await collection.rawCollection.indexes();
|
|
1198
|
+
} catch (error) {
|
|
1199
|
+
if (error.codeName === "NamespaceNotFound") {
|
|
1200
|
+
return result;
|
|
1201
|
+
}
|
|
1202
|
+
throw error;
|
|
1203
|
+
}
|
|
1204
|
+
if (!collection.indexes || collection.indexes.length === 0) {
|
|
1205
|
+
return result;
|
|
1206
|
+
}
|
|
1207
|
+
const unusedIndexes = currentIndexes.filter(
|
|
1208
|
+
(index) => index.name !== "_id_" && !isIndexDefined(collection.indexes, index)
|
|
1209
|
+
);
|
|
1210
|
+
for (const index of unusedIndexes) {
|
|
1211
|
+
try {
|
|
1212
|
+
await collection.rawCollection.dropIndex(index.name);
|
|
1213
|
+
result.deletedIndexes.push(index.name);
|
|
1214
|
+
logger2.info(`Deleted unused index "${index.name}" from collection "${collection.name}"`);
|
|
1215
|
+
} catch (error) {
|
|
1216
|
+
logger2.error(`Failed to delete index "${index.name}" from collection "${collection.name}"`, {
|
|
1217
|
+
error
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return result;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/createCollection/createIndexes.ts
|
|
1149
1225
|
async function checkIndexes(collection) {
|
|
1150
1226
|
await collection.connectionPromise;
|
|
1151
1227
|
let currentIndexes = [];
|
|
@@ -1153,13 +1229,17 @@ async function checkIndexes(collection) {
|
|
|
1153
1229
|
currentIndexes = await collection.rawCollection.indexes();
|
|
1154
1230
|
} catch (error) {
|
|
1155
1231
|
if (error.codeName !== "NamespaceNotFound") throw error;
|
|
1232
|
+
return;
|
|
1156
1233
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1234
|
+
if (!collection.indexes || collection.indexes.length === 0) {
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
const unexpectedIndexes = currentIndexes.filter(
|
|
1238
|
+
(index) => index.name !== "_id_" && !isIndexDefined(collection.indexes, index)
|
|
1239
|
+
);
|
|
1240
|
+
if (unexpectedIndexes.length > 0) {
|
|
1241
|
+
logger3.warn(
|
|
1242
|
+
`${unexpectedIndexes.length} unexpected indexes found in collection "${collection.name}": ${unexpectedIndexes.map((i) => i.name).join(", ")} | Delete the index or fix the collection definition`
|
|
1163
1243
|
);
|
|
1164
1244
|
}
|
|
1165
1245
|
}
|
|
@@ -1168,7 +1248,9 @@ async function loadIndexes(collection) {
|
|
|
1168
1248
|
if (!collection.indexes.length) return;
|
|
1169
1249
|
await collection.connectionPromise;
|
|
1170
1250
|
const results = Promise.all(
|
|
1171
|
-
collection.indexes.map(async (
|
|
1251
|
+
collection.indexes.map(async (indexDef) => {
|
|
1252
|
+
const { keys } = indexDef;
|
|
1253
|
+
const options = getIndexOptions(indexDef);
|
|
1172
1254
|
try {
|
|
1173
1255
|
return await collection.rawCollection.createIndex(keys, options);
|
|
1174
1256
|
} catch (error) {
|
|
@@ -1230,7 +1312,7 @@ function getSchema(options) {
|
|
|
1230
1312
|
}
|
|
1231
1313
|
|
|
1232
1314
|
// src/createCollection/wrapMethods.ts
|
|
1233
|
-
import { logger as
|
|
1315
|
+
import { logger as logger4 } from "@orion-js/logger";
|
|
1234
1316
|
function wrapMethods(collection) {
|
|
1235
1317
|
const methodsWithPromises = [
|
|
1236
1318
|
"findOne",
|
|
@@ -1266,7 +1348,7 @@ function wrapMethods(collection) {
|
|
|
1266
1348
|
collection[methodName2] = (...args) => {
|
|
1267
1349
|
collection.startConnection();
|
|
1268
1350
|
if (!collection.rawCollection) {
|
|
1269
|
-
|
|
1351
|
+
logger4.error("Method called before connection was initialized", {
|
|
1270
1352
|
collectionName: collection.name,
|
|
1271
1353
|
connectionName: collection.connectionName,
|
|
1272
1354
|
methodName: methodName2
|
|
@@ -1367,6 +1449,10 @@ function createCollection(options) {
|
|
|
1367
1449
|
return createIndexPromise;
|
|
1368
1450
|
};
|
|
1369
1451
|
mainCollection.createIndexes = createIndexes;
|
|
1452
|
+
mainCollection.deleteUnusedIndexes = async () => {
|
|
1453
|
+
await orionConnection.startConnection();
|
|
1454
|
+
return deleteUnusedIndexes(mainCollection);
|
|
1455
|
+
};
|
|
1370
1456
|
if (!process.env.DONT_CREATE_INDEXES_AUTOMATICALLY) {
|
|
1371
1457
|
createIndexes();
|
|
1372
1458
|
}
|
|
@@ -1402,7 +1488,7 @@ function MongoCollection(options) {
|
|
|
1402
1488
|
}
|
|
1403
1489
|
|
|
1404
1490
|
// src/encrypted/getOrCreateEncryptionKey.ts
|
|
1405
|
-
import { logger as
|
|
1491
|
+
import { logger as logger5 } from "@orion-js/logger";
|
|
1406
1492
|
import { ClientEncryption, MongoClient as MongoClient2 } from "mongodb";
|
|
1407
1493
|
async function getOrCreateEncryptionKey({
|
|
1408
1494
|
keyAltName,
|
|
@@ -1414,7 +1500,7 @@ async function getOrCreateEncryptionKey({
|
|
|
1414
1500
|
kmsProviders
|
|
1415
1501
|
}) {
|
|
1416
1502
|
const keyVaultNamespace = `${keyVaultDatabase}.${keyVaultCollection}`;
|
|
1417
|
-
|
|
1503
|
+
logger5.info("Connecting to database to get or create the encryption key", {
|
|
1418
1504
|
keyVaultNamespace,
|
|
1419
1505
|
keyAltName
|
|
1420
1506
|
});
|
|
@@ -1432,14 +1518,14 @@ async function getOrCreateEncryptionKey({
|
|
|
1432
1518
|
});
|
|
1433
1519
|
const key = await clientEncryption.getKeyByAltName(keyAltName);
|
|
1434
1520
|
if (key) {
|
|
1435
|
-
|
|
1521
|
+
logger5.info("Key found on the key vault", {
|
|
1436
1522
|
keyVaultNamespace,
|
|
1437
1523
|
keyAltName,
|
|
1438
1524
|
UUID: key._id
|
|
1439
1525
|
});
|
|
1440
1526
|
return { key: key._id, keyVaultNamespace };
|
|
1441
1527
|
}
|
|
1442
|
-
|
|
1528
|
+
logger5.info("Key not found on the key vault, creating a new one", {
|
|
1443
1529
|
keyVaultNamespace,
|
|
1444
1530
|
keyAltName
|
|
1445
1531
|
});
|
|
@@ -1447,7 +1533,7 @@ async function getOrCreateEncryptionKey({
|
|
|
1447
1533
|
keyAltNames: [keyAltName],
|
|
1448
1534
|
...masterKey ? { masterKey } : {}
|
|
1449
1535
|
});
|
|
1450
|
-
|
|
1536
|
+
logger5.info("New encryption key created", {
|
|
1451
1537
|
keyVaultNamespace,
|
|
1452
1538
|
keyAltName,
|
|
1453
1539
|
UUID: newKey
|