@sprucelabs/data-stores 31.0.7 → 31.0.9

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.
@@ -36,7 +36,6 @@ export default class MongoDatabase implements Database {
36
36
  syncIndexes(collectionName: string, indexes: Index[]): Promise<void>;
37
37
  private _syncIndexes;
38
38
  createUniqueIndex(collection: string, index: string[] | IndexWithFilter): Promise<void>;
39
- private generateIndexName;
40
39
  private normalizeIndex;
41
40
  syncUniqueIndexes(collectionName: string, indexes: Index[]): Promise<void>;
42
41
  update(collection: string, query: Record<string, any>, updates: Record<string, any>): Promise<number>;
@@ -236,10 +236,11 @@ class MongoDatabase {
236
236
  }
237
237
  async dropIndex(collection, index) {
238
238
  const indexes = await this.listIndexes(collection);
239
- const name = this.generateIndexName(this.normalizeIndex(index));
239
+ const name = this.normalizeIndex(index).name;
240
240
  let found = false;
241
241
  for (const thisIndex of indexes) {
242
- if (thisIndex.name === name) {
242
+ if (this.normalizeIndex(this.mongoIndexToIndexWithFilter(thisIndex))
243
+ .name === name) {
243
244
  await this.assertDbWhileAttempingTo('drop a index.', collection)
244
245
  .collection(collection)
245
246
  .dropIndex(thisIndex.name);
@@ -260,10 +261,10 @@ class MongoDatabase {
260
261
  const uniqueIndexes = [];
261
262
  for (const index of indexes) {
262
263
  if (index.unique) {
263
- uniqueIndexes.push({
264
+ uniqueIndexes.push(this.normalizeIndex({
264
265
  fields: Object.keys(index.key),
265
266
  filter: index.partialFilterExpression,
266
- });
267
+ }));
267
268
  }
268
269
  }
269
270
  return uniqueIndexes;
@@ -291,31 +292,32 @@ class MongoDatabase {
291
292
  }
292
293
  }
293
294
  mongoIndexToIndexWithFilter(index) {
294
- return {
295
+ return (0, database_utilities_1.normalizeIndex)({
295
296
  fields: Object.keys(index.key),
296
297
  filter: index.partialFilterExpression,
297
298
  name: index.name,
298
- };
299
+ });
299
300
  }
300
301
  async createIndex(collection, index) {
301
302
  const currentIndexes = await this.getIndexes(collection);
302
303
  this.assertIndexDoesNotExist(currentIndexes, index, collection);
303
304
  const indexSpec = {};
304
- this.normalizeIndex(index).fields.forEach((name) => {
305
+ const normalized = this.normalizeIndex(index);
306
+ normalized.fields.forEach((name) => {
305
307
  indexSpec[name] = 1;
306
308
  });
307
309
  try {
308
310
  await this.assertDbWhileAttempingTo('create an index.', collection)
309
311
  .collection(collection)
310
312
  .createIndex(indexSpec, {
311
- name: this.generateIndexName(index),
313
+ name: normalized.name,
312
314
  });
313
315
  }
314
316
  catch (err) {
315
317
  if ((err === null || err === void 0 ? void 0 : err.code) === 11000) {
316
318
  throw new SpruceError_1.default({
317
319
  code: 'DUPLICATE_KEY',
318
- friendlyMessage: `Could not create index! Index on '${collection}' has duplicate key for "${this.normalizeIndex(index).fields.join(',')}"`,
320
+ friendlyMessage: `Could not create index! Index on '${collection}' has duplicate key for "${normalized.fields.join(',')}"`,
319
321
  });
320
322
  }
321
323
  else {
@@ -338,9 +340,11 @@ class MongoDatabase {
338
340
  async syncIndexes(collectionName, indexes) {
339
341
  await this._syncIndexes(collectionName, indexes, 'createIndex');
340
342
  }
341
- async _syncIndexes(collectionName, indexes, func, shouldIncludeUnique = false) {
343
+ async _syncIndexes(collectionName, indexes, func, isSyncingUniqueIndexes = false) {
342
344
  var _a;
343
- const currentIndexes = await this.getIndexes(collectionName, shouldIncludeUnique);
345
+ const currentIndexes = isSyncingUniqueIndexes
346
+ ? await this.getUniqueIndexes(collectionName)
347
+ : await this.getIndexes(collectionName);
344
348
  const indexesToDelete = (0, database_utilities_1.pluckMissingIndexes)(currentIndexes, indexes);
345
349
  for (const extra of indexesToDelete) {
346
350
  await this.dropIndex(collectionName, extra);
@@ -369,7 +373,7 @@ class MongoDatabase {
369
373
  try {
370
374
  const options = {
371
375
  unique: true,
372
- name: this.generateIndexName(indexWithFilter),
376
+ name: indexWithFilter.name,
373
377
  };
374
378
  if (indexWithFilter.filter) {
375
379
  options.partialFilterExpression = indexWithFilter.filter;
@@ -391,9 +395,6 @@ class MongoDatabase {
391
395
  }
392
396
  }
393
397
  }
394
- generateIndexName(indexWithFilter) {
395
- return (0, database_utilities_1.generateIndexName)(this.normalizeIndex(indexWithFilter));
396
- }
397
398
  normalizeIndex(index) {
398
399
  return (0, database_utilities_1.normalizeIndex)(index);
399
400
  }
@@ -440,31 +440,37 @@ class NeDbDatabase extends AbstractMutexer_1.default {
440
440
  col._indexes = [];
441
441
  }
442
442
  await this.randomDelay();
443
- this.assertIndexDoesNotExist(col._indexes, this.normalizeIndex(fields), collection);
444
- col._indexes.push({ fields });
443
+ const normalized = this.normalizeIndex(fields);
444
+ this.assertIndexDoesNotExist(col._indexes, normalized, collection);
445
+ col._indexes.push(normalized);
445
446
  }
446
447
  normalizeIndex(index) {
447
- const { fields, filter } = (0, database_utilities_1.normalizeIndex)(index);
448
- return { fields, filter };
448
+ return (0, database_utilities_1.normalizeIndex)(index);
449
449
  }
450
450
  async syncUniqueIndexes(collectionName, indexes) {
451
451
  var _a;
452
+ await this.lock('syncUniqueIndexesMutex');
452
453
  const currentIndexes = await this.getUniqueIndexes(collectionName);
453
454
  const toDelete = (0, database_utilities_1.pluckMissingIndexes)(currentIndexes, indexes);
454
- for (const index of indexes) {
455
- if (!this.doesInclude(currentIndexes, index)) {
456
- try {
457
- await this.createUniqueIndex(collectionName, index);
458
- }
459
- catch (err) {
460
- if (((_a = err.options) === null || _a === void 0 ? void 0 : _a.code) !== 'INDEX_EXISTS') {
461
- throw err;
455
+ try {
456
+ for (const index of indexes) {
457
+ if (!this.doesInclude(currentIndexes, index)) {
458
+ try {
459
+ await this.createUniqueIndex(collectionName, index);
460
+ }
461
+ catch (err) {
462
+ if (((_a = err.options) === null || _a === void 0 ? void 0 : _a.code) !== 'INDEX_EXISTS') {
463
+ throw err;
464
+ }
462
465
  }
463
466
  }
464
467
  }
468
+ for (const extra of toDelete) {
469
+ await this.dropIndex(collectionName, extra);
470
+ }
465
471
  }
466
- for (const extra of toDelete) {
467
- await this.dropIndex(collectionName, extra);
472
+ finally {
473
+ this.unlock('syncUniqueIndexesMutex');
468
474
  }
469
475
  }
470
476
  async syncIndexes(collectionName, indexes) {
@@ -1,6 +1,5 @@
1
1
  import { IndexWithFilter, Index } from '../types/database.types';
2
2
  export declare function doesIndexesInclude(haystack: Index[], needle: Index): boolean;
3
3
  export declare function areIndexesEqual(left: Index, right: Index): boolean;
4
- export declare function generateIndexName(indexWithFilter: IndexWithFilter): string;
5
4
  export declare function normalizeIndex(index: Index): IndexWithFilter;
6
5
  export declare function pluckMissingIndexes(left: Index[], right: Index[]): Index[];
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.doesIndexesInclude = doesIndexesInclude;
7
7
  exports.areIndexesEqual = areIndexesEqual;
8
- exports.generateIndexName = generateIndexName;
9
8
  exports.normalizeIndex = normalizeIndex;
10
9
  exports.pluckMissingIndexes = pluckMissingIndexes;
11
10
  const differenceWith_1 = __importDefault(require("lodash/differenceWith"));
@@ -33,15 +32,17 @@ function generateIndexName(indexWithFilter) {
33
32
  return name;
34
33
  }
35
34
  function normalizeIndex(index) {
36
- var _a;
37
35
  const fields = Array.isArray(index) ? index : index.fields;
38
36
  const filter = Array.isArray(index) ? undefined : index.filter;
39
37
  fields.sort();
40
- return {
38
+ const normalized = {
41
39
  fields,
42
- filter,
43
- name: (_a = index.name) !== null && _a !== void 0 ? _a : undefined,
44
40
  };
41
+ if (filter) {
42
+ normalized.filter = filter;
43
+ }
44
+ normalized.name = generateIndexName(normalized);
45
+ return normalized;
45
46
  }
46
47
  function pluckMissingIndexes(left, right) {
47
48
  return (0, differenceWith_1.default)(left, right, areIndexesEqual);
@@ -36,7 +36,6 @@ export default class MongoDatabase implements Database {
36
36
  syncIndexes(collectionName: string, indexes: Index[]): Promise<void>;
37
37
  private _syncIndexes;
38
38
  createUniqueIndex(collection: string, index: string[] | IndexWithFilter): Promise<void>;
39
- private generateIndexName;
40
39
  private normalizeIndex;
41
40
  syncUniqueIndexes(collectionName: string, indexes: Index[]): Promise<void>;
42
41
  update(collection: string, query: Record<string, any>, updates: Record<string, any>): Promise<number>;
@@ -23,7 +23,7 @@ import { MongoClient, MongoError, } from 'mongodb';
23
23
  import SpruceError from '../errors/SpruceError.js';
24
24
  import generateId from '../utilities/generateId.js';
25
25
  import mongoUtil from '../utilities/mongo.utility.js';
26
- import { doesIndexesInclude, generateIndexName, normalizeIndex, pluckMissingIndexes, } from './database.utilities.js';
26
+ import { doesIndexesInclude, normalizeIndex, pluckMissingIndexes, } from './database.utilities.js';
27
27
  export const MONGO_TEST_URI = 'mongodb://localhost:27017';
28
28
  export default class MongoDatabase {
29
29
  constructor(url, options) {
@@ -262,10 +262,11 @@ export default class MongoDatabase {
262
262
  dropIndex(collection, index) {
263
263
  return __awaiter(this, void 0, void 0, function* () {
264
264
  const indexes = yield this.listIndexes(collection);
265
- const name = this.generateIndexName(this.normalizeIndex(index));
265
+ const name = this.normalizeIndex(index).name;
266
266
  let found = false;
267
267
  for (const thisIndex of indexes) {
268
- if (thisIndex.name === name) {
268
+ if (this.normalizeIndex(this.mongoIndexToIndexWithFilter(thisIndex))
269
+ .name === name) {
269
270
  yield this.assertDbWhileAttempingTo('drop a index.', collection)
270
271
  .collection(collection)
271
272
  .dropIndex(thisIndex.name);
@@ -288,10 +289,10 @@ export default class MongoDatabase {
288
289
  const uniqueIndexes = [];
289
290
  for (const index of indexes) {
290
291
  if (index.unique) {
291
- uniqueIndexes.push({
292
+ uniqueIndexes.push(this.normalizeIndex({
292
293
  fields: Object.keys(index.key),
293
294
  filter: index.partialFilterExpression,
294
- });
295
+ }));
295
296
  }
296
297
  }
297
298
  return uniqueIndexes;
@@ -322,32 +323,33 @@ export default class MongoDatabase {
322
323
  });
323
324
  }
324
325
  mongoIndexToIndexWithFilter(index) {
325
- return {
326
+ return normalizeIndex({
326
327
  fields: Object.keys(index.key),
327
328
  filter: index.partialFilterExpression,
328
329
  name: index.name,
329
- };
330
+ });
330
331
  }
331
332
  createIndex(collection, index) {
332
333
  return __awaiter(this, void 0, void 0, function* () {
333
334
  const currentIndexes = yield this.getIndexes(collection);
334
335
  this.assertIndexDoesNotExist(currentIndexes, index, collection);
335
336
  const indexSpec = {};
336
- this.normalizeIndex(index).fields.forEach((name) => {
337
+ const normalized = this.normalizeIndex(index);
338
+ normalized.fields.forEach((name) => {
337
339
  indexSpec[name] = 1;
338
340
  });
339
341
  try {
340
342
  yield this.assertDbWhileAttempingTo('create an index.', collection)
341
343
  .collection(collection)
342
344
  .createIndex(indexSpec, {
343
- name: this.generateIndexName(index),
345
+ name: normalized.name,
344
346
  });
345
347
  }
346
348
  catch (err) {
347
349
  if ((err === null || err === void 0 ? void 0 : err.code) === 11000) {
348
350
  throw new SpruceError({
349
351
  code: 'DUPLICATE_KEY',
350
- friendlyMessage: `Could not create index! Index on '${collection}' has duplicate key for "${this.normalizeIndex(index).fields.join(',')}"`,
352
+ friendlyMessage: `Could not create index! Index on '${collection}' has duplicate key for "${normalized.fields.join(',')}"`,
351
353
  });
352
354
  }
353
355
  else {
@@ -374,9 +376,11 @@ export default class MongoDatabase {
374
376
  });
375
377
  }
376
378
  _syncIndexes(collectionName_1, indexes_1, func_1) {
377
- return __awaiter(this, arguments, void 0, function* (collectionName, indexes, func, shouldIncludeUnique = false) {
379
+ return __awaiter(this, arguments, void 0, function* (collectionName, indexes, func, isSyncingUniqueIndexes = false) {
378
380
  var _a;
379
- const currentIndexes = yield this.getIndexes(collectionName, shouldIncludeUnique);
381
+ const currentIndexes = isSyncingUniqueIndexes
382
+ ? yield this.getUniqueIndexes(collectionName)
383
+ : yield this.getIndexes(collectionName);
380
384
  const indexesToDelete = pluckMissingIndexes(currentIndexes, indexes);
381
385
  for (const extra of indexesToDelete) {
382
386
  yield this.dropIndex(collectionName, extra);
@@ -407,7 +411,7 @@ export default class MongoDatabase {
407
411
  try {
408
412
  const options = {
409
413
  unique: true,
410
- name: this.generateIndexName(indexWithFilter),
414
+ name: indexWithFilter.name,
411
415
  };
412
416
  if (indexWithFilter.filter) {
413
417
  options.partialFilterExpression = indexWithFilter.filter;
@@ -430,9 +434,6 @@ export default class MongoDatabase {
430
434
  }
431
435
  });
432
436
  }
433
- generateIndexName(indexWithFilter) {
434
- return generateIndexName(this.normalizeIndex(indexWithFilter));
435
- }
436
437
  normalizeIndex(index) {
437
438
  return normalizeIndex(index);
438
439
  }
@@ -485,33 +485,39 @@ export default class NeDbDatabase extends AbstractMutexer {
485
485
  col._indexes = [];
486
486
  }
487
487
  yield this.randomDelay();
488
- this.assertIndexDoesNotExist(col._indexes, this.normalizeIndex(fields), collection);
489
- col._indexes.push({ fields });
488
+ const normalized = this.normalizeIndex(fields);
489
+ this.assertIndexDoesNotExist(col._indexes, normalized, collection);
490
+ col._indexes.push(normalized);
490
491
  });
491
492
  }
492
493
  normalizeIndex(index) {
493
- const { fields, filter } = normalizeIndex(index);
494
- return { fields, filter };
494
+ return normalizeIndex(index);
495
495
  }
496
496
  syncUniqueIndexes(collectionName, indexes) {
497
497
  return __awaiter(this, void 0, void 0, function* () {
498
498
  var _a;
499
+ yield this.lock('syncUniqueIndexesMutex');
499
500
  const currentIndexes = yield this.getUniqueIndexes(collectionName);
500
501
  const toDelete = pluckMissingIndexes(currentIndexes, indexes);
501
- for (const index of indexes) {
502
- if (!this.doesInclude(currentIndexes, index)) {
503
- try {
504
- yield this.createUniqueIndex(collectionName, index);
505
- }
506
- catch (err) {
507
- if (((_a = err.options) === null || _a === void 0 ? void 0 : _a.code) !== 'INDEX_EXISTS') {
508
- throw err;
502
+ try {
503
+ for (const index of indexes) {
504
+ if (!this.doesInclude(currentIndexes, index)) {
505
+ try {
506
+ yield this.createUniqueIndex(collectionName, index);
507
+ }
508
+ catch (err) {
509
+ if (((_a = err.options) === null || _a === void 0 ? void 0 : _a.code) !== 'INDEX_EXISTS') {
510
+ throw err;
511
+ }
509
512
  }
510
513
  }
511
514
  }
515
+ for (const extra of toDelete) {
516
+ yield this.dropIndex(collectionName, extra);
517
+ }
512
518
  }
513
- for (const extra of toDelete) {
514
- yield this.dropIndex(collectionName, extra);
519
+ finally {
520
+ this.unlock('syncUniqueIndexesMutex');
515
521
  }
516
522
  });
517
523
  }
@@ -1,6 +1,5 @@
1
1
  import { IndexWithFilter, Index } from '../types/database.types';
2
2
  export declare function doesIndexesInclude(haystack: Index[], needle: Index): boolean;
3
3
  export declare function areIndexesEqual(left: Index, right: Index): boolean;
4
- export declare function generateIndexName(indexWithFilter: IndexWithFilter): string;
5
4
  export declare function normalizeIndex(index: Index): IndexWithFilter;
6
5
  export declare function pluckMissingIndexes(left: Index[], right: Index[]): Index[];
@@ -12,7 +12,7 @@ export function areIndexesEqual(left, right) {
12
12
  const name2 = generateIndexName(normalizeIndex(right));
13
13
  return name1 === name2;
14
14
  }
15
- export function generateIndexName(indexWithFilter) {
15
+ function generateIndexName(indexWithFilter) {
16
16
  if (indexWithFilter.name) {
17
17
  return indexWithFilter.name;
18
18
  }
@@ -23,15 +23,17 @@ export function generateIndexName(indexWithFilter) {
23
23
  return name;
24
24
  }
25
25
  export function normalizeIndex(index) {
26
- var _a;
27
26
  const fields = Array.isArray(index) ? index : index.fields;
28
27
  const filter = Array.isArray(index) ? undefined : index.filter;
29
28
  fields.sort();
30
- return {
29
+ const normalized = {
31
30
  fields,
32
- filter,
33
- name: (_a = index.name) !== null && _a !== void 0 ? _a : undefined,
34
31
  };
32
+ if (filter) {
33
+ normalized.filter = filter;
34
+ }
35
+ normalized.name = generateIndexName(normalized);
36
+ return normalized;
35
37
  }
36
38
  export function pluckMissingIndexes(left, right) {
37
39
  return differenceWith(left, right, areIndexesEqual);
@@ -1,6 +1,6 @@
1
1
  import { Database, IndexWithFilter, TestConnect } from '../types/database.types';
2
2
  import { DataStore } from '../types/stores.types';
3
- declare const methods: readonly ["assertThrowsWithInvalidConnectionString", "assertThrowsWhenCantConnect", "assertThrowsWithBadDatabaseName", "assertKnowsIfConnectionClosed", "assertCanSortDesc", "assertCanSortAsc", "assertCanSortById", "assertCanQueryWithOr", "assertGeneratesIdDifferentEachTime", "assertInsertingGeneratesId", "assertCanCreateMany", "assertCanCreateWithObjectField", "assertCanCountOnId", "assertCanCount", "assertThrowsWhenUpdatingRecordNotFound", "assertCanUpdate", "assertCanUpdateMany", "assertCanPushOntoArrayValue", "assertCanUpdateWithObjectField", "assertCanUpdateFieldInObjectFieldWithTargettedWhere", "assertCanSaveAndGetNullAndUndefined", "assertUpdateReturnsMatchedCounts", "assertCanUpsertOne", "assertCanUpsertNull", "assertCanPushToArrayOnUpsert", "assertCanSyncUniqueIndexesWithFilterExpression", "assertEmptyDatabaseReturnsEmptyArray", "assertFindOneOnEmptyDatabaseReturnsNull", "assertCanLimitResults", "assertCanLimitResultsToZero", "assertCanFindWithBooleanField", "assertCanQueryByGtLtGteLteNe", "assertCanQueryPathWithDotSyntax", "assertCanReturnOnlySelectFields", "assertCanSearchByRegex", "assertCanFindWithNe", "assertCanFindWithIn", "assertCanFindOrWithBadIdField", "assertCanDeleteRecord", "assertCanDeleteOne", "assertHasNoUniqueIndexToStart", "assertCanCreateUniqueIndex", "assertCanCreateMultiFieldUniqueIndex", "assertCantCreateUniqueIndexTwice", "assertCanDropUniqueIndex", "assertCanDropCompoundUniqueIndex", "assertCantDropUniqueIndexThatDoesntExist", "assertCantDropIndexWhenNoIndexExists", "assertCantDropCompoundUniqueIndexThatDoesntExist", "assertSyncingUniqueIndexesAddsMissingIndexes", "assertSyncingUniqueIndexesSkipsExistingIndexes", "assertSyncingUniqueIndexesRemovesExtraIndexes", "assertSyncingUniqueIndexesIsRaceProof", "assertSyncingIndexesDoesNotAddAndRemove", "assertUniqueIndexBlocksDuplicates", "assertDuplicateKeyThrowsOnInsert", "assertSettingUniqueIndexViolationThrowsSpruceError", "assertCanCreateUniqueIndexOnNestedField", "assertUpsertWithUniqueIndex", "assertNestedFieldIndexUpdates", "assertHasNoIndexToStart", "assertCanCreateIndex", "assertCantCreateSameIndexTwice", "assertCanCreateMultiFieldIndex", "assertCanDropIndex", "assertCanDropCompoundIndex", "assertCantDropCompoundIndexThatDoesNotExist", "assertSyncIndexesSkipsExisting", "assertSyncIndexesRemovesExtraIndexes", "assertSyncIndexesHandlesRaceConditions", "assertSyncIndexesDoesNotRemoveExisting", "assertDuplicateFieldsWithMultipleUniqueIndexesWorkAsExpected", "assertCanSyncIndexesWithoutPartialThenAgainWithProperlyUpdates"];
3
+ declare const methods: readonly ["assertThrowsWithInvalidConnectionString", "assertThrowsWhenCantConnect", "assertThrowsWithBadDatabaseName", "assertKnowsIfConnectionClosed", "assertCanSortDesc", "assertCanSortAsc", "assertCanSortById", "assertCanQueryWithOr", "assertGeneratesIdDifferentEachTime", "assertInsertingGeneratesId", "assertCanCreateMany", "assertCanCreateWithObjectField", "assertCanCountOnId", "assertCanCount", "assertThrowsWhenUpdatingRecordNotFound", "assertCanUpdate", "assertCanUpdateMany", "assertCanPushOntoArrayValue", "assertCanUpdateWithObjectField", "assertCanUpdateFieldInObjectFieldWithTargettedWhere", "assertCanSaveAndGetNullAndUndefined", "assertUpdateReturnsMatchedCounts", "assertCanUpsertOne", "assertCanUpsertNull", "assertCanPushToArrayOnUpsert", "assertCanSyncUniqueIndexesWithFilterExpression", "assertEmptyDatabaseReturnsEmptyArray", "assertFindOneOnEmptyDatabaseReturnsNull", "assertCanLimitResults", "assertCanLimitResultsToZero", "assertCanFindWithBooleanField", "assertCanQueryByGtLtGteLteNe", "assertCanQueryPathWithDotSyntax", "assertCanReturnOnlySelectFields", "assertCanSearchByRegex", "assertCanFindWithNe", "assertCanFindWithIn", "assertCanFindOrWithBadIdField", "assertCanDeleteRecord", "assertCanDeleteOne", "assertHasNoUniqueIndexToStart", "assertCanCreateUniqueIndex", "assertCanCreateMultiFieldUniqueIndex", "assertCantCreateUniqueIndexTwice", "assertCanDropUniqueIndex", "assertCanDropCompoundUniqueIndex", "assertCantDropUniqueIndexThatDoesntExist", "assertCantDropIndexWhenNoIndexExists", "assertCantDropCompoundUniqueIndexThatDoesntExist", "assertSyncingUniqueIndexesAddsMissingIndexes", "assertSyncingUniqueIndexesSkipsExistingUniqueIndexes", "assertSyncingUniqueIndexesRemovesExtraUniqueIndexes", "assertSyncingUniqueIndexesIsRaceProof", "assertSyncUniqueIndexesSkipsOnesThatExist", "assertUniqueIndexBlocksDuplicates", "assertDuplicateKeyThrowsOnInsert", "assertSettingUniqueIndexViolationThrowsSpruceError", "assertCanCreateUniqueIndexOnNestedField", "assertUpsertWithUniqueIndex", "assertNestedFieldIndexUpdates", "assertHasNoIndexToStart", "assertCanCreateIndex", "assertCantCreateSameIndexTwice", "assertCanCreateMultiFieldIndex", "assertCanDropIndex", "assertCanDropCompoundIndex", "assertCantDropCompoundIndexThatDoesNotExist", "assertSyncIndexesSkipsExisting", "assertSyncIndexesRemovesExtraIndexes", "assertSyncIndexesHandlesRaceConditions", "assertSyncIndexesDoesNotRemoveExisting", "assertDuplicateFieldsWithMultipleUniqueIndexesWorkAsExpected", "assertCanSyncIndexesWithoutPartialThenAgainWithProperlyUpdates"];
4
4
  type OriginalMethods = (typeof methods)[number];
5
5
  type BangMethods = `!${OriginalMethods}`;
6
6
  export type DatabaseAssertionName = OriginalMethods | BangMethods;
@@ -37,9 +37,9 @@ declare const databaseAssertUtil: {
37
37
  assertCanCreateMultiFieldUniqueIndex(connect: TestConnect): Promise<void>;
38
38
  assertSettingUniqueIndexViolationThrowsSpruceError(connect: TestConnect): Promise<void>;
39
39
  assertDuplicateKeyThrowsOnInsert(connect: TestConnect): Promise<void>;
40
- assertSyncingIndexesDoesNotAddAndRemove(connect: TestConnect): Promise<void>;
41
- assertSyncingUniqueIndexesRemovesExtraIndexes(connect: TestConnect): Promise<void>;
42
- assertSyncingUniqueIndexesSkipsExistingIndexes(connect: TestConnect): Promise<void>;
40
+ assertSyncUniqueIndexesSkipsOnesThatExist(connect: TestConnect): Promise<void>;
41
+ assertSyncingUniqueIndexesRemovesExtraUniqueIndexes(connect: TestConnect): Promise<void>;
42
+ assertSyncingUniqueIndexesSkipsExistingUniqueIndexes(connect: TestConnect): Promise<void>;
43
43
  assertSyncingUniqueIndexesAddsMissingIndexes(connect: TestConnect): Promise<void>;
44
44
  assertCantDropCompoundUniqueIndexThatDoesntExist(connect: TestConnect): Promise<void>;
45
45
  assertCantDropIndexWhenNoIndexExists(connect: TestConnect): Promise<void>;
@@ -49,6 +49,7 @@ declare const databaseAssertUtil: {
49
49
  assertCantCreateUniqueIndexTwice(connect: TestConnect): Promise<void>;
50
50
  assertSyncingUniqueIndexesIsRaceProof(connect: TestConnect): Promise<void>;
51
51
  assertUniqueIndexBlocksDuplicates(connect: TestConnect): Promise<void>;
52
+ syncingUniqueIndexDoesNotTouchNonUniqueIndexes(connect: TestConnect): Promise<void>;
52
53
  assertCanCreateUniqueIndexOnNestedField(connect: TestConnect): Promise<void>;
53
54
  assertCanPushToArrayOnUpsert(connect: TestConnect): Promise<void>;
54
55
  assertCanSearchByRegex(connect: TestConnect): Promise<void>;
@@ -70,10 +70,10 @@ const methods = [
70
70
  'assertCantDropIndexWhenNoIndexExists',
71
71
  'assertCantDropCompoundUniqueIndexThatDoesntExist',
72
72
  'assertSyncingUniqueIndexesAddsMissingIndexes',
73
- 'assertSyncingUniqueIndexesSkipsExistingIndexes',
74
- 'assertSyncingUniqueIndexesRemovesExtraIndexes',
73
+ 'assertSyncingUniqueIndexesSkipsExistingUniqueIndexes',
74
+ 'assertSyncingUniqueIndexesRemovesExtraUniqueIndexes',
75
75
  'assertSyncingUniqueIndexesIsRaceProof',
76
- 'assertSyncingIndexesDoesNotAddAndRemove',
76
+ 'assertSyncUniqueIndexesSkipsOnesThatExist',
77
77
  'assertUniqueIndexBlocksDuplicates',
78
78
  'assertDuplicateKeyThrowsOnInsert',
79
79
  'assertSettingUniqueIndexViolationThrowsSpruceError',
@@ -747,7 +747,7 @@ const databaseAssertUtil = {
747
747
  yield this.shutdown(db);
748
748
  });
749
749
  },
750
- assertSyncingIndexesDoesNotAddAndRemove(connect) {
750
+ assertSyncUniqueIndexesSkipsOnesThatExist(connect) {
751
751
  return __awaiter(this, void 0, void 0, function* () {
752
752
  const db = yield connectToDabatase(connect);
753
753
  yield db.createUniqueIndex(this.collectionName, ['otherField']);
@@ -765,7 +765,7 @@ const databaseAssertUtil = {
765
765
  yield this.shutdown(db);
766
766
  });
767
767
  },
768
- assertSyncingUniqueIndexesRemovesExtraIndexes(connect) {
768
+ assertSyncingUniqueIndexesRemovesExtraUniqueIndexes(connect) {
769
769
  return __awaiter(this, void 0, void 0, function* () {
770
770
  const db = yield connectToDabatase(connect);
771
771
  yield db.syncUniqueIndexes(this.collectionName, [
@@ -800,7 +800,7 @@ const databaseAssertUtil = {
800
800
  yield this.shutdown(db);
801
801
  });
802
802
  },
803
- assertSyncingUniqueIndexesSkipsExistingIndexes(connect) {
803
+ assertSyncingUniqueIndexesSkipsExistingUniqueIndexes(connect) {
804
804
  return __awaiter(this, void 0, void 0, function* () {
805
805
  const db = yield connectToDabatase(connect);
806
806
  yield db.syncUniqueIndexes(this.collectionName, [['uniqueField']]);
@@ -925,6 +925,7 @@ const databaseAssertUtil = {
925
925
  assertSyncingUniqueIndexesIsRaceProof(connect) {
926
926
  return __awaiter(this, void 0, void 0, function* () {
927
927
  const db = yield connectToDabatase(connect);
928
+ debugger;
928
929
  const syncs = [
929
930
  db.syncUniqueIndexes(this.collectionName, [
930
931
  ['otherField', 'otherField2'],
@@ -958,6 +959,9 @@ const databaseAssertUtil = {
958
959
  ]),
959
960
  ];
960
961
  yield Promise.all(syncs);
962
+ const saved = yield db.getUniqueIndexes(this.collectionName);
963
+ assert.isLength(saved, 1, 'After many simultaneous syncUniqueIndexes() calls, there should only be one unique index created.');
964
+ assert.isEqualDeep(saved[0].fields, ['otherField', 'otherField2'], 'After many simultaneous syncUniqueIndexes() calls, the unique index created does not have the expected fields.');
961
965
  yield this.shutdown(db);
962
966
  });
963
967
  },
@@ -1017,6 +1021,28 @@ const databaseAssertUtil = {
1017
1021
  yield this.shutdown(db);
1018
1022
  });
1019
1023
  },
1024
+ syncingUniqueIndexDoesNotTouchNonUniqueIndexes(connect) {
1025
+ return __awaiter(this, void 0, void 0, function* () {
1026
+ const db = yield connectToDabatase(connect);
1027
+ yield db.createIndex(this.collectionName, ['someField']);
1028
+ yield db.syncUniqueIndexes(this.collectionName, [['uniqueField']]);
1029
+ const indexes = yield db.getIndexes(this.collectionName);
1030
+ const uniqueIndexes = yield db.getUniqueIndexes(this.collectionName);
1031
+ assert.isEqualDeep(indexes, [
1032
+ {
1033
+ fields: ['someField'],
1034
+ name: 'someField',
1035
+ },
1036
+ ], 'index was modified when syncing unique indexes');
1037
+ assert.isEqualDeep(uniqueIndexes, [
1038
+ {
1039
+ fields: ['uniqueField'],
1040
+ name: 'uniqueField',
1041
+ },
1042
+ ], 'unique indexes are not as expected after syncing unique indexes');
1043
+ yield this.shutdown(db);
1044
+ });
1045
+ },
1020
1046
  assertCanCreateUniqueIndexOnNestedField(connect) {
1021
1047
  return __awaiter(this, void 0, void 0, function* () {
1022
1048
  var _a;
@@ -1,6 +1,6 @@
1
1
  import { Database, IndexWithFilter, TestConnect } from '../types/database.types';
2
2
  import { DataStore } from '../types/stores.types';
3
- declare const methods: readonly ["assertThrowsWithInvalidConnectionString", "assertThrowsWhenCantConnect", "assertThrowsWithBadDatabaseName", "assertKnowsIfConnectionClosed", "assertCanSortDesc", "assertCanSortAsc", "assertCanSortById", "assertCanQueryWithOr", "assertGeneratesIdDifferentEachTime", "assertInsertingGeneratesId", "assertCanCreateMany", "assertCanCreateWithObjectField", "assertCanCountOnId", "assertCanCount", "assertThrowsWhenUpdatingRecordNotFound", "assertCanUpdate", "assertCanUpdateMany", "assertCanPushOntoArrayValue", "assertCanUpdateWithObjectField", "assertCanUpdateFieldInObjectFieldWithTargettedWhere", "assertCanSaveAndGetNullAndUndefined", "assertUpdateReturnsMatchedCounts", "assertCanUpsertOne", "assertCanUpsertNull", "assertCanPushToArrayOnUpsert", "assertCanSyncUniqueIndexesWithFilterExpression", "assertEmptyDatabaseReturnsEmptyArray", "assertFindOneOnEmptyDatabaseReturnsNull", "assertCanLimitResults", "assertCanLimitResultsToZero", "assertCanFindWithBooleanField", "assertCanQueryByGtLtGteLteNe", "assertCanQueryPathWithDotSyntax", "assertCanReturnOnlySelectFields", "assertCanSearchByRegex", "assertCanFindWithNe", "assertCanFindWithIn", "assertCanFindOrWithBadIdField", "assertCanDeleteRecord", "assertCanDeleteOne", "assertHasNoUniqueIndexToStart", "assertCanCreateUniqueIndex", "assertCanCreateMultiFieldUniqueIndex", "assertCantCreateUniqueIndexTwice", "assertCanDropUniqueIndex", "assertCanDropCompoundUniqueIndex", "assertCantDropUniqueIndexThatDoesntExist", "assertCantDropIndexWhenNoIndexExists", "assertCantDropCompoundUniqueIndexThatDoesntExist", "assertSyncingUniqueIndexesAddsMissingIndexes", "assertSyncingUniqueIndexesSkipsExistingIndexes", "assertSyncingUniqueIndexesRemovesExtraIndexes", "assertSyncingUniqueIndexesIsRaceProof", "assertSyncingIndexesDoesNotAddAndRemove", "assertUniqueIndexBlocksDuplicates", "assertDuplicateKeyThrowsOnInsert", "assertSettingUniqueIndexViolationThrowsSpruceError", "assertCanCreateUniqueIndexOnNestedField", "assertUpsertWithUniqueIndex", "assertNestedFieldIndexUpdates", "assertHasNoIndexToStart", "assertCanCreateIndex", "assertCantCreateSameIndexTwice", "assertCanCreateMultiFieldIndex", "assertCanDropIndex", "assertCanDropCompoundIndex", "assertCantDropCompoundIndexThatDoesNotExist", "assertSyncIndexesSkipsExisting", "assertSyncIndexesRemovesExtraIndexes", "assertSyncIndexesHandlesRaceConditions", "assertSyncIndexesDoesNotRemoveExisting", "assertDuplicateFieldsWithMultipleUniqueIndexesWorkAsExpected", "assertCanSyncIndexesWithoutPartialThenAgainWithProperlyUpdates"];
3
+ declare const methods: readonly ["assertThrowsWithInvalidConnectionString", "assertThrowsWhenCantConnect", "assertThrowsWithBadDatabaseName", "assertKnowsIfConnectionClosed", "assertCanSortDesc", "assertCanSortAsc", "assertCanSortById", "assertCanQueryWithOr", "assertGeneratesIdDifferentEachTime", "assertInsertingGeneratesId", "assertCanCreateMany", "assertCanCreateWithObjectField", "assertCanCountOnId", "assertCanCount", "assertThrowsWhenUpdatingRecordNotFound", "assertCanUpdate", "assertCanUpdateMany", "assertCanPushOntoArrayValue", "assertCanUpdateWithObjectField", "assertCanUpdateFieldInObjectFieldWithTargettedWhere", "assertCanSaveAndGetNullAndUndefined", "assertUpdateReturnsMatchedCounts", "assertCanUpsertOne", "assertCanUpsertNull", "assertCanPushToArrayOnUpsert", "assertCanSyncUniqueIndexesWithFilterExpression", "assertEmptyDatabaseReturnsEmptyArray", "assertFindOneOnEmptyDatabaseReturnsNull", "assertCanLimitResults", "assertCanLimitResultsToZero", "assertCanFindWithBooleanField", "assertCanQueryByGtLtGteLteNe", "assertCanQueryPathWithDotSyntax", "assertCanReturnOnlySelectFields", "assertCanSearchByRegex", "assertCanFindWithNe", "assertCanFindWithIn", "assertCanFindOrWithBadIdField", "assertCanDeleteRecord", "assertCanDeleteOne", "assertHasNoUniqueIndexToStart", "assertCanCreateUniqueIndex", "assertCanCreateMultiFieldUniqueIndex", "assertCantCreateUniqueIndexTwice", "assertCanDropUniqueIndex", "assertCanDropCompoundUniqueIndex", "assertCantDropUniqueIndexThatDoesntExist", "assertCantDropIndexWhenNoIndexExists", "assertCantDropCompoundUniqueIndexThatDoesntExist", "assertSyncingUniqueIndexesAddsMissingIndexes", "assertSyncingUniqueIndexesSkipsExistingUniqueIndexes", "assertSyncingUniqueIndexesRemovesExtraUniqueIndexes", "assertSyncingUniqueIndexesIsRaceProof", "assertSyncUniqueIndexesSkipsOnesThatExist", "assertUniqueIndexBlocksDuplicates", "assertDuplicateKeyThrowsOnInsert", "assertSettingUniqueIndexViolationThrowsSpruceError", "assertCanCreateUniqueIndexOnNestedField", "assertUpsertWithUniqueIndex", "assertNestedFieldIndexUpdates", "assertHasNoIndexToStart", "assertCanCreateIndex", "assertCantCreateSameIndexTwice", "assertCanCreateMultiFieldIndex", "assertCanDropIndex", "assertCanDropCompoundIndex", "assertCantDropCompoundIndexThatDoesNotExist", "assertSyncIndexesSkipsExisting", "assertSyncIndexesRemovesExtraIndexes", "assertSyncIndexesHandlesRaceConditions", "assertSyncIndexesDoesNotRemoveExisting", "assertDuplicateFieldsWithMultipleUniqueIndexesWorkAsExpected", "assertCanSyncIndexesWithoutPartialThenAgainWithProperlyUpdates"];
4
4
  type OriginalMethods = (typeof methods)[number];
5
5
  type BangMethods = `!${OriginalMethods}`;
6
6
  export type DatabaseAssertionName = OriginalMethods | BangMethods;
@@ -37,9 +37,9 @@ declare const databaseAssertUtil: {
37
37
  assertCanCreateMultiFieldUniqueIndex(connect: TestConnect): Promise<void>;
38
38
  assertSettingUniqueIndexViolationThrowsSpruceError(connect: TestConnect): Promise<void>;
39
39
  assertDuplicateKeyThrowsOnInsert(connect: TestConnect): Promise<void>;
40
- assertSyncingIndexesDoesNotAddAndRemove(connect: TestConnect): Promise<void>;
41
- assertSyncingUniqueIndexesRemovesExtraIndexes(connect: TestConnect): Promise<void>;
42
- assertSyncingUniqueIndexesSkipsExistingIndexes(connect: TestConnect): Promise<void>;
40
+ assertSyncUniqueIndexesSkipsOnesThatExist(connect: TestConnect): Promise<void>;
41
+ assertSyncingUniqueIndexesRemovesExtraUniqueIndexes(connect: TestConnect): Promise<void>;
42
+ assertSyncingUniqueIndexesSkipsExistingUniqueIndexes(connect: TestConnect): Promise<void>;
43
43
  assertSyncingUniqueIndexesAddsMissingIndexes(connect: TestConnect): Promise<void>;
44
44
  assertCantDropCompoundUniqueIndexThatDoesntExist(connect: TestConnect): Promise<void>;
45
45
  assertCantDropIndexWhenNoIndexExists(connect: TestConnect): Promise<void>;
@@ -49,6 +49,7 @@ declare const databaseAssertUtil: {
49
49
  assertCantCreateUniqueIndexTwice(connect: TestConnect): Promise<void>;
50
50
  assertSyncingUniqueIndexesIsRaceProof(connect: TestConnect): Promise<void>;
51
51
  assertUniqueIndexBlocksDuplicates(connect: TestConnect): Promise<void>;
52
+ syncingUniqueIndexDoesNotTouchNonUniqueIndexes(connect: TestConnect): Promise<void>;
52
53
  assertCanCreateUniqueIndexOnNestedField(connect: TestConnect): Promise<void>;
53
54
  assertCanPushToArrayOnUpsert(connect: TestConnect): Promise<void>;
54
55
  assertCanSearchByRegex(connect: TestConnect): Promise<void>;
@@ -66,10 +66,10 @@ const methods = [
66
66
  'assertCantDropIndexWhenNoIndexExists',
67
67
  'assertCantDropCompoundUniqueIndexThatDoesntExist',
68
68
  'assertSyncingUniqueIndexesAddsMissingIndexes',
69
- 'assertSyncingUniqueIndexesSkipsExistingIndexes',
70
- 'assertSyncingUniqueIndexesRemovesExtraIndexes',
69
+ 'assertSyncingUniqueIndexesSkipsExistingUniqueIndexes',
70
+ 'assertSyncingUniqueIndexesRemovesExtraUniqueIndexes',
71
71
  'assertSyncingUniqueIndexesIsRaceProof',
72
- 'assertSyncingIndexesDoesNotAddAndRemove',
72
+ 'assertSyncUniqueIndexesSkipsOnesThatExist',
73
73
  'assertUniqueIndexBlocksDuplicates',
74
74
  'assertDuplicateKeyThrowsOnInsert',
75
75
  'assertSettingUniqueIndexViolationThrowsSpruceError',
@@ -683,7 +683,7 @@ const databaseAssertUtil = {
683
683
  });
684
684
  await this.shutdown(db);
685
685
  },
686
- async assertSyncingIndexesDoesNotAddAndRemove(connect) {
686
+ async assertSyncUniqueIndexesSkipsOnesThatExist(connect) {
687
687
  const db = await connectToDabatase(connect);
688
688
  await db.createUniqueIndex(this.collectionName, ['otherField']);
689
689
  await db.createUniqueIndex(this.collectionName, ['someField']);
@@ -699,7 +699,7 @@ const databaseAssertUtil = {
699
699
  ]);
700
700
  await this.shutdown(db);
701
701
  },
702
- async assertSyncingUniqueIndexesRemovesExtraIndexes(connect) {
702
+ async assertSyncingUniqueIndexesRemovesExtraUniqueIndexes(connect) {
703
703
  const db = await connectToDabatase(connect);
704
704
  await db.syncUniqueIndexes(this.collectionName, [
705
705
  ['uniqueField'],
@@ -732,7 +732,7 @@ const databaseAssertUtil = {
732
732
  test_utils_1.assert.isLength(indexes, 2, `Syncing unique indexes with filter is not removing extra indexes.`);
733
733
  await this.shutdown(db);
734
734
  },
735
- async assertSyncingUniqueIndexesSkipsExistingIndexes(connect) {
735
+ async assertSyncingUniqueIndexesSkipsExistingUniqueIndexes(connect) {
736
736
  const db = await connectToDabatase(connect);
737
737
  await db.syncUniqueIndexes(this.collectionName, [['uniqueField']]);
738
738
  let indexes = await db.getUniqueIndexes(this.collectionName);
@@ -840,6 +840,7 @@ const databaseAssertUtil = {
840
840
  },
841
841
  async assertSyncingUniqueIndexesIsRaceProof(connect) {
842
842
  const db = await connectToDabatase(connect);
843
+ debugger;
843
844
  const syncs = [
844
845
  db.syncUniqueIndexes(this.collectionName, [
845
846
  ['otherField', 'otherField2'],
@@ -873,6 +874,9 @@ const databaseAssertUtil = {
873
874
  ]),
874
875
  ];
875
876
  await Promise.all(syncs);
877
+ const saved = await db.getUniqueIndexes(this.collectionName);
878
+ test_utils_1.assert.isLength(saved, 1, 'After many simultaneous syncUniqueIndexes() calls, there should only be one unique index created.');
879
+ test_utils_1.assert.isEqualDeep(saved[0].fields, ['otherField', 'otherField2'], 'After many simultaneous syncUniqueIndexes() calls, the unique index created does not have the expected fields.');
876
880
  await this.shutdown(db);
877
881
  },
878
882
  async assertUniqueIndexBlocksDuplicates(connect) {
@@ -929,6 +933,26 @@ const databaseAssertUtil = {
929
933
  test_utils_2.errorAssert.assertError(err, 'DUPLICATE_RECORD');
930
934
  await this.shutdown(db);
931
935
  },
936
+ async syncingUniqueIndexDoesNotTouchNonUniqueIndexes(connect) {
937
+ const db = await connectToDabatase(connect);
938
+ await db.createIndex(this.collectionName, ['someField']);
939
+ await db.syncUniqueIndexes(this.collectionName, [['uniqueField']]);
940
+ const indexes = await db.getIndexes(this.collectionName);
941
+ const uniqueIndexes = await db.getUniqueIndexes(this.collectionName);
942
+ test_utils_1.assert.isEqualDeep(indexes, [
943
+ {
944
+ fields: ['someField'],
945
+ name: 'someField',
946
+ },
947
+ ], 'index was modified when syncing unique indexes');
948
+ test_utils_1.assert.isEqualDeep(uniqueIndexes, [
949
+ {
950
+ fields: ['uniqueField'],
951
+ name: 'uniqueField',
952
+ },
953
+ ], 'unique indexes are not as expected after syncing unique indexes');
954
+ await this.shutdown(db);
955
+ },
932
956
  async assertCanCreateUniqueIndexOnNestedField(connect) {
933
957
  var _a;
934
958
  const db = await connectToDabatase(connect);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "31.0.7",
6
+ "version": "31.0.9",
7
7
  "files": [
8
8
  "build/**/*",
9
9
  "!build/__tests__",
@@ -66,7 +66,7 @@
66
66
  "@sprucelabs/error": "^8.0.3",
67
67
  "@sprucelabs/globby": "^2.0.510",
68
68
  "@sprucelabs/schema": "^33.0.7",
69
- "@sprucelabs/spruce-skill-utils": "^33.0.7",
69
+ "@sprucelabs/spruce-skill-utils": "^33.0.8",
70
70
  "just-clone": "^6.2.0",
71
71
  "lodash": "^4.17.21",
72
72
  "mongodb": "^7.0.0"
@@ -77,7 +77,7 @@
77
77
  "@sprucelabs/resolve-path-aliases": "^4.0.2",
78
78
  "@sprucelabs/semantic-release": "^6.0.0",
79
79
  "@sprucelabs/test": "^11.0.0",
80
- "@sprucelabs/test-utils": "^7.0.6",
80
+ "@sprucelabs/test-utils": "^7.0.7",
81
81
  "@types/lodash": "^4.17.20",
82
82
  "@types/node": "^24.10.1",
83
83
  "chokidar-cli": "^3.0.0",