handle index mismatches properly
This commit is contained in:
parent
93d205eb37
commit
e4e6fdf843
@ -1,5 +1,5 @@
|
||||
import { inspect } from 'node:util';
|
||||
import { MongoClient, MongoClientOptions, Db, Document, WithId, ObjectId, Filter, IndexSpecification, CreateIndexesOptions, FindOptions, MongoServerError } from 'mongodb';
|
||||
import { MongoClient, MongoClientOptions, Db, Document, WithId, ObjectId, Filter, IndexSpecification, CreateIndexesOptions, FindOptions } from 'mongodb';
|
||||
import { IServer, ILogger, LoggerClientOptions } from './interfaces/index.js';
|
||||
|
||||
type Credentials = {
|
||||
@ -24,6 +24,20 @@ export type MongoOptions = {
|
||||
load?: boolean
|
||||
}
|
||||
|
||||
type StringIndexable = {[key: string]: boolean | string | number | Document | object}
|
||||
|
||||
const objIsSubset = (superObj: StringIndexable, subObj: StringIndexable): boolean =>
|
||||
{
|
||||
return Object.keys(subObj).every(ele =>
|
||||
{
|
||||
if (typeof subObj[ele] === 'object' && typeof superObj[ele] === 'object')
|
||||
{
|
||||
return objIsSubset(superObj[ele] as StringIndexable, subObj[ele] as StringIndexable);
|
||||
}
|
||||
return subObj[ele] === superObj[ele];
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* A dedicated class to locally wrap the mongodb API wrapper
|
||||
*
|
||||
@ -363,36 +377,25 @@ class MongoDB
|
||||
return this.#db.collection(coll).countDocuments(query);
|
||||
}
|
||||
|
||||
async ensureIndex (collection: string, index: IndexSpecification, options?: CreateIndexesOptions): Promise<void>
|
||||
async ensureIndex (collection: string, index: IndexSpecification, options?: CreateIndexesOptions & StringIndexable): Promise<void>
|
||||
{
|
||||
if (!this.#db)
|
||||
return Promise.reject(new Error('MongoDB not connected'));
|
||||
if (!(index instanceof Array))
|
||||
index = [ index ];
|
||||
try
|
||||
{
|
||||
await this.#db.collection(collection).createIndex(index, options);
|
||||
}
|
||||
catch (err)
|
||||
{
|
||||
// If the index exists, recreate it with the new spec
|
||||
const error = err as MongoServerError;
|
||||
// Mongo changes the given name of the index to reflect the direciton, so find it by matching the start of the name
|
||||
|
||||
const indexes = await this.#db.collection(collection).indexes();
|
||||
const existing = indexes.find(idx => idx.name.startsWith(index));
|
||||
if (error.codeName === 'IndexKeySpecsConflict' && existing)
|
||||
{
|
||||
if (existing && this.#indexesEqual(existing, options))
|
||||
return;
|
||||
|
||||
if (existing)
|
||||
await this.#db.collection(collection).dropIndex(existing.name);
|
||||
|
||||
await this.#db.collection(collection).createIndex(index, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async ensureIndices (collection: string, indices: IndexSpecification[], options?: CreateIndexesOptions): Promise<void>
|
||||
async ensureIndices (collection: string, indices: IndexSpecification[], options?: CreateIndexesOptions & StringIndexable): Promise<void>
|
||||
{
|
||||
if (!this.#db)
|
||||
return Promise.reject(new Error('MongoDB not connected'));
|
||||
@ -400,6 +403,30 @@ class MongoDB
|
||||
await this.ensureIndex(collection, index, options);
|
||||
}
|
||||
|
||||
#indexesEqual (existing: Document, options?: CreateIndexesOptions & StringIndexable)
|
||||
{
|
||||
// 3 keys on the existing means that only the name was given
|
||||
if (!options && Object.keys(existing).length === 3)
|
||||
return true;
|
||||
else if (!options)
|
||||
return false;
|
||||
|
||||
const keys = Object.keys(options);
|
||||
for (const key of keys)
|
||||
{
|
||||
if (typeof options[key] !== typeof existing[key])
|
||||
return false;
|
||||
|
||||
if (typeof options[key] === 'object' && !objIsSubset(existing, options))
|
||||
return false;
|
||||
else if (options[key] !== existing[key])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { MongoDB };
|
Loading…
Reference in New Issue
Block a user