repo_description: PostgreSQL interface for Node.js
repo_topics: javascript nodejs postgresql promise-library promises transaction typescript
code: /*
   * 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 {ServerFormatting} = require('./server-formatting');
  const {ParameterizedQueryError} = require('../errors');
  const {QueryFile} = require('../query-file');
  const {assert} = require('../assert');
  
  const npm = {
      EOL: require('os').EOL,
      utils: require('../utils'),
      inspect: require('util').inspect
  };
  
  /**
   * @class ParameterizedQuery
   * @description
   * Constructs a new {@link ParameterizedQuery} object. All properties can also be set after the object's construction.
   *
   * This type extends the basic `{text, values}` object, i.e. when the basic object is used with a query method,
   * a new {@link ParameterizedQuery} object is created in its place.
   *
   * The type can be used in place of the `query` parameter, with any query method directly.
   *
   * The type is available from the library's root: `pgp.ParameterizedQuery`.
   *
   * @param {string|QueryFile|Object} [options]
   * Object configuration options / properties.
   *
   * @param {string|QueryFile} [options.text] - See property {@link ParameterizedQuery#text text}.
   * @param {array} [options.values] - See property {@link ParameterizedQuery#values values}.
   * @param {boolean} [options.binary] - See property {@link ParameterizedQuery#binary binary}.
   * @param {string} [options.rowMode] - See property {@link ParameterizedQuery#rowMode rowMode}.
   * @param {ITypes} [options.types] - See property {@link ParameterizedQuery#types types}.
   *
   * @returns {ParameterizedQuery}
   *
   * @see
   * {@link errors.ParameterizedQueryError ParameterizedQueryError}
   *
   * @example
   *
   * const {ParameterizedQuery: PQ} = require('pg-promise');
   *
   * // Creating a complete Parameterized Query with parameters:
   * const findUser = new PQ({text: 'SELECT * FROM Users WHERE id = $1', values: [123]});
   *
   * db.one(findUser)
   *     .then(user => {
   *         // user found;
   *     })
   *     .catch(error => {
   *         // error;
   *     });
   *
   * @example
   *
   * const {ParameterizedQuery: PQ} = require('pg-promise');
   *
   * // Creating a reusable Parameterized Query without values:
   * const addUser = new PQ('INSERT INTO Users(name, age) VALUES($1, $2)');
   *
   * // setting values explicitly:
   * addUser.values = ['John', 30];
   *
   * db.none(addUser)
   *     .then(() => {
   *         // user added;
   *     })
   *     .catch(error=> {
   *         // error;
   *     });
   *
   * // setting values implicitly, by passing them into the query method:
   * db.none(addUser, ['Mike', 25])
   *     .then(() => {
   *         // user added;
   *     })
   *     .catch(error=> {
   *         // error;
   *     });
   */
  class ParameterizedQuery extends ServerFormatting {
      constructor(options) {
          if (typeof options === 'string' || options instanceof QueryFile) {
              options = {
                  text: options
              };
          } else {
              options = assert(options, ['text', 'values', 'binary', 'rowMode', 'types']);
          }
          super(options);
      }
  }
  
  /**
   * @method ParameterizedQuery#parse
   * @description
   * Parses the current object and returns a simple `{text, values}`, if successful,
   * or else it returns a {@link errors.ParameterizedQueryError ParameterizedQueryError} object.
   *
   * This method is primarily for internal use by the library.
   *
   * @returns {{text, values}|errors.ParameterizedQueryError}
   */
  ParameterizedQuery.prototype.parse = function () {
  
      const _i = this._inner, options = _i.options;
      const qf = options.text instanceof QueryFile ? options.text : null;
  
      if (!_i.changed && !qf) {
          return _i.target;
      }
  
      const errors = [], values = _i.target.values;
      _i.target = {
          text: options.text
      };
      _i.changed = true;
      _i.currentError = undefined;
  
      if (qf) {
          qf.prepare();
          if (qf.error) {
              errors.push(qf.error);
          } else {
              _i.target.text = qf[QueryFile.$query];
          }
      }
  
      if (!npm.utils.isText(_i.target.text)) {
          errors.push('Property \'text\' must be a non-empty text string.');
      }
  
      if (!npm.utils.isNull(values)) {
          _i.target.values = values;
      }
  
      if (options.binary !== undefined) {
          _i.target.binary = !!options.binary;
      }
  
      if (options.rowMode !== undefined) {
          _i.target.rowMode = options.rowMode;
      }
  
      if (options.types !== undefined) {
          _i.target.types = options.types;
      }
  
      if (errors.length) {
          return _i.currentError = new ParameterizedQueryError(errors[0], _i.target);
      }
  
      _i.changed = false;
  
      return _i.target;
  };
  
  npm.utils.addInspection(ParameterizedQuery, function () {
      const pq = this.parse();
      const obj = {};
      if (npm.utils.isText(pq.text)) {
          obj.text = pq.text;
      }
      if (this.values !== undefined) {
          obj.values = this.values;
      }
      if (this.binary !== undefined) {
          obj.binary = this.binary;
      }
      if (this.rowMode !== undefined) {
          obj.rowMode = this.rowMode;
      }
      if (this.error !== undefined) {
          obj.error = this.error.message;
      }
      return 'ParameterizedQuery ' + npm.inspect(obj, {breakLength: 100, depth: 5, colors: true});
  });
  
  module.exports = {ParameterizedQuery};
  
  /**
   * @name ParameterizedQuery#text
   * @type {string|QueryFile}
   * @description
   * A non-empty query string or a {@link QueryFile} object.
   *
   * Only the basic variables (`$1`, `$2`, etc) can be used in the query, because _Parameterized Queries_
   * are formatted on the server side.
   */
  
  /**
   * @name ParameterizedQuery#values
   * @type {array}
   * @description
   * Query formatting parameters, depending on the type:
   *
   * - `null` / `undefined` means the query has no formatting parameters
   * - `Array` - it is an array of formatting parameters
   * - None of the above, means it is a single formatting value, which
   *   is then automatically wrapped into an array
   */
  
  /**
   * @name ParameterizedQuery#binary
   * @type {boolean}
   * @default undefined
   * @description
   * Activates binary result mode. The default is the text mode.
   *
   * @see {@link http://www.postgresql.org/docs/devel/static/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY Extended Query}
   */
  
  /**
   * @name ParameterizedQuery#rowMode
   * @type {string}
   * @default undefined
   * @description
   * Changes the way data arrives to the client, with only one value supported by $[pg]:
   *  - `array` will make all data rows arrive as arrays of values. By default, rows arrive as objects.
   */
  
  /**
   * @name ParameterizedQuery#types
   * @type {ITypes}
   * @default undefined
   * @description
   * Custom type parsers just for this query result.
   */
  
  /**
   * @name ParameterizedQuery#error
   * @type {errors.ParameterizedQueryError}
   * @default undefined
   * @readonly
   * @description
   * When in an error state, it is set to a {@link errors.ParameterizedQueryError ParameterizedQueryError} object. Otherwise, it is `undefined`.
   *
   * This property is primarily for internal use by the library.
   */
  