UNPKG

pg-promise

Version:
314 lines (283 loc) 9.75 kB
/* * 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 {PreparedStatementError} = require('../errors'); const {QueryFile} = require('../query-file'); const {assert} = require('../assert'); const npm = { EOL: require('os').EOL, utils: require('../utils') }; /** * @class PreparedStatement * @description * Constructs a new $[Prepared Statement] object. All properties can also be set after the object's construction. * * This type extends the basic `{name, text, values}` object, i.e. when the basic object is used * with a query method, a new {@link PreparedStatement} 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.PreparedStatement`. * * @param {Object} [options] * Object configuration options / properties. * * @param {string} [options.name] - See property {@link PreparedStatement#name name}. * @param {string|QueryFile} [options.text] - See property {@link PreparedStatement#text text}. * @param {array} [options.values] - See property {@link PreparedStatement#values values}. * @param {boolean} [options.binary] - See property {@link PreparedStatement#binary binary}. * @param {string} [options.rowMode] - See property {@link PreparedStatement#rowMode rowMode}. * @param {number} [options.rows] - See property {@link PreparedStatement#rows rows}. * @param {ITypes} [options.types] - See property {@link PreparedStatement#types types}. * * @returns {PreparedStatement} * * @see * {@link errors.PreparedStatementError PreparedStatementError}, * {@link http://www.postgresql.org/docs/9.6/static/sql-prepare.html PostgreSQL Prepared Statements} * * @example * * const {PreparedStatement: PS} = require('pg-promise'); * * // Creating a complete Prepared Statement with parameters: * const findUser = new PS({name: 'find-user', text: 'SELECT * FROM Users WHERE id = $1', values: [123]}); * * db.one(findUser) * .then(user => { * // user found; * }) * .catch(error => { * // error; * }); * * @example * * const {PreparedStatement: PS} = require('pg-promise'); * * // Creating a reusable Prepared Statement without values: * const addUser = new PS({name: 'add-user', text: '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 PreparedStatement extends ServerFormatting { constructor(options) { options = assert(options, ['name', 'text', 'values', 'binary', 'rowMode', 'rows', 'types']); super(options); } /** * @name PreparedStatement#name * @type {string} * @description * An arbitrary name given to this particular prepared statement. It must be unique within a single session and is * subsequently used to execute or deallocate a previously prepared statement. */ get name() { return this._inner.options.name; } set name(value) { const _i = this._inner; if (value !== _i.options.name) { _i.options.name = value; _i.changed = true; } } /** * @name PreparedStatement#rows * @type {number} * @description * Number of rows to return at a time from a Prepared Statement's portal. * The default is 0, which means that all rows must be returned at once. */ get rows() { return this._inner.options.rows; } set rows(value) { const _i = this._inner; if (value !== _i.options.rows) { _i.options.rows = value; _i.changed = true; } } } /** * @method PreparedStatement#parse * @description * Parses the current object and returns a simple `{name, text, values}`, if successful, * or else it returns a {@link errors.PreparedStatementError PreparedStatementError} object. * * This method is primarily for internal use by the library. * * @returns {{name, text, values}|errors.PreparedStatementError} */ PreparedStatement.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 = { name: options.name, text: options.text }; _i.changed = true; _i.currentError = undefined; if (!npm.utils.isText(_i.target.name)) { errors.push('Property \'name\' must be a non-empty text string.'); } 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.rows !== undefined) { _i.target.rows = options.rows; } if (options.types !== undefined) { _i.target.types = options.types; } if (errors.length) { return _i.currentError = new PreparedStatementError(errors[0], _i.target); } _i.changed = false; return _i.target; }; /** * @method PreparedStatement#toString * @description * Creates a well-formatted multi-line string that represents the object's current state. * * It is called automatically when writing the object into the console. * * @param {number} [level=0] * Nested output level, to provide visual offset. * * @returns {string} */ PreparedStatement.prototype.toString = function (level) { level = level > 0 ? parseInt(level) : 0; const gap = npm.utils.messageGap(level + 1); const ps = this.parse(); const lines = [ 'PreparedStatement {', gap + 'name: ' + npm.utils.toJson(this.name) ]; if (npm.utils.isText(ps.text)) { lines.push(gap + 'text: "' + ps.text + '"'); } if (this.values !== undefined) { lines.push(gap + 'values: ' + npm.utils.toJson(this.values)); } if (this.binary !== undefined) { lines.push(gap + 'binary: ' + npm.utils.toJson(this.binary)); } if (this.rowMode !== undefined) { lines.push(gap + 'rowMode: ' + npm.utils.toJson(this.rowMode)); } if (this.rows !== undefined) { lines.push(gap + 'rows: ' + npm.utils.toJson(this.rows)); } if (this.error) { lines.push(gap + 'error: ' + this.error.toString(level + 1)); } lines.push(npm.utils.messageGap(level) + '}'); return lines.join(npm.EOL); }; module.exports = {PreparedStatement}; /** * @name PreparedStatement#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 $[Prepared Statements] * are formatted on the server side. * * Changing this property for the same {@link PreparedStatement#name name} will have no effect, because queries * for Prepared Statements are cached by the server, with {@link PreparedStatement#name name} being the cache key. */ /** * @name PreparedStatement#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 PreparedStatement#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 PreparedStatement#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 PreparedStatement#types * @type {ITypes} * @default undefined * @description * Custom type parsers just for this query result. */ /** * @name PreparedStatement#error * @type {errors.PreparedStatementError} * @default undefined * @description * When in an error state, it is set to a {@link errors.PreparedStatementError PreparedStatementError} object. Otherwise, it is `undefined`. * * This property is primarily for internal use by the library. */