rest-api-starter
Version:
Rest API starter kit.
235 lines (215 loc) • 8.4 kB
JavaScript
/**
* Created by svinci on 1/12/17.
*/
/**
* Created by svinci on 8/18/16.
*/
;
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)
};