/* * 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 {PromiseAdapter} = require(`./promise-adapter`); const {DatabasePool} = require(`./database-pool`); const {PreparedStatement, ParameterizedQuery} = require(`./types`); const {QueryFile} = require(`./query-file`); const {queryResult} = require(`./query-result`); const {parsePromise} = require(`./promise-parser`); const {assertOptions} = require(`assert-options`); const npm = { path: require(`path`), pg: require(`pg`), minify: require(`pg-minify`), formatting: require(`./formatting`), helpers: require(`./helpers`), errors: require(`./errors`), utils: require(`./utils`), pubUtils: require(`./utils/public`), mode: require(`./tx-mode`), package: require(`../package.json`), text: require(`./text`) }; let originalClientConnect; /** * @author Vitaly Tomilov * @module pg-promise * * @description * ## pg-promise v10 * All documentation here is for the latest official release only. * * ### Initialization Options * * Below is the complete list of _Initialization Options_ for the library that can be passed in during * the library's initialization: * * ```js * const initOptions = {/* options as documented below */}; * * const pgp = require('pg-promise')(initOptions); * ``` * * @param {{}} [options] * Library Initialization Options. * * @param {boolean} [options.pgFormatting=false] * Redirects all query formatting to the $[pg] driver. * * By default (`false`), the library uses its own advanced query-formatting engine. * If you set this option to a truthy value, query formatting will be done entirely by the * $[pg] driver, which means you won't be able to use any of the feature-rich query formatting * that this library implements, restricting yourself to the very basic `$1, $2,...` syntax. * * This option is dynamic (can be set before or after initialization). * * @param {boolean} [options.pgNative=false] * Use $[Native Bindings]. Library $[pg-native] must be included and installed independently, or else there will * be an error thrown: {@link external:Error Error} = `Failed to initialize Native Bindings.` * * This is a static option (can only be set prior to initialization). * * @param {object|function} [options.promiseLib=Promise] * Overrides the default (ES6 Promise) promise library for its internal use. * * Example below sets to use $[Bluebird] - the best and recommended promise library. It is the fastest one, * and supports $[Long Stack Traces], essential for debugging promises. * * ```js * const Promise = require('bluebird'); * const initOptions = { * promiseLib: Promise * }; * const pgp = require('pg-promise')(initOptions); * ``` * * All existing promise libraries are supported. The ones with recognizable signature are used automatically, * while the rest can be configured via the $[Promise Adapter]. * * This is a static option (can only be set prior to initialization). * * @param {boolean} [options.noLocking=false] * Prevents protocol locking. * * By default, the library locks much of its protocol to read-only access, as a fool-proof mechanism. * Specifically for the {@link event:extend extend} event this serves as a protection against overriding existing * properties or trying to set them at the wrong time. * * If this provision gets in the way of using a mock-up framework for your tests, you can force * the library to deactivate most of the locks by setting `noLocking` = `true` within the options. * * This option is dynamic (can be set before or after initialization). However, changing it after the library's * initialization will not affect {@link Database} objects that have already been created. * * @param {boolean} [options.capSQL=false] * Capitalizes any SQL generated by the library. * * By default, all internal SQL within the library is generated using the low case. * If, however, you want all SQL to be capitalized instead, set `capSQL` = `true`. * * It is purely a cosmetic feature. * * This option is dynamic (can be set before or after initialization). * * @param {string|Array|null|undefined|function} [options.schema] * Forces change of the default database schema(s) for every fresh connection, i.e. * the library will execute `SET search_path TO schema_1, schema_2, ...` in the background * whenever a fresh physical connection is allocated. * * Normally, one changes the default schema(s) by $[changing the database or the role], but sometimes you * may want to switch the default schema(s) without persisting the change, and then use this option. * * It can be a string, an array of strings, or a callback function that takes `dc` (database context) * as the only parameter (and as `this`), and returns schema(s) according to the database context. A callback function * can also return nothing (`undefined` or `null`), if no schema change needed for the specified database context. * * The order of schema names matters, so if a table name exists in more than one schema, its default access resolves * to the table from the first such schema on the list. * * This option is dynamic (can be set before or after initialization). * * @param {boolean} [options.noWarnings=false] * Disables all diagnostic warnings in the library (it is ill-advised). * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.connect] * Global event {@link event:connect connect} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.disconnect] * Global event {@link event:disconnect disconnect} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.query] * Global event {@link event:query query} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.receive] * Global event {@link event:receive receive} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.task] * Global event {@link event:task task} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.transact] * Global event {@link event:transact transact} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.error] * Global event {@link event:error error} handler. * * This option is dynamic (can be set before or after initialization). * * @param {function} [options.extend] * Global event {@link event:extend extend} handler. * * This option is dynamic (can be set before or after initialization). * * @see * {@link module:pg-promise~end end}, * {@link module:pg-promise~as as}, * {@link module:pg-promise~errors errors}, * {@link module:pg-promise~helpers helpers}, * {@link module:pg-promise~minify minify}, * {@link module:pg-promise~ParameterizedQuery ParameterizedQuery}, * {@link module:pg-promise~PreparedStatement PreparedStatement}, * {@link module:pg-promise~pg pg}, * {@link module:pg-promise~QueryFile QueryFile}, * {@link module:pg-promise~queryResult queryResult}, * {@link module:pg-promise~spex spex}, * {@link module:pg-promise~txMode txMode}, * {@link module:pg-promise~utils utils} * */ function $main(options) { options = assertOptions(options, [`pgFormatting`, `pgNative`, `promiseLib`, `noLocking`, `capSQL`, `noWarnings`, `connect`, `disconnect`, `query`, `receive`, `task`, `transact`, `error`, `extend`, `schema`]); let pg = npm.pg; const p = parsePromise(options.promiseLib); const config = { version: npm.package.version, promiseLib: p.promiseLib, promise: p.promise }; npm.utils.addReadProp(config, `$npm`, {}, true); // Locking properties that cannot be changed later: npm.utils.addReadProp(options, `promiseLib`, options.promiseLib); npm.utils.addReadProp(options, `pgNative`, !!options.pgNative); config.options = options; // istanbul ignore next: // we do not cover code specific to Native Bindings if (options.pgNative) { pg = npm.pg.native; if (npm.utils.isNull(pg)) { throw new Error(npm.text.nativeError); } } else { if (!originalClientConnect) { originalClientConnect = pg.Client.prototype.connect; pg.Client.prototype.connect = function () { const handler = msg => { if (msg.parameterName === `server_version`) { this.serverVersion = msg.parameterValue; this.connection.removeListener(`parameterStatus`, handler); } }; this.connection.on(`parameterStatus`, handler); return originalClientConnect.call(this, ...arguments); }; } } const Database = require(`./database`)(config); const inst = (cn, dc) => { if (npm.utils.isText(cn) || (cn && typeof cn === `object`)) { return new Database(cn, dc, config); } throw new TypeError(`Invalid connection details: ` + npm.utils.toJson(cn)); }; npm.utils.addReadProperties(inst, rootNameSpace); /** * @member {external:PG} pg * @description * Instance of the $[pg] library that's being used, depending on initialization option `pgNative`: * - regular `pg` module instance, without option `pgNative`, or equal to `false` (default) * - `pg` module instance with $[Native Bindings], if option `pgNative` was set. * * Available as `pgp.pg`, after initializing the library. */ inst.pg = pg; // keep it modifiable, so the protocol can be mocked /** * @member {function} end * @readonly * @description * Shuts down all connection pools created in the process, so it can terminate without delay. * It is available as `pgp.end`, after initializing the library. * * All {@link Database} objects created previously can no longer be used, and their query methods will be rejecting * with {@link external:Error Error} = `Connection pool of the database object has been destroyed.` * * And if you want to shut down only a specific connection pool, you do so via the {@link Database} * object that owns the pool: `db.$pool.end()` (see {@link Database#$pool Database.$pool}). * * For more details see $[Library de-initialization]. */ npm.utils.addReadProp(inst, `end`, () => { DatabasePool.shutDown(); }); /** * @member {helpers} helpers * @readonly * @description * Namespace for {@link helpers all query-formatting helper functions}. * * Available as `pgp.helpers`, after initializing the library. * * @see {@link helpers}. */ npm.utils.addReadProp(inst, `helpers`, npm.helpers(config)); /** * @member {external:spex} spex * @readonly * @description * Initialized instance of the $[spex] module, used by the library within tasks and transactions. * * Available as `pgp.spex`, after initializing the library. * * @see * {@link Task#batch}, * {@link Task#page}, * {@link Task#sequence} */ npm.utils.addReadProp(inst, `spex`, config.$npm.spex); config.pgp = inst; npm.utils.lock(config, true, options); return inst; } const rootNameSpace = { /** * @member {formatting} as * @readonly * @description * Namespace for {@link formatting all query-formatting functions}. * * Available as `pgp.as`, before and after initializing the library. * * @see {@link formatting}. */ as: npm.formatting.as, /** * @member {external:pg-minify} minify * @readonly * @description * Instance of the $[pg-minify] library used internally to minify SQL scripts. * * Available as `pgp.minify`, before and after initializing the library. */ minify: npm.minify, /** * @member {queryResult} queryResult * @readonly * @description * Query Result Mask enumerator. * * Available as `pgp.queryResult`, before and after initializing the library. */ queryResult, /** * @member {PromiseAdapter} PromiseAdapter * @readonly * @description * {@link PromiseAdapter} class. * * Available as `pgp.PromiseAdapter`, before and after initializing the library. */ PromiseAdapter, /** * @member {ParameterizedQuery} ParameterizedQuery * @readonly * @description * {@link ParameterizedQuery} class. * * Available as `pgp.ParameterizedQuery`, before and after initializing the library. */ ParameterizedQuery, /** * @member {PreparedStatement} PreparedStatement * @readonly * @description * {@link PreparedStatement} class. * * Available as `pgp.PreparedStatement`, before and after initializing the library. */ PreparedStatement, /** * @member {QueryFile} QueryFile * @readonly * @description * {@link QueryFile} class. * * Available as `pgp.QueryFile`, before and after initializing the library. */ QueryFile, /** * @member {errors} errors * @readonly * @description * {@link errors} - namespace for all error types. * * Available as `pgp.errors`, before and after initializing the library. */ errors: npm.errors, /** * @member {utils} utils * @readonly * @description * {@link utils} - namespace for utility functions. * * Available as `pgp.utils`, before and after initializing the library. */ utils: npm.pubUtils, /** * @member {txMode} txMode * @readonly * @description * {@link txMode Transaction Mode} namespace. * * Available as `pgp.txMode`, before and after initializing the library. */ txMode: npm.mode }; npm.utils.addReadProperties($main, rootNameSpace); module.exports = $main; /** * @external Promise * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise */ /** * @external PG * @see https://node-postgres.com */ /** * @external Client * @see https://node-postgres.com/api/client */ /** * @external pg-minify * @see https://github.com/vitaly-t/pg-minify */ /** * @external spex * @see https://github.com/vitaly-t/spex */