dce-mango
Version:
Harvard DCE's Non-relational DB Wrapper.
159 lines (137 loc) • 4.51 kB
text/typescript
// Import MongoDB
import MongoDB from 'mongodb';
// Import dbState
import dbState from '../dbState';
// Import types
import CollectionOpts from '../types/CollectionOpts';
/**
* Initialize a collection.
* @author Gabe Abrams
* @param collectionName the name of the collection
* @param options the options tied to the collection
* @returns a Promise which resolves to the Mongo collection
*/
const initCollection = async (
collectionName: string,
options: CollectionOpts,
): Promise<MongoDB.Collection<MongoDB.Document>> => {
// Get the collection names
const collectionNames = await dbState.initDB;
// Variable for the collection
let collection: MongoDB.Collection<MongoDB.Document>;
// Create collection if it doesn't exist
if (collectionNames.indexOf(collectionName) < 0) {
// Collection doesn't exist. Create it
try {
// Create collection
await dbState.db.createCollection(collectionName);
// Get the collection
collection = dbState.db.collection(collectionName);
} catch (err) {
// eslint-disable-next-line no-console
console.log('DCE-MANGO: An error occurred while creating collections. Fatal error. Now exiting.');
// eslint-disable-next-line no-console
console.log(err);
process.exit(1);
}
} else {
// Collection exists. Get it
collection = dbState.db.collection(collectionName);
}
// Get the indexes
const existingIndexes = await collection.indexes();
// If any of the indexes are old, drop them all
const dropAllIndexes = (
existingIndexes
.some((index: { name?: string }) => {
// Ignore invalid indexes
if (!index || !index.name || typeof index.name !== 'string') {
return false;
}
// Ignore ttl index
if (index.name === 'ttl-index') {
return false;
}
// Ignore default index
if (index.name.startsWith('_')) {
return false;
}
// Check if this index is from a previous version
return (!index.name.includes(dbState.schemaVersionTag));
})
);
// Drop all indexes if need be
if (dropAllIndexes) {
try {
// eslint-disable-next-line no-console
console.log(`DCE-MANGO: Found old schema for collection ${collectionName}! Dropping all indexes and re-creating them.`);
await collection.dropIndexes();
} catch (err) {
// eslint-disable-next-line no-console
console.log('DCE-MANGO: An error occurred while dropping old indexes. Fatal error. Now exiting.');
// eslint-disable-next-line no-console
console.log(err);
process.exit(1);
}
}
// Gather a list of indexes that need to be created
const indexesToCreate = [];
// Add unique index to the list
if (options.uniqueIndexKey) {
// Create index options
const indexOpts = {
key: {
[options.uniqueIndexKey]: 1,
},
name: `main-${options.uniqueIndexKey}-unique-index-${dbState.schemaVersionTag}`,
unique: true,
background: false,
} as any;
// Add expiry
if (options.expireAfterSeconds) {
indexOpts.expireAfterSeconds = options.expireAfterSeconds;
}
// Add the index to the list
indexesToCreate.push(indexOpts);
}
// Add TTL for DocDB
if (options.expireAfterSeconds) {
indexesToCreate.push({
key: {
lastUpdatedForTTL: 1,
},
name: `ttl-index-${dbState.schemaVersionTag}`,
expireAfterSeconds: options.expireAfterSeconds,
background: false,
unique: false,
});
}
// Add secondary indexes to the list
(options.indexKeys || []).forEach((secondaryIndexKey: any) => {
indexesToCreate.push({
key: {
[secondaryIndexKey]: 1,
},
name: `secondary-${secondaryIndexKey}-index-${dbState.schemaVersionTag}`,
unique: false,
background: false,
});
});
// Create the indexes
try {
await collection.createIndexes(indexesToCreate);
if ((process.env.MANGO_LOG_LEVEL ?? '').toLowerCase() === 'info') {
// eslint-disable-next-line no-console
console.log('DCE-MANGO: Created indexes. ', indexesToCreate);
}
} catch (err) {
// eslint-disable-next-line no-console
console.log('DCE-MANGO: An error occurred while creating indexes. Fatal error. Now exiting.');
// eslint-disable-next-line no-console
console.log(err);
process.exit(1);
}
// Return the collection
return collection;
};
export default initCollection;