Sequelize

declaration

Utils

Utils
    var Utils     = require("./utils")
      , DAO       = require("./dao")
      , DataTypes = require("./data-types")
    
    module.exports = (function() {
      var DAOFactory = function(name, attributes, options) {
        var self = this
    
        this.options = Utils._.extend({
          timestamps: true,
          instanceMethods: {},
          classMethods: {},
          validate: {},
          freezeTableName: false,
          underscored: false,
          syncOnAssociation: true,
          paranoid: false
        }, options || {})
    
        this.name = name
        this.tableName = this.options.freezeTableName ? name : Utils.pluralize(name)
        this.rawAttributes = attributes
        this.daoFactoryManager = null // defined in init function
        this.associations = {}
    
        // extract validation
        this.validate = this.options.validate || {}
      }
    
      Object.defineProperty(DAOFactory.prototype, 'attributes', {
        get: function() {
          return this.QueryGenerator.attributesToSQL(this.rawAttributes)
        }
      })
    
      Object.defineProperty(DAOFactory.prototype, 'QueryInterface', {
        get: function() { return this.daoFactoryManager.sequelize.getQueryInterface() }
      })
    
      Object.defineProperty(DAOFactory.prototype, 'QueryGenerator', {
        get: function() { return this.QueryInterface.QueryGenerator }
      })
    
      Object.defineProperty(DAOFactory.prototype, 'primaryKeyCount', {
        get: function() { return Utils._.keys(this.primaryKeys).length }
      })
    
      Object.defineProperty(DAOFactory.prototype, 'hasPrimaryKeys', {
        get: function() { return this.primaryKeyCount > 0 }
      })
    
      DAOFactory.prototype.init = function(daoFactoryManager) {
        this.daoFactoryManager = daoFactoryManager
    
        addDefaultAttributes.call(this)
        addOptionalClassMethods.call(this)
        findAutoIncrementField.call(this)
    
        return this
      }
    
      DAOFactory.prototype.sync = function(options) {
        options = Utils.merge(options || {}, this.options)
    
        var self = this
        return new Utils.CustomEventEmitter(function(emitter) {
          var doQuery = function() {
            self.QueryInterface
              .createTable(self.tableName, self.attributes, options)
              .success(function() { emitter.emit('success', self) })
              .error(function(err) { emitter.emit('error', err) })
              .on('sql', function(sql) { emitter.emit('sql', sql) })
          }
    
          if(options.force)
            self.drop().success(doQuery).error(function(err) { emitter.emit('error', err) })
          else
            doQuery()
    
        }).run()
      }
    
      DAOFactory.prototype.drop = function() {
        return this.QueryInterface.dropTable(this.tableName)
      }
    
      // alias for findAll
      DAOFactory.prototype.all = function(options) {
        return this.findAll(options)
      }
    
      DAOFactory.prototype.findAll = function(options) {
        return this.QueryInterface.select(this, this.tableName, options)
      }
    
      //right now, the caller (has-many-double-linked) is in charge of the where clause
      DAOFactory.prototype.findAllJoin = function(joinTableName, options) {
        var optcpy = Utils._.clone(options)
        optcpy.attributes = optcpy.attributes || [Utils.addTicks(this.tableName)+".*"]
    
        return this.QueryInterface.select(this, [this.tableName, joinTableName], optcpy)
      }
    
      DAOFactory.prototype.find = function(options) {
        // no options defined?
        // return an emitter which emits null
        if([null, undefined].indexOf(options) > -1) {
          return new Utils.CustomEventEmitter(function(emitter) {
            setTimeout(function() { emitter.emit('success', null) }, 10)
          }).run()
        }
    
        // options is not a hash but an id
        if(typeof options === 'number') {
          options = { where: options }
        } else if (Utils.argsArePrimaryKeys(arguments, this.primaryKeys)) {
            var where = {}
              , self  = this
    
            Utils._.each(arguments, function(arg, i) {
              var key = Utils._.keys(self.primaryKeys)[i]
              where[key] = arg
            })
    
            options = { where: where }
        } else if((typeof options === 'object') && (options.hasOwnProperty('include'))) {
          var includes = options.include
    
          options.include = {}
    
          includes.forEach(function(daoName) {
            options.include[daoName] = this.daoFactoryManager.getDAO(daoName)
          }.bind(this))
        }
    
        options.limit = 1
    
        return this.QueryInterface.select(this, this.tableName, options, { plain: true })
      }
    
      DAOFactory.prototype.count = function(options) {
        options = Utils._.extend({ attributes: [] }, options || {})
        options.attributes.push(['count(*)', 'count'])
        options.parseInt = true
    
        return this.QueryInterface.rawSelect(this.tableName, options, 'count')
      }
    
      DAOFactory.prototype.max = function(field, options) {
        options = Utils._.extend({ attributes: [] }, options || {})
        options.attributes.push(['max(' + field + ')', 'max'])
        options.parseInt = true
    
        return this.QueryInterface.rawSelect(this.tableName, options, 'max')
      }
      DAOFactory.prototype.min = function(field, options) {
        options = Utils._.extend({ attributes: [] }, options || {})
        options.attributes.push(['min(' + field + ')', 'min'])
        options.parseInt = true
    
        return this.QueryInterface.rawSelect(this.tableName, options, 'min')
      }
    
      DAOFactory.prototype.build = function(values, options) {
        var instance = new DAO(values, Utils._.extend(this.options, this.attributes, { hasPrimaryKeys: this.hasPrimaryKeys }))
          , self     = this
    
        options = options || {}
        instance.__factory = this
    
        Utils._.each(this.attributes, function(definition, name) {
          //transform integer 0,1 into boolean
          if((definition.indexOf(DataTypes.BOOLEAN) !== -1) && (typeof instance[name] === "number")) {
            instance[name] = (instance[name] !== 0)
          }
    
          //add default attributes
          if(typeof instance[name] === 'undefined') {
            var value = null
    
            if(self.rawAttributes.hasOwnProperty(name) && self.rawAttributes[name].hasOwnProperty('defaultValue')) {
              value = Utils.toDefaultValue(self.rawAttributes[name].defaultValue)
            }
    
            instance[name] = value
            instance.addAttribute(name, value)
          }
    
          // add validation
          if (self.rawAttributes.hasOwnProperty(name) && self.rawAttributes[name].hasOwnProperty('validate')) {
            instance.setValidators(name, self.rawAttributes[name].validate)
          }
        })
    
        Utils._.each(this.options.instanceMethods || {}, function(fct, name) { instance[name] = fct })
        Utils._.each(this.associations, function(association, associationName) {
          association.injectGetter(instance)
          association.injectSetter(instance)
        })
    
        instance.isNewRecord = options.hasOwnProperty('isNewRecord') ? options.isNewRecord : true
    
        return instance
      }
    
      DAOFactory.prototype.create = function(values, fields) {
        return this.build(values).save(fields)
      }
    
      DAOFactory.prototype.__defineGetter__('primaryKeys', function() {
        var result = {}
        Utils._.each(this.attributes, function(dataTypeString, attributeName) {
          if((attributeName != 'id') && (dataTypeString.indexOf('PRIMARY KEY') > -1))
            result[attributeName] = dataTypeString
        })
    
        return result
      })
    
      // private
    
      var query = function() {
        var args = Utils._.map(arguments, function(arg, _) { return arg })
          , s    = this.daoFactoryManager.sequelize
    
        // add this as the second argument
        if(arguments.length == 1) args.push(this)
        return s.query.apply(s, args)
      }
    
      var addOptionalClassMethods = function() {
        var self = this
        Utils._.each(this.options.classMethods || {}, function(fct, name) { self[name] = fct })
      }
    
      var addDefaultAttributes = function() {
        var self              = this
          , defaultAttributes = {
            id: {
              type: DataTypes.INTEGER,
              allowNull: false,
              primaryKey: true,
              autoIncrement: true
            }
          }
    
        if(this.hasPrimaryKeys) defaultAttributes = {}
    
        if(this.options.timestamps) {
          defaultAttributes[Utils._.underscoredIf('createdAt', this.options.underscored)] = {type: DataTypes.DATE, allowNull: false}
          defaultAttributes[Utils._.underscoredIf('updatedAt', this.options.underscored)] = {type: DataTypes.DATE, allowNull: false}
    
          if(this.options.paranoid)
            defaultAttributes[Utils._.underscoredIf('deletedAt', this.options.underscored)] = {type: DataTypes.DATE}
        }
    
        Utils._.each(defaultAttributes, function(value, attr) {
          self.rawAttributes[attr] = value
        })
      }
    
      var findAutoIncrementField = function() {
        var self   = this
          , fields = this.QueryGenerator.findAutoIncrementField(this)
    
        this.autoIncrementField = null
    
        fields.forEach(function(field) {
          if(self.autoIncrementField)
            throw new Error('Invalid DAO definition. Only one autoincrement field allowed.')
          else
            self.autoIncrementField = field
        })
      }
    
      Utils._.extend(DAOFactory.prototype, require("./associations/mixin"))
    
      return DAOFactory
    })()