Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 173 additions & 21 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,57 @@ var path = require('path');
var wrench = require('wrench');
var events = require('events');
var mongoose = require('mongoose');
var extend = require('node.extend');

// Patch mongoose-types bug (#17 and #21)
// @link {https://github.com/bnoguchi/mongoose-types/}
var bson = require(__dirname + '/../node_modules/mongoose/node_modules/mongodb/node_modules/bson');
mongoose.mongo.BinaryParser = bson.BinaryParser;

var mongooseTypes = require('mongoose-types');
var mongooseTypes= require('mongoose-types'),
keywordize= require('mongoose-keywordize'),
mongoosastic = require('mongoosastic');

// Expose mongoose and mongoose's types
exports.mongoose = mongoose;
exports.types = mongoose.SchemaTypes;

exports.init = function(conf) {

console.log('mongoose version: %s', mongoose.version);

mongoose.set('debug', conf.debug || false);

var connection = mongoose.createConnection(conf.url);

// Add AMQP stuff to enable models messaging if provided else defaults to console...
var amqpClient= conf.clients.amqp;
if (!amqpClient){
amqpClient= {
sendMessage: function(routing_key, payload){
var encoded_payload = JSON.stringify(payload);
console.log('__NO_AMQP_TRANSPORT_DEFINED__%s!%s', routing_key, payload);
}
};
}

// Add MAIL stuff to enable email notifications...
var mailClient= conf.clients.mail;
if (!mailClient){
mailClient= {
sendMailMessage: function(emailFrom, emailTo, subject, tplName, tplVars, cb){
console.log('__NO_MAIL_TRANSPORT_DEFINED__%s!%s', emailFrom, emailTo);
cb(null,'__NO_MAIL_TRANSPORT_DEFINED__');
}
};
}

// Add mongoose transport to the logging system if needed...
var auditLog= conf.logger;
if (auditLog){
auditLog.addTransport("mongoose", {connectionString: conf.url, collectionName: 'audit.logs'});
}

var virtuals = { };
exports.installVirtuals = function(type, builder) {
virtuals[type._mmId] = builder;
Expand All @@ -37,7 +77,6 @@ exports.init = function(conf) {
});
}


