text: 'use strict'
  
  /*
   * adonis-lucid
   *
   * (c) Harminder Virk <virk@adonisjs.com>
   *
   * For the full copyright and license information, please view the LICENSE
   * file that was distributed with this source code.
  */
  
  const _ = require('lodash')
  const chancejs = require('./chance')
  const { ioc } = require('../../lib/iocResolver')
  
  /**
   * Model factory to seed database using Lucid
   * models
   *
   * @class DatabaseFactory
   * @constructor
   */
  class DatabaseFactory {
    constructor (tableName, dataCallback) {
      this.tableName = tableName
      this.dataCallback = dataCallback
      this._returningColumn = null
      this._connection = null
    }
  
    /**
     * Returns the query builder instance for
     * a given connection
     *
     * @method _getQueryBuilder
     *
     * @return {Object}
     *
     * @private
     */
    _getQueryBuilder () {
      return this._connection
        ? ioc.use('Adonis/Src/Database').connection(this._connection)
        : ioc.use('Adonis/Src/Database')
    }
  
    /**
     * Make a single instance of blueprint for a given
     * index. This method will evaluate the functions
     * in the return payload from blueprint.
     *
     * @method _makeOne
     * @async
     *
     * @param  {Number} index
     * @param  {Object} data
     *
     * @return {Object}
     *
     * @private
     */
    async _makeOne (index, data) {
      const hash = await this.dataCallback(chancejs, index, data)
      const keys = _.keys(hash)
  
      /**
       * Evaluate all values
       */
      const values = await Promise.all(_.map(_.values(hash), (val) => {
        return typeof (val) === 'function' ? Promise.resolve(val()) : val
      }))
  
      /**
       * Pair them back in same order
       */
      return _.transform(keys, (result, key, index) => {
        result[key] = values[index]
        return result
      }, {})
    }
  
    /**
     * Set table to used for the database
     * operations
     *
     * @method table
     *
     * @param  {String} tableName
     *
     * @chainable
     */
    table (tableName) {
      this.tableName = tableName
      return this
    }
  
    /**
     * Specify the returning column from the insert
     * query
     *
     * @method returning
     *
     * @param  {String}  column
     *
     * @chainable
     */
    returning (column) {
      this._returningColumn = column
      return this
    }
  
    /**
     * Specify the connection to be used on
     * the query builder
     *
     * @method connection
     *
     * @param  {String}   connection
     *
     * @chainable
     */
    connection (connection) {
      this._connection = connection
      return this
    }
  
    /**
     * Make a single model instance with attributes
     * from blueprint fake values
     *
     * @method make
     * @async
     *
     * @param  {Object} data
     * @param  {Number} [index = 0]
     *
     * @return {Object}
     */
    async make (data = {}, index = 0) {
      return this._makeOne(index, data)
    }
  
    /**
     * Make x number of model instances with
     * fake data
     *
     * @method makeMany
     * @async
     *
     * @param  {Number} instances
     * @param  {Object} [data = {}]
     *
     * @return {Array}
     */
    async makeMany (instances, data = {}) {
      return Promise.all(_.map(_.range(instances), (index) => this.make(data, index)))
    }
  
    /**
     * Create model instance and persist to database
     * and then return it back
     *
     * @method create
     * @async
     *
     * @param  {Object} data
     *
     * @return {Object}
     */
    async create (data = {}, index = 0) {
      const attributes = await this.make(data, index)
      const query = this._getQueryBuilder().table(this.tableName)
  
      if (this._returningColumn) {
        query.returning(this._returningColumn)
      }
  
      return query.insert(attributes)
    }
  
    /**
     * Persist multiple model instances to database and get
     * them back as an array
     *
     * @method createMany
     * @async
     *
     * @param  {Number}   numberOfRows
     * @param  {Object}   [data = {}]
     *
     * @return {Array}
     */
    async createMany (numberOfRows, data = {}) {
      const rows = []
  
      for (const index of _.range(numberOfRows)) {
        const row = await this.create(data, index)
        rows.push(row)
      }
  
      return rows
    }
  
    /**
     * Truncate the database table
     *
     * @method reset
     * @async
     *
     * @return {Number}
     */
    async reset () {
      return this._getQueryBuilder().table(this.tableName).truncate()
    }
  }
  
  module.exports = DatabaseFactory
  