UNPKG

cramit

Version:

<a href="https://nodei.co/npm/cramit/" target="_blank"><img src="https://nodei.co/npm/cramit.png?downloads=true&downloadRank=true"></a>

588 lines (494 loc) 18.3 kB
module.exports = function(cramit) { /* ************************************************** * * ******************** Global Variables * ************************************************** */ var async = require('async'), path = require('path'), _ = require('lodash'); var DatabaseAdapter = require(path.resolve(__dirname, '.'+path.sep+'index.js')); /* ************************************************** * * ******************** Constructor & Inherit * ************************************************** */ /** * Initalizes a new Mongoose Adapter and configures the * parent Database Adapter class. */ function MongooseAdapter() { this.idAttributeName = cramit.config.database.idAttributeName || '_id'; if( ! cramit.config.database.instance) { //console.log("MongooseAdapter(): Require Mongoose."); this.mongoose = require('mongoose'); } else { //console.log("MongooseAdapter(): Using Mongoose instance."); this.mongoose = cramit.config.database.instance; } DatabaseAdapter.call(this, cramit.config, cramit.log); } // Inherits the DatabaseAdapter parent class's methods and variables. MongooseAdapter.prototype = cramit.inherit(DatabaseAdapter.prototype); /* ************************************************** * * ******************** Transaction Methods * ************************************************** */ MongooseAdapter.prototype.createMongooseTransactionEventMethod = function(transaction, cb) { var adapter = this; return function(err) { if(err) { adapter.log.error(err); } if(cb) { cb(err, transaction || {}); } } } /** * Called before any database action is taken. Allows * the adapter to track actions or pre-perform tasks. * * Notice: This method should be overridden by any * classes that inherit DatabaseAdapter and require * transactions. * * @param {string} type is the type of transaction. * @param {object|array} items is the object or list * of objects to be modified or queried. * @param {object} options is any additional settings * included with the database operation. * @param {transactionCallback} is a callback method. */ MongooseAdapter.prototype.startTransaction = function(type, items, options, cb) { var adapter = this, transaction = {}; if( ! adapter.mongoose) { cb(cramit.error.build('MongooseAdapter.startTransaction(): Database "Mongoose" was never initalized.', 500)); } else if( ! adapter.mongoose.connection) { cb(cramit.error.build('MongooseAdapter.startTransaction(): Mongoose connection was never initalized.', 500)); } else if(adapter.mongoose.connection.readyState !== 1){ //console.log(adapter.mongoose.connection.readyState); //console.log("MongooseAdapter.startTransaction(): Mongoose not connected."); // Make sure the connection URI is specified. if( ! cramit.config.database.connectionUri) { cramit.config.database.connectionUri = 'mongodb://localhost/cramit'; cramit.log.warn('Database not connected and the Mongoose connection URI is not specified, defaulting to %s', cramit.config.database.connectionUri) } // Handle when mongoose connects and/or errors. adapter.mongoose.connection.on('error', adapter.createMongooseTransactionEventMethod(transaction, cb)); adapter.mongoose.connection.once('connected', adapter.createMongooseTransactionEventMethod(transaction, cb)); // Start connecting to the database. adapter.mongoose.connect(cramit.config.database.connectionUri || 'mongodb://localhost/cramit'); } else { cb(undefined, transaction); } }; /* ************************************************** * * ******************** Public Adapter Methods * ************************************************** */ /** * Adds an item to the specified document. * * @param {string} schemaName is the data's schema name * where the information will be stored. * @param {object} item is the data to add to the database. * @param {crudOneItemCallback} cb is a callback method. */ MongooseAdapter.prototype.addItem = function(schemaName, item, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.addItem(): Cannot add item to an undefined schema.')); } // The item should always be an object. if( ! item || ! _.isObject(item)) { item = {}; } var Model = adapter.mongoose.model(schemaName); new Model(item).save(function(err, newItem) { if(err) { cb(err); } else { cramit.log.trace("Added %s with id.", schemaName, newItem[adapter.idAttributeName]); cb(undefined, newItem); } }); }; /** * Adds multiple items to the specified document. * * For the items parameter you can pass a single item * object. * * @param {string} schemaName is the data's schema name * where the information will be stored. * @param {array} items is the list of items to add to * the database. * @param {cudMultipleItemCallback} cb is a callback method. */ MongooseAdapter.prototype.addItems = function(items, schemaName, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.addItems(): Cannot add items to an undefined schema.')); } // Make sure the items parameter is an array. if( ! _.isArray(items)) { items = [items]; } var tasks = []; for(var i = 0; i < items.length; i++) { tasks.push(adapter.createAddItemMethod(schemaName, items[i])); } async.parallel(tasks, cb); }; /** * Find an item by ID in the specified document. * * Specify the ID attribute name using the class's * "idAttributeName" value. * * @param {string} schemaName is the data's schema name * where the information is stored. * @param {string} id is the data's unique identifier. * @param {crudOneItemCallback} cb is a callback method. */ MongooseAdapter.prototype.findItemById = function(schemaName, id, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.findById(): Cannot find an item from an undefined schema.')); } // The ID should always be a valid string. if( ! id || ! _.isString(id)) { return cb(cramit.error.build('MongooseAdapter.findById(): Cannot find an item with an invalid ID.')); } var Schema = adapter.mongoose.model(schemaName), query = {}; query[adapter.idAttributeName] = id; Schema.findOne(query, function (err, data) { if (err) { cb(err); } else if (data === undefined || data === null) { cramit.log.trace("Schema %s with item id %s was not found.", schemaName, id); cb(); } else { cb(undefined, data); } }); } /** * Find an item by ID in a list of items. * * Specify the ID attribute name using the class's * "idAttributeName" value. * * @param {string} schemaName is the data's schema name * where the information is stored. * @param {string} id is the data's unique identifier. * @param {crudOneItemCallback} cb is a callback method. */ MongooseAdapter.prototype.findItemInListById = function(list, id, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.findById(): Cannot find an item from an undefined schema.')); } // The ID should always be a valid string. if( ! id || ! _.isString(id)) { return cb(cramit.error.build('MongooseAdapter.findById(): Cannot find an item with an invalid ID.')); } var Schema = adapter.mongoose.model(schemaName), query = {}; query[adapter.idAttributeName] = id; Schema.findOne(query, function (err, data) { if (err) { cb(err); } else if (data === undefined || data === null) { cramit.log.trace("Schema %s with item id %s was not found.", schemaName, id); cb(); } else { cb(undefined, data); } }); } /** * Find an item by ID and remove it from the specified * document. * * Specify the ID attribute name using the class's * "idAttributeName" value. * * @param {string} schemaName is the data's schema name * where the information is stored. * @param {string} id is the data's unique identifier. * @param {crudOneItemCallback} cb is a callback method. */ MongooseAdapter.prototype.removeItemById = function(schemaName, id, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } adapter.findItemById(schemaName, id, function(err, item){ if(err) { cb(err); } else if( ! item) { cramit.log.trace("Schema %s with item id %s already removed.", schemaName, id); cb(); } else { item.remove(function(err, removedItem) { if(err) { cb(err); } else { cramit.log.trace("Schema %s with item id %s removed.", schemaName, item[adapter.idAttributeName]); cb(undefined, removedItem); } }); } }); }; /** * Find items by ID and remove them from the specified * document. * * Specify the ID attribute name using the class's * "idAttributeName" value. * * @param {string} schemaName is the data's schema name * where the information is stored. * @param {string} ids is a list of the data's unique * identifiers. * @param {cudMultipleItemCallback} cb is a callback method. */ MongooseAdapter.prototype.removeItemsById = function(schemaName, ids, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.removeItemsById(): Cannot remove items from an undefined schema.')); } // Make sure the ids parameter is an array. if( ! _.isArray(ids)) { ids = [ids]; } var tasks = []; for(var i = 0; i < ids.length; i++) { tasks.push(adapter.createRemoveItemByIdMethod(schemaName, ids[i])); } async.parallel(tasks, cb); }; /** * Find an item and remove it from the specified * document. * * @param {string} schemaName is the data's schema name * where the information is stored. * @param {string} item is the item to remove from the * document. * @param {crudOneItemCallback} cb is a callback method. */ MongooseAdapter.prototype.removeItem = function(schemaName, item, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! item || ! _.isObject(item)) { item = {}; } adapter.removeItemById(schemaName, item[adapter.idAttributeName], cb); }; /** * Find items and remove them from the specified document. * * @param {string} schemaName is the data's schema name * where the information is stored. * @param {string} items is a list of items to remove from * the database. * @param {cudMultipleItemCallback} cb is a callback method. */ MongooseAdapter.prototype.removeItems = function(items, schemaName, cb) { if( ! _.isArray(items)) { items = [ items ]; } var ids = []; for(var i = 0; i < items.length; i++) { ids.push(items[i][this.idAttributeName]); } this.removeItemsById(schemaName, ids, cb); }; /** * Upsert an item in the specified document. * * @param {string} schemaName is the data's schema name * where the information will be added or updated. * @param {object} item is the data to upsert in the database. * @param {crudOneItemCallback} cb is a callback method. */ MongooseAdapter.prototype.upsertItem = function(schemaName, item, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.upsertItem(): Cannot upsert item to an undefined schema.')); } // The item should always be an object. if( ! item || ! _.isObject(item)) { item = {}; } var Model = adapter.mongoose.model(schemaName), query = {}; query[adapter.idAttributeName] = item[adapter.idAttributeName]; delete item[adapter.idAttributeName]; Model.findOneAndUpdate(query, item, { 'new': true, 'upsert': true }, function(err, newItem) { if(err) { cb(err); } else { adapter.log.trace("Upsert %s with id.", schemaName, newItem._id); cb(undefined, newItem); } }); }; /** * Upserts multiple items in the specified document. * * For the items parameter you can pass a single item * object. * * @param {string} schemaName is the data's schema name * where the information will be added or updated. * @param {array} items is the list of items to upsert * in the database. * @param {cudMultipleItemCallback} cb is a callback method. */ MongooseAdapter.prototype.upsertItems = function(items, schemaName, cb) { var adapter = this; // Make sure the callback is defined and displays errors if( ! cb) { cb = function(err) { if(err) { cramit.log.error(err); } }; } // The schema needs to be defined. if( ! schemaName) { return cb(cramit.error.build('MongooseAdapter.upsertItems(): Cannot upsert items to an undefined schema.')); } // Make sure the items parameter is an array. if(!_.isArray(items)) { items = [items]; } var tasks = []; for(var i = 0; i < items.length; i++) { tasks.push(adapter.createUpsertItemMethod(schemaName, items[i])); } async.parallel(tasks, cb); }; /* ************************************************** * * ******************** Private Methods * ************************************************** */ /** * Create an asynchronous method to upsert an item into * the specified document. * * Upsert refers to inserting the new data or * updating the existing data. * * @param {string} schemaName is the data's schema name * where the information will be added or updated. * @param {object} item is the data to upsert in the * database. * @return {asyncFunction} the described method. */ MongooseAdapter.prototype.createUpsertItemMethod = function(schemaName, item) { var adapter = this; return function(cb) { adapter.upsertItem(schemaName, item, cb); } }; /** * Create an asynchronous method to add an item into * the specified document. * * @param {string} schemaName is the data's schema name * where the information will be added. * @param {object} item is the data to add in to the * database. * @return {asyncFunction} the described method. */ MongooseAdapter.prototype.createAddItemMethod = function(schemaName, item) { var adapter = this; return function(cb) { adapter.addItem(schemaName, item, cb); } }; /** * Create an asynchronous method to find an item by * ID and remove it from the specified document. * * Specify the ID attribute name using the class's * "idAttributeName" value. * * @param {string} schemaName is the data's schema name * where the information will be removed from. * @param {object} id is the data's unique identifier. * @return {asyncFunction} the described method. */ MongooseAdapter.prototype.createRemoveItemByIdMethod = function(schemaName, id) { var adapter = this; return function(cb) { adapter.removeItemById(schemaName, id, cb); } }; /* ************************************************** * * ******************** Export and Initalize * ************************************************** */ return new MongooseAdapter(); }; /* ************************************************** * * ******************** Documentation Stubs * ************************************************** */ /** * A callback used when fixture data is queried, inserted, * updated, or deleted in the database. The result data * will be the modified object. * * @callback crudOneItemCallback * @param {object|undefined} error describes the error that * occurred. * @param {array|undefined} result is the modified object. */ /** * A callback used when fixture data is inserted, updated, * or deleted in the database. The result data will be an * array of the modified objects. * * @callback cudMultipleItemCallback * @param {object|undefined} error describes the error that occurred. * @param {array|undefined} result is a list of modified objects. */ /** * An asynchronous function that accepts only a callback as the parameter. * All results will be passed to the callback with the first parameter * being an error. * * @callback asyncFunction * @param {function} cb is a callback method. */