You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
444 lines
15 KiB
444 lines
15 KiB
2 years ago
|
/*
|
||
|
* 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<string>|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
|
||
|
*/
|