UNPKG

rest-api-starter

Version:
235 lines (215 loc) 8.4 kB
/** * Created by svinci on 1/12/17. */ /** * Created by svinci on 8/18/16. */ 'use strict'; const Promise = require('bluebird'); const configuration = require('config'); const MongoClient = require('mongodb').MongoClient; const ObjectId = require('mongodb').ObjectId; const logger = require('./logger')('db'); /** * Retrieve configured database. */ const database = () => new Promise((resolve, reject) => MongoClient.connect(configuration.get('app.mongo.url'), (err, db) => { if (err) { logger.error(`Error retrieving database: ${err}.`); reject(err); } else { resolve({'db': db}); } })); /** * Retrieve a collection by name. * @param name collection name. */ const collection = (name) => database().then((result) => ({ 'db': result.db, 'collection': result.db.collection(name) })); /** * Check dabase connection's health. */ const healthCheck = () => database() .then((result) => { if (result.db) { result.db.close(); } return { 'healthy': true }; }) .catch((err) => ({ 'healthy': false, 'error': err })); /** * Execute the given query. The promise will resolve with an array containing the results, or reject with the exception. * @param query Mongo query object. * @param collectionName Collection where the query has to be executed. * @param sortOptions Options to sort the resulting array. */ const find = (query, collectionName, sortOptions) => { const startDate = new Date(); return collection(collectionName).then( (result) => new Promise( (resolve, reject) => result.collection.find(query, {'sort': sortOptions}).toArray((err, documents) => { if (err) { logger.error(`Search with query ${JSON.stringify(query)} in collection ${collectionName} failed with error: ${err}.`); reject(err); } else { logger.debug(`Search with query ${JSON.stringify(query)} in collection ${collectionName} returned ${documents.length} documents.`); resolve(documents); } }) ).finally(() => { logger.info(`Query to collection ${collectionName} with query ${JSON.stringify(query)} took ${new Date() - startDate}ms.`); if (result.db) { result.db.close(); } }) ); }; /** * Execute the given query. The promise will resolve with the first document of the resulting array, or reject with the exception. If there is no result, will raise a document.not.found error. * @param query Mongo query object. * @param collectionName Collection where the query has to be executed. */ const findUnique = (query, collectionName) => find(query, collectionName) .then((documents) => { if (!documents || documents.length === 0) { return null; } return documents[0]; }) .then((document) => new Promise((resolve, reject) => { if (document) { logger.debug(`Search in collection ${collectionName} for unique document returned successfully.`); resolve(document); } else { logger.warn(`Search in collection ${collectionName} for unique document returned nothing.`); reject({ 'name': 'document.not.found', 'message': 'Query for unique document returned empty.', 'detail': { 'collection': collectionName, 'query': query } }); } })); /** * Retrieve all documents in the given collection. The promise will resolve with an array containing the results, or reject with the exception. * @param collectionName Collection where the query has to be executed. * @param sortOptions Options to sort the resulting array. */ const all = (collectionName, sortOptions) => find({}, collectionName, sortOptions); /** * Find a document by its _id field. The promise will resolve with the found document, or reject with the exception. If there is no result, will raise a document.not.found error. * @param id Identifier (_id) of the document you want to retrieve. * @param collectionName Collection where the query has to be executed. */ const findById = (id, collectionName) => findUnique({'_id': id}, collectionName); /** * Insert the given document in the provided collection. If the document doesn't have a _id field, a random ObjectId will be generated. The promise will resolve with the inserted document, or reject with an exception. * @param document Document to insert. * @param collectionName Target collection. */ const insert = (document, collectionName) => { const startDate = new Date(); if (!document._id) { document._id = new ObjectId(); } return collection(collectionName).then( (result) => new Promise( (resolve, reject) => result.collection.insertMany([document], (err) => { if (err) { logger.error(`Insertion in collection ${collectionName} with id ${document._id} failed with error: ${err}.`); reject(err); } else { logger.debug(`Insertion in collection ${collectionName} with id ${document._id} returned successfully.`); resolve(document); } }) ).finally(() => { logger.info(`Insert to collection ${collectionName} took ${new Date() - startDate}ms.`); if (result.db) { result.db.close(); } }) ); }; /** * Update a document by its id. The promise will resolve with the updated document, or reject with an exception. * @param id Id of the document to insert. * @param document Update object. * @param collectionName Name of the target collection. */ const update = (id, document, collectionName) => { const startDate = new Date(); const query = { '_id': id }; return collection(collectionName).then( (result) => new Promise( (resolve, reject) => result.collection.updateOne(query, {'$set': document}, (err) => { if (err) { logger.error(`Update in collection ${collectionName} with id ${id} failed with error: ${err}.`); reject(err); } else { logger.debug(`Update in collection ${collectionName} with id ${id} returned successfully.`); document._id = id; resolve(document); // TODO the provided document might be an update object, I must retrieve the document. } }) ).finally(() => { logger.info(`Update of document with id ${id} to collection ${collectionName} took ${new Date() - startDate}ms.`); if (result.db) { result.db.close(); } }) ); }; /** * Delete a document by its id. The promise will resolve empty, or reject with an exception. * @param id Id of the document to remove. * @param collectionName Name of the target collection. */ const del = (id, collectionName) => { const startDate = new Date(); const query = { '_id': id }; return collection(collectionName).then( (result) => new Promise( (resolve, reject) => result.collection.deleteOne(query, (err) => { if (err) { logger.error(`Delete in collection ${collectionName} with id ${id} failed with error: ${err}.`); reject(err); } else { logger.debug(`Delete in collection ${collectionName} with id ${id} returned successfully.`); resolve(); } }) ).finally(() => { logger.info(`Removal of document with id ${id} to collection ${collectionName} took ${new Date() - startDate}ms.`); if (result.db) { result.db.close(); } }) ); }; module.exports = { 'healthCheck': healthCheck, 'all': all, 'find': find, 'findUnique': findUnique, 'findById': findById, 'del': del, 'insert': insert, 'update': update, 'newId': () => new ObjectId(), 'toObjectId': (stringId) => new ObjectId(stringId) };