UNPKG

ground

Version:

A framework work with sails and backbone.

186 lines (141 loc) 5.69 kB
# Author: Andy Zhao(andy@nodeswork.com) # # A sample for how to use it as sails model. # # class YourModel extends GroundModel # # schema: # name: String # # YourModel.sails() _ = require 'underscore' async = require 'async' mongoose = require 'mongoose' changeCase = require 'change-case' groundDb = require './ground_db' __constants = # The available lifecycle callback function for sails model. LifecycleCallbackFunctionNames: [ 'beforeValidation', 'beforeCreate', 'afterCreate', 'beforeUpdate', 'afterUpdate' 'beforeDestroy', 'afterDestroy' ] ExtendFuncs: removeMongooseDoc: (cb) -> sailsDoc = @__sailsDoc for key in _.keys(sailsDoc) delete sailsDoc[key] delete @__sailsDoc _.extend sailsDoc, @toObject() cb null beforeValidation: (cb) -> @validate cb __constants.ExtendFuncs.beforeCreate = __constants.ExtendFuncs.removeMongooseDoc __constants.ExtendFuncs.beforeUpdate = __constants.ExtendFuncs.removeMongooseDoc __helper = sailsType: (v) -> switch when _.isArray v then 'array' when not _.isFunction(v) and not v.type? then 'json' when v is mongoose.Schema.Types.Mixed then 'json' when _.isFunction(v) and v.name is 'Mixed' then 'json' else {} sailsSchema: (schema) -> _.reduce(schema, ((memo, v, k) -> memo[k] = __helper.sailsType(v); memo), {}) class GroundModel # The database name. @adapter: 'test' # To specify the collection name. By default, it will translate the model class name to a # related collection name. @collection: null # The schema of the model, using mongoose format. See the mongoose document for help. @schema: {} # Sails lifecycle callbacks. As commented below. @callbacks: {} # beforeValidation: (cb) -> # beforeCreate: (cb) -> # afterCreate: (cb) -> # beforeUpdate: (cb) -> # afterUpdate: (cb) -> # beforeDestroy: (cb) -> # afterDestroy: (cb) -> # The statics function of the model. 'this' will be bound to sails model class. @statics: validate: (doc, cb) -> model = new (@ground.mongoose()) doc model.validate cb findByIds: (ids, cb) -> async.series (_.map ids, (id) => (cb) => @findOneById id, cb), cb @methods: {} # The indexes of the model. @indexes: {} # Returns the mongoose model interface. @mongoose: () -> return @__mongooseModel if @__mongooseModel? modelPath = @collection ? @__getModelPathFromModelName() connection = groundDb.mongooseConnection @adapter @__mongooseModel ?= connection.model modelPath, @__mongooseSchema() # Returns the sails model interface. @sails: -> @__sailsModel ?= _.extend { # The adapter which appears inside config/adapters.coffee adapter: @adapter # The attributes of the current model. Since we are using mongoose to do the validation, so # most time, the schema of sails model would be empty, and in schemaless mode. attributes: @__sailsAttributes() schema: no # Same with mongoose table name. tableName: @mongoose().collection.name }, @__sailsLifecycleCallbacks() # Returns the sails attributes. By using mongoose to do the validation, no need to returns the # real attributes. But will involve some instance methods inside the attributes. @__sailsAttributes: -> _.extend {}, @__super__?.constructor?.__sailsAttributes() ? {}, @__methods(), __helper.sailsSchema(@schema) ground: @ # Returns the sails lifecycle callback function for specific callback name. @__sailsLifecycleCallback: (callbackName) -> return [] unless callbackFunc = @callbacks?[callbackName] callbacks = @__super__?.constructor?.__sailsLifecycleCallback(callbackName).slice(0) ? [] if _.indexOf(callbacks, callbackFunc) < 0 then callbacks.push callbackFunc callbacks # Assemble the sails lifecycle callbacks. All the defined function for super classes would also # be called. The order will be from base class to subclasses. @__sailsLifecycleCallbacks: -> callbacks = {} for functionName in __constants.LifecycleCallbackFunctionNames callbackFuncs = @__sailsLifecycleCallback(functionName) if __constants.ExtendFuncs[functionName] callbackFuncs.push __constants.ExtendFuncs[functionName] if callbackFuncs.length is 0 continue do (functionName, callbackFuncs) => callbacks[functionName] = (values, cb) => values.__mongooseDoc ?= new (@mongoose())(values) values.__mongooseDoc.__sailsDoc ?= values async.series (_.bind(func, values.__mongooseDoc) for func in callbackFuncs), (err) -> cb err callbacks # Returns the nested schema. @__schema: -> _.extend {}, @__super__?.constructor?.__schema() ? {}, @schema # Returns the nested methods. @__methods: -> _.extend {}, @__super__?.constructor?.__methods() ? {}, @methods # Returns the nested statics. @__statics: -> _.extend {}, @__super__?.constructor?.__statics() ? {}, @statics # Assemble the NOT cached mongoose schema. @__mongooseSchema: -> mongooseSchema = new mongoose.Schema @__schema(), _id: no _.extend mongooseSchema.methods, @__methods() _.extend mongooseSchema.statics, @__statics() mongooseSchema # Returns the model path from model name. # # e.g. class GroupModel -> groups # class UserGroup -> user_groups @__getModelPathFromModelName: -> modelName = if @name.length > 5 and @name.substring(@name.length - 5) is 'Model' @name.substring(0, @name.length - 5) else @name changeCase.snakeCase modelName module.exports = GroundModel