import { DbQueryWrapper, QueryExecutionError } from './basedb'; import { Collection, FilterQuery, ObjectID } from 'mongodb'; import { wrapIdToMongoDbQuery, wrapIdsToMongoDbQuery, isEmptyArray } from './utils'; import * as _ from 'lodash'; export class MongoDbQueryWrapper implements DbQueryWrapper { async dbInsertOne(collection: Collection, doc: any): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#insertOne // TODO: move to utils if(doc._id !== undefined) { doc._id = new ObjectID(doc._id); } const newDoc = await collection.insertOne(doc); return newDoc.insertedId.toString(); } async dbInsertMany(collection: Collection, docs: any[]): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#insertMany if(docs.length === 0) { return []; } // TODO: move to utils docs.forEach(doc => { if(doc._id !== undefined) { doc._id = new ObjectID(doc._id); } }); const newDocs = await collection.insertMany(docs); return _.map(newDocs.insertedIds, (id: ObjectID) => id.toString()); } async dbUpdateOne(collection: Collection, query: FilterQuery, updateQuery: any): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#updateOne // "_id" is immutable. Mongo throws an exception if updateQuery contains "_id" field. if(updateQuery._id !== undefined) { delete updateQuery._id; } let mongodbUpdateQuery = { $set: updateQuery } query = wrapIdToMongoDbQuery(query); await collection.updateOne( query, mongodbUpdateQuery ); } async dbUpdateMany(collection: Collection, query: string[] | object, updateQuery: any): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#updateMany if(isEmptyArray(query)) { return; } // "_id" is immutable. Mongo throws an exception if updateQuery contains "_id" field. if(updateQuery._id !== undefined) { delete updateQuery._id; } let mongodbUpdateQuery = { $set: updateQuery }; query = wrapIdsToMongoDbQuery(query); await collection.updateMany( query, mongodbUpdateQuery ); } async dbFindOne(collection: Collection, query: FilterQuery): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#findOne query = wrapIdToMongoDbQuery(query); let doc = await collection.findOne(query); // TODO: move to utils if(doc !== null) { doc._id = doc._id.toString(); } return doc; } async dbFindMany(collection: Collection, query: string[] | object, sortQuery: object = {}): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#find if(isEmptyArray(query)) { return []; } query = wrapIdsToMongoDbQuery(query); try { const docs = await collection.find(query).sort(sortQuery).toArray(); docs.forEach(doc => { if (doc !== null) { doc._id = doc._id.toString(); } }); return docs; } catch(error) { console.error(`Can't get query result for query ${JSON.stringify(query)} in collection: ${collection.namespace}`); throw new QueryExecutionError(`MongoDB query error: ${error.message}`); } } async dbRemoveOne(collection: Collection, query: FilterQuery): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteOne query = wrapIdToMongoDbQuery(query); const deleted = await collection.deleteOne(query); if(deleted.deletedCount > 1) { throw new Error(`Removed ${deleted.deletedCount} elements with query: ${JSON.stringify(query)}. Only one is Ok.`); } return deleted.deletedCount === 1; } async dbRemoveMany(collection: Collection, query: string[] | object): Promise { // http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#deleteMany if(isEmptyArray(query)) { return 0; } query = wrapIdsToMongoDbQuery(query); const deleted = await collection.deleteMany(query); return deleted.deletedCount; } }