UNPKG

angoose

Version:

Angoose is a Remote Method Invocation module that comes with built-in mongoose/angular support. Now you can call server side module in browser just like you're in the server side!

167 lines (145 loc) 5.63 kB
// This is the base class for Angoose model classes and service classes. // This is used internally and it's here only for listing the APIs common // to all Model and Service classes. var logger = require("log4js").getLogger("angoose"); var _ = require("underscore"); var Class = require("./util/classy"); var toolbox = require("./util/toolbox"); // ### API Rereferences // **getContext()** // // This method allows you obtain the execution context. // See [Context](Context.html) for more. // // Note this method is also available on the class(function) as well. i.e., // // /** MyModel is subclass of Remotable */ // var instance = new MyModel(); // /** Following yields true */ // MyModel.getContext() === instance.getContext(); // var getContext = function(){ return require("./angoose").getContext() } var Remotable = Class.$extend({}); Remotable.prototype = { getContext: getContext } Remotable._angoosemeta ={ baseClass: 'Remotable' } Remotable.extend = extend; Remotable.getContext = getContext; // ** extend ** // // This static method is used to create Angoose model or service classes. // All classes created using this method is a subclass of `Remotable` function extend(target, options){ options = options||{}; var parentClass = this; logger.trace("Extending from ", parentClass._angoosemeta.name, options); var rv = null; if(typeof (target) == 'function'){ rv = target; mixinInstance(parentClass, rv, options); /**@todo: temp hack */ bindMongooseMethods(rv); } else{ /** schema object */ rv = parentClass.$extend( target ); } /** mixin Angoose class level functions */ rv = mixinStatic(parentClass, rv, options); if(rv._angoosemeta.name){ /** register it with Angoose */ //require("./angoose").registerClass(rv._angoosemeta.name, rv); } return rv; } function mixinInstance(parentClass, subClass, options){ subClass.prototype.getContext = getContext; /** look for static classes*/ } function mixinStatic(parentClass, subClass, options){ /** mixin Angoose functions to the new class */ /** if(subClass.extend || subClass.getContext ) throw "Class already has 'extend' or 'getContext' property/method" */ /** mixing static properties from parentClass to subClass */ for(var prop in parentClass){ var val = parentClass[prop]; if(!parentClass.hasOwnProperty(prop) || typeof(val) != 'function') continue; if(isRemotableReserved(prop)) continue; if(subClass[prop]) { logger.warn("Cannot mixin subclass: property '"+ prop+"' already exists on subclass"); throw "Subclass already has property '"+ prop+"' defined."; } //logger.trace("Mixing: ", prop) subClass[prop] = val; } // subClass.extend = extend; // subClass.getContext = getContext; subClass._angoosemeta = _.extend({}, parentClass._angoosemeta); subClass._angoosemeta = _.extend(subClass._angoosemeta, options) return subClass; } function isRemotableReserved(methodName){ /** check if method is reserved by the Remotable interface */ return methodName.indexOf("_") == 0 || methodName.indexOf("$") == 0 || ['constructor', 'isRemotableReserved'].indexOf(methodName)>=0; } /** a$ is Angoose's internal property*/ //Remotable.prototype._angoosemeta = {}; Remotable.getContext = getContext; Remotable.isRemotableReserved=isRemotableReserved; module.exports = Remotable Remotable.mixin = function(opts, target){ opts = opts || {}; target.getSchema = getSchema; target._angoosemeta = toolbox.merge(target._angoosemeta , opts); target._angoosemeta.baseClass = target._angoosemeta.baseClass || 'Service'; target.getContext = getContext; //deprecated target.config = config; if(target._angoosemeta.baseClass == 'Model') bindMongooseMethods(target); } function config(path, opts){ var conf = this._angoosemeta; switch(arguments.length){ case 0: return conf; case 1: return toolbox.getter(conf, path); case 2: toolbox.setter(conf, path, opts); } return this; } function getSchema(){ var thisClass = this; var schema = {statics: {}, methods:{} }; for(var name in thisClass){ var val = thisClass[name]; if( filter(name) ) continue; if(typeof (val) != 'function') continue; schema.statics[name] = val; } if(typeof(thisClass) == 'function'){ schema.methods = _.extend({}, thisClass.prototype) } return schema; } function filter(methodName){ if(Remotable.isRemotableReserved(methodName)) return true; if(['extend', 'getContext', 'getSchema','mixin','toJSON' ].indexOf(methodName)>=0) return true; return false; } function bindMongooseMethods(modelClass){ var staticMethods = "populate,find,findOne,findById,findByIdAndRemove,findByIdAndUpdate,findOneAndRemove,findOneAndUpdate,update,remove,count,geoNear,geoSearch,aggregate".split(","); _.each(staticMethods, function(method){ var fn = modelClass[method]; if( typeof(fn) == 'function'){ modelClass[method] = toolbox.bindCallback(modelClass, fn ) } }); var instanceMethods = "save,remove,populate,update".split(","); _.each(instanceMethods, function(method){ var fn = modelClass.prototype[method]; if( typeof(fn) == 'function'){ modelClass.prototype[method] = toolbox.bindCallback(null, fn ) } }); }