<commit_before>var Utils     = require("./utils")
  , Mixin     = require("./associations/mixin")
  , Validator = require("validator")
  , DataTypes = require("./data-types")

module.exports = (function() {
  var DAO = function(values, options, isNewRecord) {
    var self = this

    this.__options                   = options
    this.hasPrimaryKeys              = options.hasPrimaryKeys
    this.selectedValues              = values
    this.__eagerlyLoadedAssociations = []

    initAttributes.call(this, values, isNewRecord)

    if (this.hasDefaultValues) {
      Utils._.each(this.defaultValues, function (value, name) {
        if (typeof self[name] === 'undefined') {
          self.addAttribute(name, value());
        }
      })
    }

    if (this.booleanValues.length) {
      this.booleanValues.forEach(function (name) {
        //transform integer 0,1 into boolean
        self[name] = !!self[name];
      });
    }
  }
  Utils._.extend(DAO.prototype, Mixin.prototype)

  Object.defineProperty(DAO.prototype, 'sequelize', {
    get: function(){ return this.__factory.daoFactoryManager.sequelize }
  })

  Object.defineProperty(DAO.prototype, 'QueryInterface', {
    get: function(){ return this.sequelize.getQueryInterface() }
  })

  Object.defineProperty(DAO.prototype, 'isDeleted', {
    get: function() {
      var result = this.__options.timestamps && this.__options.paranoid
      result = result && this[this.__options.underscored ? 'deleted_at' : 'deletedAt'] !== null

      return result
    }
  })

  Object.defineProperty(DAO.prototype, 'values', {
    get: function() {
      var result = {}
        , self   = this

      this.attributes.concat(this.__eagerlyLoadedAssociations).forEach(function(attr) {
        result[attr] = self[attr]
      })

      return result
    }
  })

  Object.defineProperty(DAO.prototype, 'primaryKeyValues', {
    get: function() {
      var result = {}
        , self   = this

      Utils._.each(this.__factory.primaryKeys, function(_, attr) {
        result[attr] = self[attr]
      })

      return result
    }
  })

  Object.defineProperty(DAO.prototype, "identifiers", {
    get: function() {
      var primaryKeys = Object.keys(this.__factory.primaryKeys)
        , result      = {}
        , self        = this

      if (!this.__factory.hasPrimaryKeys) {
        primaryKeys = ['id']
      }

      primaryKeys.forEach(function(identifier) {
        result[identifier] = self[identifier]
      })

      return result
    }
  })

  // if an array with field names is passed to save()
  // only those fields will be updated
  DAO.prototype.save = function(fields) {
    var self          = this
      , values        = fields ? {} : this.values
      , updatedAtAttr = this.__options.underscored ? 'updated_at' : 'updatedAt'
      , createdAtAttr = this.__options.underscored ? 'created_at' : 'createdAt'

    if (fields) {
      if (self.__options.timestamps) {
        if (fields.indexOf(updatedAtAttr) === -1) {
          fields.push(updatedAtAttr)
        }

        if (fields.indexOf(createdAtAttr) === -1) {
          fields.push(createdAtAttr)
        }
      }

      fields.forEach(function(field) {
        if (self.values[field] !== undefined) {
          values[field] = self.values[field]
        }
      })
    }

    for (var attrName in this.daoFactory.rawAttributes) {
      if (this.daoFactory.rawAttributes.hasOwnProperty(attrName)) {
        var definition      = this.daoFactory.rawAttributes[attrName]
          , isEnum          = (definition.type && (definition.type.toString() === DataTypes.ENUM.toString()))
          , hasValue        = (typeof values[attrName] !== 'undefined')
          , valueOutOfScope = ((definition.values || []).indexOf(values[attrName]) === -1)

        if (isEnum && hasValue && valueOutOfScope) {
          throw new Error('Value "' + values[attrName] + '" for ENUM ' + attrName + ' is out of allowed scope. Allowed values: ' + definition.values.join(', '))
        }
      }
    }

    if (this.__options.timestamps && this.hasOwnProperty(updatedAtAttr)) {
      this[updatedAtAttr] = values[updatedAtAttr] = Utils.now()
    }

    if (this.isNewRecord) {
      return this.QueryInterface.insert(this, this.__factory.tableName, values)
    } else {
      var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : this.id;

      if (identifier === null && this.__options.whereCollection !== null) {
        identifier = this.__options.whereCollection;
      }

      var tableName  = this.__factory.tableName
        , query      = this.QueryInterface.update(this, tableName, values, identifier)

      return query
    }
  }

 /*
  * Refresh the current instance in-place, i.e. update the object with current data from the DB and return the same object.
  * This is different from doing a `find(DAO.id)`, because that would create and return a new object. With this method,
  * all references to the DAO are updated with the new data and no new objects are created.
  *
  * @return {Object}         A promise which fires `success`, `error`, `complete` and `sql`.
  */
  DAO.prototype.reload = function() {
    return this.QueryInterface.reload(this, this.__factory.tableName);
  }

  /*
   * Validate this dao's attribute values according to validation rules set in the dao definition.
   *
   * @return null if and only if validation successful; otherwise an object containing { field name : [error msgs] } entries.
   */<commit_msg>use Model.find to reload a model instance<commit_after>var Utils     = require("./utils")
  , Mixin     = require("./associations/mixin")
  , Validator = require("validator")
  , DataTypes = require("./data-types")

module.exports = (function() {
  var DAO = function(values, options, isNewRecord) {
    var self = this

    this.__options                   = options
    this.hasPrimaryKeys              = options.hasPrimaryKeys
    this.selectedValues              = values
    this.__eagerlyLoadedAssociations = []

    initAttributes.call(this, values, isNewRecord)

    if (this.hasDefaultValues) {
      Utils._.each(this.defaultValues, function (value, name) {
        if (typeof self[name] === 'undefined') {
          self.addAttribute(name, value());
        }
      })
    }

    if (this.booleanValues.length) {
      this.booleanValues.forEach(function (name) {
        //transform integer 0,1 into boolean
        self[name] = !!self[name];
      });
    }
  }
  Utils._.extend(DAO.prototype, Mixin.prototype)

  Object.defineProperty(DAO.prototype, 'sequelize', {
    get: function(){ return this.__factory.daoFactoryManager.sequelize }
  })

  Object.defineProperty(DAO.prototype, 'QueryInterface', {
    get: function(){ return this.sequelize.getQueryInterface() }
  })

  Object.defineProperty(DAO.prototype, 'isDeleted', {
    get: function() {
      var result = this.__options.timestamps && this.__options.paranoid
      result = result && this[this.__options.underscored ? 'deleted_at' : 'deletedAt'] !== null

      return result
    }
  })

  Object.defineProperty(DAO.prototype, 'values', {
    get: function() {
      var result = {}
        , self   = this

      this.attributes.concat(this.__eagerlyLoadedAssociations).forEach(function(attr) {
        result[attr] = self[attr]
      })

      return result
    }
  })

  Object.defineProperty(DAO.prototype, 'primaryKeyValues', {
    get: function() {
      var result = {}
        , self   = this

      Utils._.each(this.__factory.primaryKeys, function(_, attr) {
        result[attr] = self[attr]
      })

      return result
    }
  })

  Object.defineProperty(DAO.prototype, "identifiers", {
    get: function() {
      var primaryKeys = Object.keys(this.__factory.primaryKeys)
        , result      = {}
        , self        = this

      if (!this.__factory.hasPrimaryKeys) {
        primaryKeys = ['id']
      }

      primaryKeys.forEach(function(identifier) {
        result[identifier] = self[identifier]
      })

      return result
    }
  })

  // if an array with field names is passed to save()
  // only those fields will be updated
  DAO.prototype.save = function(fields) {
    var self          = this
      , values        = fields ? {} : this.values
      , updatedAtAttr = this.__options.underscored ? 'updated_at' : 'updatedAt'
      , createdAtAttr = this.__options.underscored ? 'created_at' : 'createdAt'

    if (fields) {
      if (self.__options.timestamps) {
        if (fields.indexOf(updatedAtAttr) === -1) {
          fields.push(updatedAtAttr)
        }

        if (fields.indexOf(createdAtAttr) === -1) {
          fields.push(createdAtAttr)
        }
      }

      fields.forEach(function(field) {
        if (self.values[field] !== undefined) {
          values[field] = self.values[field]
        }
      })
    }

    for (var attrName in this.daoFactory.rawAttributes) {
      if (this.daoFactory.rawAttributes.hasOwnProperty(attrName)) {
        var definition      = this.daoFactory.rawAttributes[attrName]
          , isEnum          = (definition.type && (definition.type.toString() === DataTypes.ENUM.toString()))
          , hasValue        = (typeof values[attrName] !== 'undefined')
          , valueOutOfScope = ((definition.values || []).indexOf(values[attrName]) === -1)

        if (isEnum && hasValue && valueOutOfScope) {
          throw new Error('Value "' + values[attrName] + '" for ENUM ' + attrName + ' is out of allowed scope. Allowed values: ' + definition.values.join(', '))
        }
      }
    }

    if (this.__options.timestamps && this.hasOwnProperty(updatedAtAttr)) {
      this[updatedAtAttr] = values[updatedAtAttr] = Utils.now()
    }

    if (this.isNewRecord) {
      return this.QueryInterface.insert(this, this.__factory.tableName, values)
    } else {
      var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : this.id;

      if (identifier === null && this.__options.whereCollection !== null) {
        identifier = this.__options.whereCollection;
      }

      var tableName  = this.__factory.tableName
        , query      = this.QueryInterface.update(this, tableName, values, identifier)

      return query
    }
  }

 /*
  * Refresh the current instance in-place, i.e. update the object with current data from the DB and return the same object.
  * This is different from doing a `find(DAO.id)`, because that would create and return a new object. With this method,
  * all references to the DAO are updated with the new data and no new objects are created.
  *
  * @return {Object}         A promise which fires `success`, `error`, `complete` and `sql`.
  */
  DAO.prototype.reload = function() {
    var where = [
      this.QueryInterface.QueryGenerator.addQuotes(this.__factory.tableName) + '.' + this.QueryInterface.QueryGenerator.addQuotes('id')+'=?',
      this.id
    ]

    return new Utils.CustomEventEmitter(function(emitter) {
      this.__factory.find({
        where:   where,
        limit:   1,
        include: this.__eagerlyLoadedOptions || []
      })
      .on('sql', function(sql) { emitter.emit('sql', sql) })
      .on('error', function(error) { emitter.emit('error', error) })
      .on('success', function(obj) {
        for (var valueName in obj.values) {
          if (obj.values.hasOwnProperty(valueName)) {
            this[valueName] = obj.values[valueName]
          }
        }
        emitter.emit('success', this)
      }.bind(this))
    }.bind(this)).run()
  }

  /*
   * Validate this dao's attribute values according to validation rules set in the dao definition.
   *
   * @return null if and only if validation successful; otherwise an object containing { field name : [error msgs] } entries.
   */
{'fraction_non_alphanumeric': 0.12657037860011966, 'fraction_numerical': 0.0009400905905478165, 'mean_word_length': 2.5535985423625873, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5844695', 'n_tokens_mistral': 3426, 'n_tokens_neox': 3363, 'n_words': 757}