text: /*
   * Copyright (c) 2015-present, Vitaly Tomilov
   *
   * See the LICENSE file at the top-level directory of this distribution
   * for licensing information.
   *
   * Removal or modification of this copyright notice is prohibited.
   */
  
  const {TableName} = require('../table-name');
  const {ColumnSet} = require('../column-set');
  
  const npm = {
      formatting: require('../../formatting'),
      utils: require('../../utils')
  };
  
  /**
   * @method helpers.insert
   * @description
   * Generates an `INSERT` query for either one object or an array of objects.
   *
   * @param {object|object[]} data
   * An insert object with properties for insert values, or an array of such objects.
   *
   * When `data` is not a non-null object and not an array, it will throw {@link external:TypeError TypeError} = `Invalid parameter 'data' specified.`
   *
   * When `data` is an empty array, it will throw {@link external:TypeError TypeError} = `Cannot generate an INSERT from an empty array.`
   *
   * When `data` is an array that contains a non-object value, the method will throw {@link external:Error Error} =
   * `Invalid insert object at index N.`
   *
   * @param {array|helpers.Column|helpers.ColumnSet} [columns]
   * Set of columns to be inserted.
   *
   * It is optional when `data` is a single object, and required when `data` is an array of objects. If not specified for an array
   * of objects, the method will throw {@link external:TypeError TypeError} = `Parameter 'columns' is required when inserting multiple records.`
   *
   * When `columns` is not a {@link helpers.ColumnSet ColumnSet} object, a temporary {@link helpers.ColumnSet ColumnSet}
   * is created - from the value of `columns` (if it was specified), or from the value of `data` (if it is not an array).
   *
   * When the final {@link helpers.ColumnSet ColumnSet} is empty (no columns in it), the method will throw
   * {@link external:Error Error} = `Cannot generate an INSERT without any columns.`
   *
   * @param {helpers.TableName|string|{table,schema}} [table]
   * Destination table.
   *
   * It is normally a required parameter. But when `columns` is passed in as a {@link helpers.ColumnSet ColumnSet} object
   * with `table` set in it, that will be used when this parameter isn't specified. When neither is available, the method
   * will throw {@link external:Error Error} = `Table name is unknown.`
   *
   * @returns {string}
   * The resulting query string.
   *
   * @see
   *  {@link helpers.Column Column},
   *  {@link helpers.ColumnSet ColumnSet},
   *  {@link helpers.TableName TableName}
   *
   * @example
   *
   * const pgp = require('pg-promise')({
   *    capSQL: true // if you want all generated SQL capitalized
   * });
   *
   * const dataSingle = {val: 123, msg: 'hello'};
   * const dataMulti = [{val: 123, msg: 'hello'}, {val: 456, msg: 'world!'}];
   *
   * // Column details can be taken from the data object:
   *
   * pgp.helpers.insert(dataSingle, null, 'my-table');
   * //=> INSERT INTO "my-table"("val","msg") VALUES(123,'hello')
   *
   * @example
   *
   * // Column details are required for a multi-row `INSERT`:
   *
   * pgp.helpers.insert(dataMulti, ['val', 'msg'], 'my-table');
   * //=> INSERT INTO "my-table"("val","msg") VALUES(123,'hello'),(456,'world!')
   *
   * @example
   *
   * // Column details from a reusable ColumnSet (recommended for performance):
   *
   * const cs = new pgp.helpers.ColumnSet(['val', 'msg'], {table: 'my-table'});
   *
   * pgp.helpers.insert(dataMulti, cs);
   * //=> INSERT INTO "my-table"("val","msg") VALUES(123,'hello'),(456,'world!')
   *
   */
  function insert(data, columns, table, capSQL) {
  
      if (!data || typeof data !== 'object') {
          throw new TypeError('Invalid parameter \'data\' specified.');
      }
  
      const isArray = Array.isArray(data);
  
      if (isArray && !data.length) {
          throw new TypeError('Cannot generate an INSERT from an empty array.');
      }
  
      if (columns instanceof ColumnSet) {
          if (npm.utils.isNull(table)) {
              table = columns.table;
          }
      } else {
          if (isArray && npm.utils.isNull(columns)) {
              throw new TypeError('Parameter \'columns\' is required when inserting multiple records.');
          }
          columns = new ColumnSet(columns || data);
      }
  
      if (!columns.columns.length) {
          throw new Error('Cannot generate an INSERT without any columns.');
      }
  
      if (!table) {
          throw new Error('Table name is unknown.');
      }
  
      if (!(table instanceof TableName)) {
          table = new TableName(table);
      }
  
      let query = capSQL ? sql.capCase : sql.lowCase;
      const fmOptions = {capSQL};
  
      const format = npm.formatting.as.format;
      query = format(query, [table.name, columns.names], fmOptions);
  
      if (isArray) {
          return query + data.map((d, index) => {
              if (!d || typeof d !== 'object') {
                  throw new Error('Invalid insert object at index ' + index + '.');
              }
              return '(' + format(columns.variables, columns.prepare(d), fmOptions) + ')';
          }).join();
      }
      return query + '(' + format(columns.variables, columns.prepare(data), fmOptions) + ')';
  }
  
  const sql = {
      lowCase: 'insert into $1^($2^) values',
      capCase: 'INSERT INTO $1^($2^) VALUES'
  };
  
  module.exports = {insert};
  