main.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. * Copyright (c) 2015-present, Vitaly Tomilov
  3. *
  4. * See the LICENSE file at the top-level directory of this distribution
  5. * for licensing information.
  6. *
  7. * Removal or modification of this copyright notice is prohibited.
  8. */
  9. const {PromiseAdapter} = require('./promise-adapter');
  10. const {DatabasePool} = require('./database-pool');
  11. const {PreparedStatement, ParameterizedQuery} = require('./types');
  12. const {QueryFile} = require('./query-file');
  13. const {queryResult} = require('./query-result');
  14. const {parsePromise} = require('./promise-parser');
  15. const {assert} = require('./assert');
  16. const npm = {
  17. path: require('path'),
  18. pg: require('pg'),
  19. minify: require('pg-minify'),
  20. formatting: require('./formatting'),
  21. helpers: require('./helpers'),
  22. errors: require('./errors'),
  23. utils: require('./utils'),
  24. pubUtils: require('./utils/public'),
  25. mode: require('./tx-mode'),
  26. package: require('../package.json'),
  27. text: require('./text')
  28. };
  29. let originalClientConnect;
  30. /**
  31. * @author Vitaly Tomilov
  32. * @module pg-promise
  33. *
  34. * @description
  35. * ## pg-promise v11.4
  36. * All documentation here is for the latest official release only.
  37. *
  38. * ### Initialization Options
  39. *
  40. * Below is the complete list of _Initialization Options_ for the library that can be passed in during
  41. * the library's initialization:
  42. *
  43. * ```js
  44. * const initOptions = {/* options as documented below */};
  45. *
  46. * const pgp = require('pg-promise')(initOptions);
  47. * ```
  48. *
  49. * @property {{}} [options]
  50. * Library Initialization Options.
  51. *
  52. * @property {boolean} [options.pgFormatting=false]
  53. * Redirects all query formatting to the $[pg] driver.
  54. *
  55. * By default (`false`), the library uses its own advanced query-formatting engine.
  56. * If you set this option to a truthy value, query formatting will be done entirely by the
  57. * $[pg] driver, which means you won't be able to use any of the feature-rich query formatting
  58. * that this library implements, restricting yourself to the very basic `$1, $2,...` syntax.
  59. *
  60. * This option is dynamic (can be set before or after initialization).
  61. *
  62. * @property {boolean} [options.pgNative=false]
  63. * Use $[Native Bindings]. Library $[pg-native] must be included and installed independently, or else there will
  64. * be an error thrown: {@link external:Error Error} = `Failed to initialize Native Bindings.`
  65. *
  66. * This is a static option (can only be set prior to initialization).
  67. *
  68. * @property {object|function} [options.promiseLib=Promise]
  69. * Overrides the default (ES6 Promise) promise library for its internal use.
  70. *
  71. * Example below sets to use $[Bluebird] - the best and recommended promise library. It is the fastest one,
  72. * and supports $[Long Stack Traces], essential for debugging promises.
  73. *
  74. * ```js
  75. * const Promise = require('bluebird');
  76. * const initOptions = {
  77. * promiseLib: Promise
  78. * };
  79. * const pgp = require('pg-promise')(initOptions);
  80. * ```
  81. *
  82. * All existing promise libraries are supported. The ones with recognizable signature are used automatically,
  83. * while the rest can be configured via the $[Promise Adapter].
  84. *
  85. * This is a static option (can only be set prior to initialization).
  86. *
  87. * @property {boolean} [options.capSQL=false]
  88. * Capitalizes any SQL generated by the library.
  89. *
  90. * By default, all internal SQL within the library is generated using the low case.
  91. * If, however, you want all SQL to be capitalized instead, set `capSQL` = `true`.
  92. *
  93. * It is purely a cosmetic feature.
  94. *
  95. * This option is dynamic (can be set before or after initialization).
  96. *
  97. * @property {string|Array<string>|null|undefined|function} [options.schema]
  98. * Forces change of the default database schema(s) for every fresh connection, i.e.
  99. * the library will execute `SET search_path TO schema_1, schema_2, ...` in the background
  100. * whenever a fresh physical connection is allocated.
  101. *
  102. * Normally, one changes the default schema(s) by $[changing the database or the role], but sometimes you
  103. * may want to switch the default schema(s) without persisting the change, and then use this option.
  104. *
  105. * It can be a string, an array of strings, or a callback function that takes `dc` (database context)
  106. * as the only parameter (and as `this`), and returns schema(s) according to the database context. A callback function
  107. * can also return nothing (`undefined` or `null`), if no schema change needed for the specified database context.
  108. *
  109. * The order of schema names matters, so if a table name exists in more than one schema, its default access resolves
  110. * to the table from the first such schema on the list.
  111. *
  112. * This option is dynamic (can be set before or after initialization).
  113. *
  114. * @property {boolean} [options.noWarnings=false]
  115. * Disables all diagnostic warnings in the library (it is ill-advised).
  116. *
  117. * This option is dynamic (can be set before or after initialization).
  118. *
  119. * @property {function} [options.connect]
  120. * Global event {@link event:connect connect} handler.
  121. *
  122. * This option is dynamic (can be set before or after initialization).
  123. *
  124. * @property {function} [options.disconnect]
  125. * Global event {@link event:disconnect disconnect} handler.
  126. *
  127. * This option is dynamic (can be set before or after initialization).
  128. *
  129. * @property {function} [options.query]
  130. * Global event {@link event:query query} handler.
  131. *
  132. * This option is dynamic (can be set before or after initialization).
  133. *
  134. * @property {function} [options.receive]
  135. * Global event {@link event:receive receive} handler.
  136. *
  137. * This option is dynamic (can be set before or after initialization).
  138. *
  139. * @property {function} [options.task]
  140. * Global event {@link event:task task} handler.
  141. *
  142. * This option is dynamic (can be set before or after initialization).
  143. *
  144. * @property {function} [options.transact]
  145. * Global event {@link event:transact transact} handler.
  146. *
  147. * This option is dynamic (can be set before or after initialization).
  148. *
  149. * @property {function} [options.error]
  150. * Global event {@link event:error error} handler.
  151. *
  152. * This option is dynamic (can be set before or after initialization).
  153. *
  154. * @property {function} [options.extend]
  155. * Global event {@link event:extend extend} handler.
  156. *
  157. * This option is dynamic (can be set before or after initialization).
  158. *
  159. * @see
  160. * {@link module:pg-promise~end end},
  161. * {@link module:pg-promise~as as},
  162. * {@link module:pg-promise~errors errors},
  163. * {@link module:pg-promise~helpers helpers},
  164. * {@link module:pg-promise~minify minify},
  165. * {@link module:pg-promise~ParameterizedQuery ParameterizedQuery},
  166. * {@link module:pg-promise~PreparedStatement PreparedStatement},
  167. * {@link module:pg-promise~pg pg},
  168. * {@link module:pg-promise~QueryFile QueryFile},
  169. * {@link module:pg-promise~queryResult queryResult},
  170. * {@link module:pg-promise~spex spex},
  171. * {@link module:pg-promise~txMode txMode},
  172. * {@link module:pg-promise~utils utils}
  173. *
  174. */
  175. function $main(options) {
  176. options = assert(options, ['pgFormatting', 'pgNative', 'promiseLib', 'capSQL', 'noWarnings',
  177. 'connect', 'disconnect', 'query', 'receive', 'task', 'transact', 'error', 'extend', 'schema']);
  178. let pg = npm.pg;
  179. const p = parsePromise(options.promiseLib);
  180. const config = {
  181. version: npm.package.version,
  182. promiseLib: p.promiseLib,
  183. promise: p.promise
  184. };
  185. npm.utils.addReadProp(config, '$npm', {}, true);
  186. // Locking properties that cannot be changed later:
  187. npm.utils.addReadProp(options, 'promiseLib', options.promiseLib);
  188. npm.utils.addReadProp(options, 'pgNative', !!options.pgNative);
  189. config.options = options;
  190. // istanbul ignore next:
  191. // we do not cover code specific to Native Bindings
  192. if (options.pgNative) {
  193. pg = npm.pg.native;
  194. if (npm.utils.isNull(pg)) {
  195. throw new Error(npm.text.nativeError);
  196. }
  197. } else {
  198. if (!originalClientConnect) {
  199. originalClientConnect = pg.Client.prototype.connect;
  200. pg.Client.prototype.connect = function () {
  201. const handler = msg => {
  202. if (msg.parameterName === 'server_version') {
  203. this.serverVersion = msg.parameterValue;
  204. this.connection.removeListener('parameterStatus', handler);
  205. }
  206. };
  207. this.connection.on('parameterStatus', handler);
  208. return originalClientConnect.call(this, ...arguments);
  209. };
  210. }
  211. }
  212. const Database = require('./database')(config);
  213. const inst = (cn, dc) => {
  214. if (npm.utils.isText(cn) || (cn && typeof cn === 'object')) {
  215. return new Database(cn, dc, config);
  216. }
  217. throw new TypeError('Invalid connection details: ' + npm.utils.toJson(cn));
  218. };
  219. npm.utils.addReadProperties(inst, rootNameSpace);
  220. /**
  221. * @member {external:PG} pg
  222. * @description
  223. * Instance of the $[pg] library that's being used, depending on initialization option `pgNative`:
  224. * - regular `pg` module instance, without option `pgNative`, or equal to `false` (default)
  225. * - `pg` module instance with $[Native Bindings], if option `pgNative` was set.
  226. *
  227. * Available as `pgp.pg`, after initializing the library.
  228. */
  229. inst.pg = pg; // keep it modifiable, so the protocol can be mocked
  230. /**
  231. * @member {function} end
  232. * @readonly
  233. * @description
  234. * Shuts down all connection pools created in the process, so it can terminate without delay.
  235. * It is available as `pgp.end`, after initializing the library.
  236. *
  237. * All {@link Database} objects created previously can no longer be used, and their query methods will be rejecting
  238. * with {@link external:Error Error} = `Connection pool of the database object has been destroyed.`
  239. *
  240. * And if you want to shut down only a specific connection pool, you do so via the {@link Database}
  241. * object that owns the pool: `db.$pool.end()` (see {@link Database#$pool Database.$pool}).
  242. *
  243. * For more details see $[Library de-initialization].
  244. */
  245. npm.utils.addReadProp(inst, 'end', () => {
  246. DatabasePool.shutDown();
  247. });
  248. /**
  249. * @member {helpers} helpers
  250. * @readonly
  251. * @description
  252. * Namespace for {@link helpers all query-formatting helper functions}.
  253. *
  254. * Available as `pgp.helpers`, after initializing the library.
  255. *
  256. * @see {@link helpers}.
  257. */
  258. npm.utils.addReadProp(inst, 'helpers', npm.helpers(config));
  259. /**
  260. * @member {external:spex} spex
  261. * @readonly
  262. * @description
  263. * Initialized instance of the $[spex] module, used by the library within tasks and transactions.
  264. *
  265. * Available as `pgp.spex`, after initializing the library.
  266. *
  267. * @see
  268. * {@link Task#batch},
  269. * {@link Task#page},
  270. * {@link Task#sequence}
  271. */
  272. npm.utils.addReadProp(inst, 'spex', config.$npm.spex);
  273. config.pgp = inst;
  274. return inst;
  275. }
  276. const rootNameSpace = {
  277. /**
  278. * @member {formatting} as
  279. * @readonly
  280. * @description
  281. * Namespace for {@link formatting all query-formatting functions}.
  282. *
  283. * Available as `pgp.as`, before and after initializing the library.
  284. *
  285. * @see {@link formatting}.
  286. */
  287. as: npm.formatting.as,
  288. /**
  289. * @member {external:pg-minify} minify
  290. * @readonly
  291. * @description
  292. * Instance of the $[pg-minify] library used internally to minify SQL scripts.
  293. *
  294. * Available as `pgp.minify`, before and after initializing the library.
  295. */
  296. minify: npm.minify,
  297. /**
  298. * @member {queryResult} queryResult
  299. * @readonly
  300. * @description
  301. * Query Result Mask enumerator.
  302. *
  303. * Available as `pgp.queryResult`, before and after initializing the library.
  304. */
  305. queryResult,
  306. /**
  307. * @member {PromiseAdapter} PromiseAdapter
  308. * @readonly
  309. * @description
  310. * {@link PromiseAdapter} class.
  311. *
  312. * Available as `pgp.PromiseAdapter`, before and after initializing the library.
  313. */
  314. PromiseAdapter,
  315. /**
  316. * @member {ParameterizedQuery} ParameterizedQuery
  317. * @readonly
  318. * @description
  319. * {@link ParameterizedQuery} class.
  320. *
  321. * Available as `pgp.ParameterizedQuery`, before and after initializing the library.
  322. */
  323. ParameterizedQuery,
  324. /**
  325. * @member {PreparedStatement} PreparedStatement
  326. * @readonly
  327. * @description
  328. * {@link PreparedStatement} class.
  329. *
  330. * Available as `pgp.PreparedStatement`, before and after initializing the library.
  331. */
  332. PreparedStatement,
  333. /**
  334. * @member {QueryFile} QueryFile
  335. * @readonly
  336. * @description
  337. * {@link QueryFile} class.
  338. *
  339. * Available as `pgp.QueryFile`, before and after initializing the library.
  340. */
  341. QueryFile,
  342. /**
  343. * @member {errors} errors
  344. * @readonly
  345. * @description
  346. * {@link errors} - namespace for all error types.
  347. *
  348. * Available as `pgp.errors`, before and after initializing the library.
  349. */
  350. errors: npm.errors,
  351. /**
  352. * @member {utils} utils
  353. * @readonly
  354. * @description
  355. * {@link utils} - namespace for utility functions.
  356. *
  357. * Available as `pgp.utils`, before and after initializing the library.
  358. */
  359. utils: npm.pubUtils,
  360. /**
  361. * @member {txMode} txMode
  362. * @readonly
  363. * @description
  364. * {@link txMode Transaction Mode} namespace.
  365. *
  366. * Available as `pgp.txMode`, before and after initializing the library.
  367. */
  368. txMode: npm.mode
  369. };
  370. npm.utils.addReadProperties($main, rootNameSpace);
  371. module.exports = $main;
  372. /**
  373. * @external Promise
  374. * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
  375. */
  376. /**
  377. * @external PG
  378. * @see https://node-postgres.com
  379. */
  380. /**
  381. * @external Client
  382. * @see https://node-postgres.com/api/client
  383. */
  384. /**
  385. * @external pg-minify
  386. * @see https://github.com/vitaly-t/pg-minify
  387. */
  388. /**
  389. * @external spex
  390. * @see https://github.com/vitaly-t/spex
  391. */