// Find all of the models (This does not load models,
// simply creates a registry with all of the file paths)
var models = { };
Expand Down Expand Up @@ -74,12 +113,44 @@ exports.init = function(conf) {
// Handles circular references
var circles = new events.EventEmitter();

// Load external schema definitions if any...
var schemas = {},
commonSchema = require(path.join(conf.schemaPath, 'common.js'));

wrench.readdirSyncRecursive(conf.schemaPath).forEach(function(file) {

if (file[0] === '.') {return;}
file = file.split('.');
if (file.length > 1 && file.pop() === 'js') {
file = file.join('.');
file = path.join(conf.schemaPath, file);

// schema name for the current model...
var model = path.basename(file);
var schema= require(file);

schemas[model]= {
path: file,
collection: schema.collection || '',
schema: schema.definition || {},
funcs: extend(schema.funcs || {}, commonSchema.funcs),
globals: schema.globals || {},
options: schema.options || {},
columns: schema.columns || {},
};
}
});

// Creates a new model
exports.create = function(name, props) {
props = props || { };

// Retrieve schema definition from file if any....
var schemaDef = schemas[name] || {options: {}},
_virtuals = {};

props = props || { };
extend(props, schemaDef);

var _virtuals = { };

// Check for a scheme definition
if (props.schema) {
// Look for circular references
Expand All @@ -94,11 +165,11 @@ exports.init = function(conf) {
if (typeof def.ref === 'object' && def.ref && def.ref.$circular) {
var model = def.ref.$circular;
// First, check if the model is already loaded
if (models[model] && typeof models[model] === 'object') {
if (models[model] && typeof models[model] === 'object') {
props.schema[key].ref = models[model].schema;
}
// Otherwise, wait and resolve it later
else {
else {
circles.once(model, function(model) {
def.ref = model.schema;
var update = { };
Expand Down Expand Up @@ -134,43 +205,124 @@ exports.init = function(conf) {
.set(funcs.set || function() { });
})
}

Object.keys(props.options).forEach(function(opt){

switch (opt.toLowerCase()) {
case "usetimestamps":
if (String(props.options[opt]) === 'true')
props.schema.plugin(mongooseTypes.useTimestamps);
break;

case "usekeyword":
if (typeof props.options[opt] === 'object')
props.schema.plugin(keywordize, props.options[opt]);
break;

case "useaudit":
if (auditLog && typeof props.options[opt] === 'object'){
var pluginFn = auditLog.getPlugin('mongoose', props.options[opt]); // setup occurs here
props.schema.plugin(pluginFn.handler); // .handler is the pluggable function for mongoose in this case
}
break;

case "useelastic":
if (typeof props.options[opt] === 'object')
props.schema.plugin(mongoosastic, props.options[opt]);
break;
}
});

// Check if we are loading the timestamps plugin
if (props.useTimestamps) {
if (props.hasOwnProperty('useTimestamps') && props.useTimestamps) {
props.schema.plugin(mongooseTypes.useTimestamps);
}

// Check if we are loading the keywordiez plugin
if (props.useKeyword && typeof props.useKeyword === 'object') {
props.schema.plugin(keywordize, props.useKeyword);
}

// Check if we are loading the audit-log plugin
if (auditLog && props.useAudit && typeof props.useAudit === 'object') {

var pluginFn = auditLog.getPlugin('mongoose', props.useAudit); // setup occurs here
props.schema.plugin(pluginFn.handler); // .handler is the pluggable function for mongoose in this case
}

// Check if we are loading the elasticsearch plugin
if (props.useElastic && typeof props.useElastic === 'object') {
props.schema.plugin(mongoosastic, props.useElastic);
}

// Bind any instance methods to the schema.methods object
if (props.methods) {
Object.keys(props.methods).forEach(function(i) {
props.schema.methods[i] = props.methods[i];
});
}

mongoose.Model.paginate = function(q, skipFrom, resultsPerPage, sortCols, selCols, callback){
var MyModel = this,
query,
pageCount= 0,
callback = callback || function(){};

if (skipFrom>0) {
query = MyModel.find(q).skip(skipFrom).limit(resultsPerPage).sort(sortCols).select(selCols);
}
else {
query = MyModel.find(q).limit(resultsPerPage).sort(sortCols).select(selCols);
}

query.exec(function(error, results) {
if (error) {
callback(error, null, null);
} else {
MyModel.count(q, function(error, count) {
if (error) {
callback(error, null, null);
} else {
pageCount = Math.floor(count / resultsPerPage);
callback(null, count, results);
}
});
}
});
}

// Create the mongoose model
var model = connection.model(name, props.schema);
var model = connection.model(name, props.schema, props.collection);
var excludeProps= ['schema', 'collection', 'useTimestamps', 'useKeyword', 'useAudit', 'useElastic', 'methods', 'statics', 'options', 'columns', 'funcs'];

// Copy over all other properties as static model properties
Object.keys(props).forEach(function(i) {
if (i !== 'schema' && i !== 'useTimestamps' && i !== 'methods') {
model[i] = props[i];
// Copy over all other properties as static model properties
Object.keys(props).forEach(function(key) {
if (excludeProps.indexOf(key)<0) {
model[key] = props[key];
}
});


if (props.statics){
Object.keys(props.statics).forEach(function(key) {
model[key] = props.statics[key];
});
}

// Store the model
models[name].model = model;

// The model is done being built, allow circular reference to resolve
circles.emit(name, model);

circles.emit(name, model);
return model;
};

// Expose schemas repo in outside world...
exports.schemaRepository = schemas;

// Expose mongoose and mongoose's types
exports.mongoose = mongoose;
exports.types = mongoose.SchemaTypes;
//Expose specific clients in models world...
exports.amqpClient = amqpClient;
exports.mailClient = mailClient;

// Don't allow re-init
exports.init = undefined;
};

};
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
},
"repository": {
"type": "git",
"url": "git://github.com/SportZing/mongoose-models"
"url": "git://github.com/marco48/mongoose-models"
},
"keywords": [
"mongoose",
"mongo",
"db",
"model"
],
"author": "James Brumond",
"author": "marco",
"license": "MIT",
"dependencies": {
"mongoose": "~3.0.0",
"mongoose": "3.8.4",
"wrench": "~1.3.9",
"mongoose-types": "~1.0.3",
"mongoose-types": "marco48/mongoose-types",
"uuid-v4": "~0.1.0",
"colors": "0.6.0-1"
}
}
}