database.js 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683
  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 {Events} = require('./events');
  10. const {assert} = require('./assert');
  11. const {resultQuery, multiResultQuery, streamQuery} = require('./special-query');
  12. const {ConnectionContext} = require('./context');
  13. const {DatabasePool} = require('./database-pool');
  14. const {queryResult} = require('./query-result');
  15. const npm = {
  16. utils: require('./utils'),
  17. pubUtils: require('./utils/public'),
  18. connect: require('./connect'),
  19. query: require('./query'),
  20. task: require('./task'),
  21. text: require('./text')
  22. };
  23. /**
  24. * @class Database
  25. * @description
  26. *
  27. * Represents the database protocol, extensible via event {@link event:extend extend}.
  28. * This type is not available directly, it can only be created via the library's base call.
  29. *
  30. * **IMPORTANT:**
  31. *
  32. * For any given connection, you should only create a single {@link Database} object in a separate module,
  33. * to be shared in your application (see the code example below). If instead you keep creating the {@link Database}
  34. * object dynamically, your application will suffer from loss in performance, and will be getting a warning in a
  35. * development environment (when `NODE_ENV` = `development`):
  36. *
  37. * `WARNING: Creating a duplicate database object for the same connection.`
  38. *
  39. * If you ever see this warning, rectify your {@link Database} object initialization, so there is only one object
  40. * per connection details. See the example provided below.
  41. *
  42. * See also: property `noWarnings` in {@link module:pg-promise Initialization Options}.
  43. *
  44. * Note however, that in special cases you may need to re-create the database object, if its connection pool has been
  45. * shut-down externally. And in this case the library won't be showing any warning.
  46. *
  47. * @param {string|object} cn
  48. * Database connection details, which can be:
  49. *
  50. * - a configuration object
  51. * - a connection string
  52. *
  53. * For details see {@link https://github.com/vitaly-t/pg-promise/wiki/Connection-Syntax Connection Syntax}.
  54. *
  55. * The value can be accessed from the database object via property {@link Database.$cn $cn}.
  56. *
  57. * @param {*} [dc]
  58. * Database Context.
  59. *
  60. * Any object or value to be propagated through the protocol, to allow implementations and event handling
  61. * that depend on the database context.
  62. *
  63. * This is mainly to facilitate the use of multiple databases which may need separate protocol extensions,
  64. * or different implementations within a single task / transaction callback, depending on the database context.
  65. *
  66. * This parameter also adds uniqueness to the connection context that's used in combination with the connection
  67. * parameters, i.e. use of unique database context will prevent getting the warning about creating a duplicate
  68. * Database object.
  69. *
  70. * The value can be accessed from the database object via property {@link Database#$dc $dc}.
  71. *
  72. * @returns {Database}
  73. *
  74. * @see
  75. *
  76. * {@link Database#query query},
  77. * {@link Database#none none},
  78. * {@link Database#one one},
  79. * {@link Database#oneOrNone oneOrNone},
  80. * {@link Database#many many},
  81. * {@link Database#manyOrNone manyOrNone},
  82. * {@link Database#any any},
  83. * {@link Database#func func},
  84. * {@link Database#proc proc},
  85. * {@link Database#result result},
  86. * {@link Database#multiResult multiResult},
  87. * {@link Database#multi multi},
  88. * {@link Database#map map},
  89. * {@link Database#each each},
  90. * {@link Database#stream stream},
  91. * {@link Database#task task},
  92. * {@link Database#taskIf taskIf},
  93. * {@link Database#tx tx},
  94. * {@link Database#txIf txIf},
  95. * {@link Database#connect connect},
  96. * {@link Database#$config $config},
  97. * {@link Database#$cn $cn},
  98. * {@link Database#$dc $dc},
  99. * {@link Database#$pool $pool},
  100. * {@link event:extend extend}
  101. *
  102. * @example
  103. * // Proper way to initialize and share the Database object
  104. *
  105. * // Loading and initializing the library:
  106. * const pgp = require('pg-promise')({
  107. * // Initialization Options
  108. * });
  109. *
  110. * // Preparing the connection details:
  111. * const cn = 'postgres://username:password@host:port/database';
  112. *
  113. * // Creating a new database instance from the connection details:
  114. * const db = pgp(cn);
  115. *
  116. * // Exporting the database object for shared use:
  117. * module.exports = db;
  118. */
  119. function Database(cn, dc, config) {
  120. const dbThis = this,
  121. $p = config.promise,
  122. poolConnection = typeof cn === 'string' ? {connectionString: cn} : cn,
  123. pool = new config.pgp.pg.Pool(poolConnection),
  124. endMethod = pool.end;
  125. let destroyed;
  126. pool.end = cb => {
  127. const res = endMethod.call(pool, cb);
  128. dbThis.$destroy();
  129. return res;
  130. };
  131. pool.on('error', onError);
  132. /**
  133. * @method Database#connect
  134. *
  135. * @description
  136. * Acquires a new or existing connection, depending on the current state of the connection pool, and parameter `direct`.
  137. *
  138. * This method creates a shared connection for executing a chain of queries against it. The connection must be released
  139. * in the end of the chain by calling `done()` on the connection object.
  140. *
  141. * Method `done` takes one optional parameter - boolean `kill` flag, to signal the connection pool that you want it to kill
  142. * the physical connection. This flag is ignored for direct connections, as they always close when released.
  143. *
  144. * It should not be used just for chaining queries on the same connection, methods {@link Database#task task} and
  145. * {@link Database#tx tx} (for transactions) are to be used for that. This method is primarily for special cases, like
  146. * `LISTEN` notifications.
  147. *
  148. * **NOTE:** Even though this method exposes a {@link external:Client Client} object via property `client`,
  149. * you cannot call `client.end()` directly, or it will print an error into the console:
  150. * `Abnormal client.end() call, due to invalid code or failed server connection.`
  151. * You should only call method `done()` to release the connection.
  152. *
  153. * @param {object} [options]
  154. * Connection Options.
  155. *
  156. * @param {boolean} [options.direct=false]
  157. * Creates a new connection directly, as a stand-alone {@link external:Client Client} object, bypassing the connection pool.
  158. *
  159. * By default, all connections are acquired from the connection pool. But if you set this option, the library will instead
  160. * create a new {@link external:Client Client} object directly (separately from the pool), and then call its `connect` method.
  161. *
  162. * Note that specifically for direct connections, method `done` returns a {@link external:Promise Promise}, because those connections
  163. * are closed physically, which may take time.
  164. *
  165. * **WARNING:**
  166. *
  167. * Do not use this option for regular query execution, because it exclusively occupies one physical channel, and it cannot scale.
  168. * This option is only suitable for global connection usage, such as event listeners.
  169. *
  170. * @param {function} [options.onLost]
  171. * Notification callback of the lost/broken connection, called with the following parameters:
  172. * - `err` - the original connectivity error
  173. * - `e` - error context object, which contains:
  174. * - `cn` - safe connection string/config (with the password hashed);
  175. * - `dc` - Database Context, as was used during {@link Database} construction;
  176. * - `start` - Date/Time (`Date` type) when the connection was established;
  177. * - `client` - {@link external:Client Client} object that has lost the connection.
  178. *
  179. * The notification is mostly valuable with `direct: true`, to be able to re-connect direct/permanent connections by calling
  180. * method {@link Database#connect connect} again.
  181. *
  182. * You do not need to call `done` on lost connections, as it happens automatically. However, if you had event listeners
  183. * set up on the connection's `client` object, you should remove them to avoid leaks:
  184. *
  185. * ```js
  186. * function onLostConnection(err, e) {
  187. * e.client.removeListener('my-event', myHandler);
  188. * }
  189. * ```
  190. *
  191. * For a complete example see $[Robust Listeners].
  192. *
  193. * @returns {external:Promise}
  194. * A promise object that represents the connection result:
  195. * - resolves with the complete {@link Database} protocol, extended with:
  196. * - property `client` of type {@link external:Client Client} that represents the open connection
  197. * - method `done` that must be called in the end, in order to release the connection (returns a {@link external:Promise Promise}
  198. * in case of direct connections)
  199. * - methods `batch`, `page` and `sequence`, same as inside a {@link Task}
  200. * - rejects with a connection-related error when it fails to connect.
  201. *
  202. * @see
  203. * {@link Database#task Database.task},
  204. * {@link Database#taskIf Database.taskIf},
  205. * {@link Database#tx Database.tx},
  206. * {@link Database#txIf Database.txIf}
  207. *
  208. * @example
  209. *
  210. * let sco; // shared connection object;
  211. *
  212. * db.connect()
  213. * .then(obj => {
  214. * // obj.client = new connected Client object;
  215. *
  216. * sco = obj; // save the connection object;
  217. *
  218. * // execute all the queries you need:
  219. * return sco.any('SELECT * FROM Users');
  220. * })
  221. * .then(data => {
  222. * // success
  223. * })
  224. * .catch(error => {
  225. * // error
  226. * })
  227. * .finally(() => {
  228. * // release the connection, if it was successful:
  229. * if (sco) {
  230. * // if you pass `true` into method done, i.e. done(true),
  231. * // it will make the pool kill the physical connection.
  232. * sco.done();
  233. * }
  234. * });
  235. *
  236. */
  237. this.connect = function (options) {
  238. options = options || {};
  239. const ctx = createContext();
  240. ctx.cnOptions = options;
  241. const self = {
  242. query(query, values, qrm) {
  243. if (!ctx.db) {
  244. return $p.reject(new Error(npm.text.queryDisconnected));
  245. }
  246. return config.$npm.query.call(this, ctx, query, values, qrm);
  247. },
  248. done(kill) {
  249. if (!ctx.db) {
  250. throw new Error(npm.text.looseQuery);
  251. }
  252. return ctx.disconnect(kill);
  253. },
  254. batch(values, opt) {
  255. return config.$npm.spex.batch.call(this, values, opt);
  256. },
  257. page(source, opt) {
  258. return config.$npm.spex.page.call(this, source, opt);
  259. },
  260. sequence(source, opt) {
  261. return config.$npm.spex.sequence.call(this, source, opt);
  262. }
  263. };
  264. const connection = options.direct ? config.$npm.connect.direct(ctx) : config.$npm.connect.pool(ctx, dbThis);
  265. return connection
  266. .then(db => {
  267. ctx.connect(db);
  268. self.client = db.client;
  269. extend(ctx, self);
  270. return self;
  271. });
  272. };
  273. /**
  274. * @method Database#query
  275. *
  276. * @description
  277. * Base query method that executes a generic query, expecting the return data according to parameter `qrm`.
  278. *
  279. * It performs the following steps:
  280. *
  281. * 1. Validates and formats the query via {@link formatting.format as.format}, according to the `query` and `values` passed in;
  282. * 2. For a root-level query (against the {@link Database} object), it requests a new connection from the pool;
  283. * 3. Executes the query;
  284. * 4. For a root-level query (against the {@link Database} object), it releases the connection back to the pool;
  285. * 5. Resolves/rejects, according to the data returned from the query and the value of `qrm`.
  286. *
  287. * Direct use of this method is not suitable for chaining queries, for performance reasons. It should be done
  288. * through either task or transaction context, see $[Chaining Queries].
  289. *
  290. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  291. *
  292. * @param {string|function|object} query
  293. * Query to be executed, which can be any of the following types:
  294. * - A non-empty query string
  295. * - A function that returns a query string or another function, i.e. recursive resolution
  296. * is supported, passing in `values` as `this`, and as the first parameter.
  297. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  298. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  299. * - {@link QueryFile} object
  300. *
  301. * @param {array|value|function} [values]
  302. * Query formatting parameter(s), or a function that returns it.
  303. *
  304. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  305. * - a single value - to replace all `$1` occurrences
  306. * - an array of values - to replace all `$1`, `$2`, ... variables
  307. * - an object - to apply $[Named Parameters] formatting
  308. *
  309. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  310. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  311. * as an override for its internal `values`.
  312. *
  313. * @param {queryResult} [qrm=queryResult.any]
  314. * {@link queryResult Query Result Mask}
  315. *
  316. * @returns {external:Promise}
  317. * A promise object that represents the query result according to `qrm`.
  318. */
  319. this.query = function (query, values, qrm) {
  320. const self = this, ctx = createContext();
  321. return config.$npm.connect.pool(ctx, dbThis)
  322. .then(db => {
  323. ctx.connect(db);
  324. return config.$npm.query.call(self, ctx, query, values, qrm);
  325. })
  326. .then(data => {
  327. ctx.disconnect();
  328. return data;
  329. })
  330. .catch(error => {
  331. ctx.disconnect();
  332. return $p.reject(error);
  333. });
  334. };
  335. /**
  336. * @member {object} Database#$config
  337. * @readonly
  338. * @description
  339. * This is a hidden property, to help integrating type {@link Database} directly with third-party libraries.
  340. *
  341. * Properties available in the object:
  342. * - `pgp` - instance of the entire library after initialization
  343. * - `options` - the library's {@link module:pg-promise Initialization Options} object
  344. * - `promiseLib` - instance of the promise library that's used
  345. * - `promise` - generic promise interface that uses `promiseLib` via 4 basic methods:
  346. * - `promise((resolve, reject) => {})` - to create a new promise
  347. * - `promise.resolve(value)` - to resolve with a value
  348. * - `promise.reject(reason)` - to reject with a reason
  349. * - `promise.all(iterable)` - to resolve an iterable list of promises
  350. * - `version` - this library's version
  351. * - `$npm` _(hidden property)_ - internal module cache
  352. *
  353. * @example
  354. *
  355. * // Using the promise protocol as configured by pg-promise:
  356. *
  357. * const $p = db.$config.promise;
  358. *
  359. * const resolvedPromise = $p.resolve('some data');
  360. * const rejectedPromise = $p.reject('some reason');
  361. *
  362. * const newPromise = $p((resolve, reject) => {
  363. * // call either resolve(data) or reject(reason) here
  364. * });
  365. */
  366. npm.utils.addReadProp(this, '$config', config, true);
  367. /**
  368. * @member {string|object} Database#$cn
  369. * @readonly
  370. * @description
  371. * Database connection, as was passed in during the object's construction.
  372. *
  373. * This is a hidden property, to help integrating type {@link Database} directly with third-party libraries.
  374. *
  375. * @see Database
  376. */
  377. npm.utils.addReadProp(this, '$cn', cn, true);
  378. /**
  379. * @member {*} Database#$dc
  380. * @readonly
  381. * @description
  382. * Database Context, as was passed in during the object's construction.
  383. *
  384. * This is a hidden property, to help integrating type {@link Database} directly with third-party libraries.
  385. *
  386. * @see Database
  387. */
  388. npm.utils.addReadProp(this, '$dc', dc, true);
  389. /**
  390. * @member {external:pg-pool} Database#$pool
  391. * @readonly
  392. * @description
  393. * A $[pg-pool] object associated with the database object, as each {@link Database} creates its own $[pg-pool] instance.
  394. *
  395. * This is a hidden property, primarily for integrating type {@link Database} with third-party libraries that support
  396. * $[pg-pool] directly. Note however, that if you pass the pool object into a library that calls `pool.end()`, you will no longer be able
  397. * to use this {@link Database} object, and each query method will be rejecting with {@link external:Error Error} =
  398. * `Connection pool of the database object has been destroyed.`
  399. *
  400. * You can also use this object to shut down the pool, by calling `$pool.end()`.
  401. *
  402. * For more details see $[Library de-initialization].
  403. *
  404. * @see
  405. * {@link Database}
  406. * {@link module:pg-promise~end pgp.end}
  407. *
  408. * @example
  409. *
  410. * // Shutting down the connection pool of this database object,
  411. * // after all queries have finished in a run-though process:
  412. *
  413. * .then(() => {}) // processing the data
  414. * .catch() => {}) // handling the error
  415. * .finally(db.$pool.end); // shutting down the pool
  416. *
  417. */
  418. npm.utils.addReadProp(this, '$pool', pool, true);
  419. /**
  420. * @member {function} Database.$destroy
  421. * @readonly
  422. * @private
  423. * @description
  424. * Permanently shuts down the database object.
  425. */
  426. npm.utils.addReadProp(this, '$destroy', () => {
  427. if (!destroyed) {
  428. if (!pool.ending) {
  429. endMethod.call(pool);
  430. }
  431. DatabasePool.unregister(dbThis);
  432. pool.removeListener('error', onError);
  433. destroyed = true;
  434. }
  435. }, true);
  436. DatabasePool.register(this);
  437. extend(createContext(), this); // extending root protocol;
  438. function createContext() {
  439. return new ConnectionContext({cn, dc, options: config.options});
  440. }
  441. // Optional value-transformation helper:
  442. function transform(value, cb, thisArg) {
  443. return typeof cb === 'function' ? value.then(data => cb.call(thisArg, data)) : value;
  444. }
  445. ////////////////////////////////////////////////////
  446. // Injects additional methods into an access object,
  447. // extending the protocol's base method 'query'.
  448. function extend(ctx, obj) {
  449. /**
  450. * @method Database#none
  451. * @description
  452. * Executes a query that expects no data to be returned. If the query returns any data,
  453. * the method rejects.
  454. *
  455. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  456. *
  457. * @param {string|function|object} query
  458. * Query to be executed, which can be any of the following types:
  459. * - A non-empty query string
  460. * - A function that returns a query string or another function, i.e. recursive resolution
  461. * is supported, passing in `values` as `this`, and as the first parameter.
  462. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  463. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  464. * - {@link QueryFile} object
  465. *
  466. * @param {array|value|function} [values]
  467. * Query formatting parameter(s), or a function that returns it.
  468. *
  469. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  470. * - a single value - to replace all `$1` occurrences
  471. * - an array of values - to replace all `$1`, `$2`, ... variables
  472. * - an object - to apply $[Named Parameters] formatting
  473. *
  474. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  475. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  476. * as an override for its internal `values`.
  477. *
  478. * @returns {external:Promise<null>}
  479. * A promise object that represents the query result:
  480. * - When no records are returned, it resolves with `null`.
  481. * - When any data is returned, it rejects with {@link errors.QueryResultError QueryResultError}:
  482. * - `.message` = `No return data was expected.`
  483. * - `.code` = {@link errors.queryResultErrorCode.notEmpty queryResultErrorCode.notEmpty}
  484. */
  485. obj.none = function (query, values) {
  486. return obj.query.call(this, query, values, queryResult.none);
  487. };
  488. /**
  489. * @method Database#one
  490. * @description
  491. * Executes a query that expects exactly 1 row to be returned. When 0 or more than 1 rows are returned,
  492. * the method rejects.
  493. *
  494. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  495. *
  496. * @param {string|function|object} query
  497. * Query to be executed, which can be any of the following types:
  498. * - A non-empty query string
  499. * - A function that returns a query string or another function, i.e. recursive resolution
  500. * is supported, passing in `values` as `this`, and as the first parameter.
  501. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  502. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  503. * - {@link QueryFile} object
  504. *
  505. * @param {array|value|function} [values]
  506. * Query formatting parameter(s), or a function that returns it.
  507. *
  508. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  509. * - a single value - to replace all `$1` occurrences
  510. * - an array of values - to replace all `$1`, `$2`, ... variables
  511. * - an object - to apply $[Named Parameters] formatting
  512. *
  513. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  514. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  515. * as an override for its internal `values`.
  516. *
  517. * @param {function} [cb]
  518. * Value-transformation callback, to allow in-line value change.
  519. * When specified, the returned value replaces the original one.
  520. *
  521. * The function takes only one parameter - value resolved from the query.
  522. *
  523. * @param {*} [thisArg]
  524. * Value to use as `this` when executing the transformation callback.
  525. *
  526. * @returns {external:Promise}
  527. * A promise object that represents the query result:
  528. * - When 1 row is returned, it resolves with that row as a single object.
  529. * - When no rows are returned, it rejects with {@link errors.QueryResultError QueryResultError}:
  530. * - `.message` = `No data returned from the query.`
  531. * - `.code` = {@link errors.queryResultErrorCode.noData queryResultErrorCode.noData}
  532. * - When multiple rows are returned, it rejects with {@link errors.QueryResultError QueryResultError}:
  533. * - `.message` = `Multiple rows were not expected.`
  534. * - `.code` = {@link errors.queryResultErrorCode.multiple queryResultErrorCode.multiple}
  535. * - Resolves with the new value, if transformation callback `cb` was specified.
  536. *
  537. * @see
  538. * {@link Database#oneOrNone oneOrNone}
  539. *
  540. * @example
  541. *
  542. * // a query with in-line value transformation:
  543. * db.one('INSERT INTO Events VALUES($1) RETURNING id', [123], event => event.id)
  544. * .then(data => {
  545. * // data = a new event id, rather than an object with it
  546. * });
  547. *
  548. * @example
  549. *
  550. * // a query with in-line value transformation + conversion:
  551. * db.one('SELECT count(*) FROM Users', [], c => +c.count)
  552. * .then(count => {
  553. * // count = a proper integer value, rather than an object with a string
  554. * });
  555. *
  556. */
  557. obj.one = function (query, values, cb, thisArg) {
  558. const v = obj.query.call(this, query, values, queryResult.one);
  559. return transform(v, cb, thisArg);
  560. };
  561. /**
  562. * @method Database#many
  563. * @description
  564. * Executes a query that expects one or more rows to be returned. When the query returns no rows, the method rejects.
  565. *
  566. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  567. *
  568. * @param {string|function|object} query
  569. * Query to be executed, which can be any of the following types:
  570. * - A non-empty query string
  571. * - A function that returns a query string or another function, i.e. recursive resolution
  572. * is supported, passing in `values` as `this`, and as the first parameter.
  573. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  574. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  575. * - {@link QueryFile} object
  576. *
  577. * @param {array|value|function} [values]
  578. * Query formatting parameter(s), or a function that returns it.
  579. *
  580. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  581. * - a single value - to replace all `$1` occurrences
  582. * - an array of values - to replace all `$1`, `$2`, ... variables
  583. * - an object - to apply $[Named Parameters] formatting
  584. *
  585. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  586. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  587. * as an override for its internal `values`.
  588. *
  589. * @returns {external:Promise}
  590. * A promise object that represents the query result:
  591. * - When 1 or more rows are returned, it resolves with the array of rows.
  592. * - When no rows are returned, it rejects with {@link errors.QueryResultError QueryResultError}:
  593. * - `.message` = `No data returned from the query.`
  594. * - `.code` = {@link errors.queryResultErrorCode.noData queryResultErrorCode.noData}
  595. */
  596. obj.many = function (query, values) {
  597. return obj.query.call(this, query, values, queryResult.many);
  598. };
  599. /**
  600. * @method Database#oneOrNone
  601. * @description
  602. * Executes a query that expects 0 or 1 rows to be returned. It resolves with the row-object when 1 row is returned,
  603. * or with `null` when nothing is returned. When the query returns more than 1 row, the method rejects.
  604. *
  605. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  606. *
  607. * @param {string|function|object} query
  608. * Query to be executed, which can be any of the following types:
  609. * - A non-empty query string
  610. * - A function that returns a query string or another function, i.e. recursive resolution
  611. * is supported, passing in `values` as `this`, and as the first parameter.
  612. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  613. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  614. * - {@link QueryFile} object
  615. *
  616. * @param {array|value|function} [values]
  617. * Query formatting parameter(s), or a function that returns it.
  618. *
  619. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  620. * - a single value - to replace all `$1` occurrences
  621. * - an array of values - to replace all `$1`, `$2`, ... variables
  622. * - an object - to apply $[Named Parameters] formatting
  623. *
  624. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  625. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  626. * as an override for its internal `values`.
  627. *
  628. * @param {function} [cb]
  629. * Value-transformation callback, to allow in-line value change.
  630. * When specified, the returned value replaces the original one.
  631. *
  632. * The function takes only one parameter - value resolved from the query.
  633. *
  634. * @param {*} [thisArg]
  635. * Value to use as `this` when executing the transformation callback.
  636. *
  637. * @returns {external:Promise}
  638. * A promise object that represents the query result:
  639. * - When no rows are returned, it resolves with `null`.
  640. * - When 1 row is returned, it resolves with that row as a single object.
  641. * - When multiple rows are returned, it rejects with {@link errors.QueryResultError QueryResultError}:
  642. * - `.message` = `Multiple rows were not expected.`
  643. * - `.code` = {@link errors.queryResultErrorCode.multiple queryResultErrorCode.multiple}
  644. * - Resolves with the new value, if transformation callback `cb` was specified.
  645. *
  646. * @see
  647. * {@link Database#one one},
  648. * {@link Database#none none},
  649. * {@link Database#manyOrNone manyOrNone}
  650. *
  651. * @example
  652. *
  653. * // a query with in-line value transformation:
  654. * db.oneOrNone('SELECT id FROM Events WHERE type = $1', ['entry'], e => e && e.id)
  655. * .then(data => {
  656. * // data = the event id or null (rather than object or null)
  657. * });
  658. *
  659. */
  660. obj.oneOrNone = function (query, values, cb, thisArg) {
  661. const v = obj.query.call(this, query, values, queryResult.one | queryResult.none);
  662. return transform(v, cb, thisArg);
  663. };
  664. /**
  665. * @method Database#manyOrNone
  666. * @description
  667. * Executes a query that can return any number of rows.
  668. *
  669. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  670. *
  671. * @param {string|function|object} query
  672. * Query to be executed, which can be any of the following types:
  673. * - A non-empty query string
  674. * - A function that returns a query string or another function, i.e. recursive resolution
  675. * is supported, passing in `values` as `this`, and as the first parameter.
  676. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  677. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  678. * - {@link QueryFile} object
  679. *
  680. * @param {array|value|function} [values]
  681. * Query formatting parameter(s), or a function that returns it.
  682. *
  683. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  684. * - a single value - to replace all `$1` occurrences
  685. * - an array of values - to replace all `$1`, `$2`, ... variables
  686. * - an object - to apply $[Named Parameters] formatting
  687. *
  688. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  689. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  690. * as an override for its internal `values`.
  691. *
  692. * @returns {external:Promise<Array>}
  693. * A promise object that represents the query result:
  694. * - When no rows are returned, it resolves with an empty array.
  695. * - When 1 or more rows are returned, it resolves with the array of rows.
  696. *
  697. * @see
  698. * {@link Database#any any},
  699. * {@link Database#many many},
  700. * {@link Database#none none}
  701. *
  702. */
  703. obj.manyOrNone = function (query, values) {
  704. return obj.query.call(this, query, values, queryResult.many | queryResult.none);
  705. };
  706. /**
  707. * @method Database#any
  708. * @description
  709. * Executes a query that can return any number of rows.
  710. * This is simply a shorter alias for method {@link Database#manyOrNone manyOrNone}.
  711. *
  712. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  713. *
  714. * @param {string|function|object} query
  715. * Query to be executed, which can be any of the following types:
  716. * - A non-empty query string
  717. * - A function that returns a query string or another function, i.e. recursive resolution
  718. * is supported, passing in `values` as `this`, and as the first parameter.
  719. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  720. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  721. * - {@link QueryFile} object
  722. *
  723. * @param {array|value|function} [values]
  724. * Query formatting parameter(s), or a function that returns it.
  725. *
  726. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  727. * - a single value - to replace all `$1` occurrences
  728. * - an array of values - to replace all `$1`, `$2`, ... variables
  729. * - an object - to apply $[Named Parameters] formatting
  730. *
  731. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  732. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  733. * as an override for its internal `values`.
  734. *
  735. * @returns {external:Promise<Array>}
  736. * A promise object that represents the query result:
  737. * - When no rows are returned, it resolves with an empty array.
  738. * - When 1 or more rows are returned, it resolves with the array of rows.
  739. *
  740. * @see
  741. * {@link Database#manyOrNone manyOrNone},
  742. * {@link Database#map map},
  743. * {@link Database#each each}
  744. *
  745. */
  746. obj.any = function (query, values) {
  747. return obj.query.call(this, query, values, queryResult.any);
  748. };
  749. /**
  750. * @method Database#result
  751. * @description
  752. * Executes a query without any expectation for the return data, and resolves with the
  753. * original $[Result] object when successful.
  754. *
  755. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  756. *
  757. * @param {string|function|object} query
  758. * Query to be executed, which can be any of the following types:
  759. * - A non-empty query string
  760. * - A function that returns a query string or another function, i.e. recursive resolution
  761. * is supported, passing in `values` as `this`, and as the first parameter.
  762. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  763. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  764. * - {@link QueryFile} object
  765. *
  766. * @param {array|value|function} [values]
  767. * Query formatting parameter(s), or a function that returns it.
  768. *
  769. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  770. * - a single value - to replace all `$1` occurrences
  771. * - an array of values - to replace all `$1`, `$2`, ... variables
  772. * - an object - to apply $[Named Parameters] formatting
  773. *
  774. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  775. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  776. * as an override for its internal `values`.
  777. *
  778. * @param {function} [cb]
  779. * Value-transformation callback, to allow in-line value change.
  780. * When specified, the returned value replaces the original one.
  781. *
  782. * The function takes only one parameter - value resolved from the query.
  783. *
  784. * @param {*} [thisArg]
  785. * Value to use as `this` when executing the transformation callback.
  786. *
  787. * @returns {external:Promise}
  788. * A promise object that represents the query result:
  789. * - resolves with the original $[Result] object (by default);
  790. * - resolves with the new value, if transformation callback `cb` was specified.
  791. *
  792. * @example
  793. *
  794. * // use of value transformation:
  795. * // deleting rows and returning the number of rows deleted
  796. * db.result('DELETE FROM Events WHERE id = $1', [123], r => r.rowCount)
  797. * .then(data => {
  798. * // data = number of rows that were deleted
  799. * });
  800. *
  801. * @example
  802. *
  803. * // use of value transformation:
  804. * // getting only column details from a table
  805. * db.result('SELECT * FROM Users LIMIT 0', null, r => r.fields)
  806. * .then(data => {
  807. * // data = array of column descriptors
  808. * });
  809. *
  810. */
  811. obj.result = function (query, values, cb, thisArg) {
  812. const v = obj.query.call(this, query, values, resultQuery);
  813. return transform(v, cb, thisArg);
  814. };
  815. /**
  816. * @method Database#multiResult
  817. * @description
  818. * Executes a multi-query string, without any expectation for the return data, and resolves with an array
  819. * of the original $[Result] objects when successful.
  820. *
  821. * The operation is atomic, i.e. all queries are executed in a single transaction, unless there are explicit
  822. * `BEGIN/COMMIT` commands included in the query string to divide it into multiple transactions.
  823. *
  824. * @param {string|function|object} query
  825. * Multi-query string to be executed, which can be any of the following types:
  826. * - A non-empty string that can contain any number of queries
  827. * - A function that returns a query string or another function, i.e. recursive resolution
  828. * is supported, passing in `values` as `this`, and as the first parameter.
  829. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  830. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  831. * - {@link QueryFile} object
  832. *
  833. * @param {array|value|function} [values]
  834. * Query formatting parameter(s), or a function that returns it.
  835. *
  836. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  837. * - a single value - to replace all `$1` occurrences
  838. * - an array of values - to replace all `$1`, `$2`, ... variables
  839. * - an object - to apply $[Named Parameters] formatting
  840. *
  841. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  842. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  843. * as an override for its internal `values`.
  844. *
  845. * @returns {external:Promise<external:Result[]>}
  846. *
  847. * @see {@link Database#multi multi}
  848. *
  849. */
  850. obj.multiResult = function (query, values) {
  851. return obj.query.call(this, query, values, multiResultQuery);
  852. };
  853. /**
  854. * @method Database#multi
  855. * @description
  856. * Executes a multi-query string, without any expectation for the return data, and resolves with an array
  857. * of arrays of rows when successful.
  858. *
  859. * The operation is atomic, i.e. all queries are executed in a single transaction, unless there are explicit
  860. * `BEGIN/COMMIT` commands included in the query string to divide it into multiple transactions.
  861. *
  862. * @param {string|function|object} query
  863. * Multi-query string to be executed, which can be any of the following types:
  864. * - A non-empty string that can contain any number of queries
  865. * - A function that returns a query string or another function, i.e. recursive resolution
  866. * is supported, passing in `values` as `this`, and as the first parameter.
  867. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  868. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  869. * - {@link QueryFile} object
  870. *
  871. * @param {array|value|function} [values]
  872. * Query formatting parameter(s), or a function that returns it.
  873. *
  874. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  875. * - a single value - to replace all `$1` occurrences
  876. * - an array of values - to replace all `$1`, `$2`, ... variables
  877. * - an object - to apply $[Named Parameters] formatting
  878. *
  879. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  880. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  881. * as an override for its internal `values`.
  882. *
  883. * @returns {external:Promise<Array<Array>>}
  884. *
  885. * @see {@link Database#multiResult multiResult}
  886. *
  887. * @example
  888. *
  889. * // Get data from 2 tables in a single request:
  890. * const [users, products] = await db.multi('SELECT * FROM users;SELECT * FROM products');
  891. *
  892. */
  893. obj.multi = function (query, values) {
  894. return obj.query.call(this, query, values, multiResultQuery)
  895. .then(data => data.map(a => a.rows));
  896. };
  897. /**
  898. * @method Database#stream
  899. * @description
  900. * Custom data streaming, with the help of $[pg-query-stream].
  901. *
  902. * This method doesn't work with the $[Native Bindings], and if option `pgNative`
  903. * is set, it will reject with `Streaming doesn't work with Native Bindings.`
  904. *
  905. * @param {QueryStream} qs
  906. * Stream object of type $[QueryStream].
  907. *
  908. * @param {Database.streamInitCB} initCB
  909. * Stream initialization callback.
  910. *
  911. * It is invoked with the same `this` context as the calling method.
  912. *
  913. * @returns {external:Promise}
  914. * Result of the streaming operation.
  915. *
  916. * Once the streaming has finished successfully, the method resolves with
  917. * `{processed, duration}`:
  918. * - `processed` - total number of rows processed;
  919. * - `duration` - streaming duration, in milliseconds.
  920. *
  921. * Possible rejections messages:
  922. * - `Invalid or missing stream object.`
  923. * - `Invalid stream state.`
  924. * - `Invalid or missing stream initialization callback.`
  925. */
  926. obj.stream = function (qs, init) {
  927. return obj.query.call(this, qs, init, streamQuery);
  928. };
  929. /**
  930. * @method Database#func
  931. * @description
  932. * Executes a database function that returns a table, abbreviating the full syntax
  933. * of `query('SELECT * FROM $1:alias($2:csv)', [funcName, values], qrm)`.
  934. *
  935. * @param {string} funcName
  936. * Name of the function to be executed.
  937. * When it is not same-case, or contains extended symbols, it is double-quoted, as per the `:alias` filter,
  938. * which also supports `.`, to auto-split into a composite name.
  939. *
  940. * @param {array|value|function} [values]
  941. * Parameters for the function - one value | array of values | function returning value(s).
  942. *
  943. * @param {queryResult} [qrm=queryResult.any] - {@link queryResult Query Result Mask}.
  944. *
  945. * @returns {external:Promise}
  946. *
  947. * A promise object as returned from method {@link Database#query query}, according to parameter `qrm`.
  948. *
  949. * @see
  950. * {@link Database#query query},
  951. * {@link Database#proc proc}
  952. */
  953. obj.func = function (funcName, values, qrm) {
  954. return obj.query.call(this, {entity: funcName, type: 'func'}, values, qrm);
  955. };
  956. /**
  957. * @method Database#proc
  958. * @description
  959. * Executes a stored procedure by name, abbreviating the full syntax of
  960. * `oneOrNone('CALL $1:alias($2:csv)', [procName, values], cb, thisArg)`.
  961. *
  962. * **NOTE:** This method uses the new `CALL` syntax that requires PostgreSQL v11 or later.
  963. *
  964. * @param {string} procName
  965. * Name of the stored procedure to be executed.
  966. * When it is not same-case, or contains extended symbols, it is double-quoted, as per the `:alias` filter,
  967. * which also supports `.`, to auto-split into a composite SQL name.
  968. *
  969. * @param {array|value|function} [values]
  970. * Parameters for the procedure - one value | array of values | function returning value(s).
  971. *
  972. * @param {function} [cb]
  973. * Value-transformation callback, to allow in-line value change.
  974. * When specified, the returned value replaces the original one.
  975. *
  976. * The function takes only one parameter - value resolved from the query.
  977. *
  978. * @param {*} [thisArg]
  979. * Value to use as `this` when executing the transformation callback.
  980. *
  981. * @returns {external:Promise}
  982. * When the procedure takes output parameters, a single object is returned, with
  983. * properties for the output values. Otherwise, the method resolves with `null`.
  984. * And if the value-transformation callback is provided, it overrides the result.
  985. *
  986. * @see
  987. * {@link Database#func func}
  988. */
  989. obj.proc = function (procName, values, cb, thisArg) {
  990. const v = obj.query.call(this, {
  991. entity: procName,
  992. type: 'proc'
  993. }, values, queryResult.one | queryResult.none);
  994. return transform(v, cb, thisArg);
  995. };
  996. /**
  997. * @method Database#map
  998. * @description
  999. * Creates a new array with the results of calling a provided function on every element in the array of rows
  1000. * resolved by method {@link Database#any any}.
  1001. *
  1002. * It is a convenience method, to reduce the following code:
  1003. *
  1004. * ```js
  1005. * db.any(query, values)
  1006. * .then(data => {
  1007. * return data.map((row, index, data) => {
  1008. * // return a new element
  1009. * });
  1010. * });
  1011. * ```
  1012. *
  1013. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  1014. *
  1015. * @param {string|function|object} query
  1016. * Query to be executed, which can be any of the following types:
  1017. * - A non-empty query string
  1018. * - A function that returns a query string or another function, i.e. recursive resolution
  1019. * is supported, passing in `values` as `this`, and as the first parameter.
  1020. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  1021. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  1022. * - {@link QueryFile} object
  1023. *
  1024. * @param {array|value|function} values
  1025. * Query formatting parameter(s), or a function that returns it.
  1026. *
  1027. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  1028. * - a single value - to replace all `$1` occurrences
  1029. * - an array of values - to replace all `$1`, `$2`, ... variables
  1030. * - an object - to apply $[Named Parameters] formatting
  1031. *
  1032. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  1033. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  1034. * as an override for its internal `values`.
  1035. *
  1036. * @param {function} cb
  1037. * Function that produces an element of the new array, taking three arguments:
  1038. * - `row` - the current row object being processed in the array
  1039. * - `index` - the index of the current row being processed in the array
  1040. * - `data` - the original array of rows resolved by method {@link Database#any any}
  1041. *
  1042. * @param {*} [thisArg]
  1043. * Value to use as `this` when executing the callback.
  1044. *
  1045. * @returns {external:Promise<Array>}
  1046. * Resolves with the new array of values returned from the callback.
  1047. *
  1048. * @see
  1049. * {@link Database#any any},
  1050. * {@link Database#each each},
  1051. * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map Array.map}
  1052. *
  1053. * @example
  1054. *
  1055. * db.map('SELECT id FROM Users WHERE status = $1', ['active'], row => row.id)
  1056. * .then(data => {
  1057. * // data = array of active user id-s
  1058. * })
  1059. * .catch(error => {
  1060. * // error
  1061. * });
  1062. *
  1063. * @example
  1064. *
  1065. * db.tx(t => {
  1066. * return t.map('SELECT id FROM Users WHERE status = $1', ['active'], row => {
  1067. * return t.none('UPDATE Events SET checked = $1 WHERE userId = $2', [true, row.id]);
  1068. * }).then(t.batch);
  1069. * })
  1070. * .then(data => {
  1071. * // success
  1072. * })
  1073. * .catch(error => {
  1074. * // error
  1075. * });
  1076. *
  1077. * @example
  1078. *
  1079. * // Build a list of active users, each with the list of user events:
  1080. * db.task(t => {
  1081. * return t.map('SELECT id FROM Users WHERE status = $1', ['active'], user => {
  1082. * return t.any('SELECT * FROM Events WHERE userId = $1', user.id)
  1083. * .then(events=> {
  1084. * user.events = events;
  1085. * return user;
  1086. * });
  1087. * }).then(t.batch);
  1088. * })
  1089. * .then(data => {
  1090. * // success
  1091. * })
  1092. * .catch(error => {
  1093. * // error
  1094. * });
  1095. *
  1096. */
  1097. obj.map = function (query, values, cb, thisArg) {
  1098. return obj.any.call(this, query, values)
  1099. .then(data => data.map(cb, thisArg));
  1100. };
  1101. /**
  1102. * @method Database#each
  1103. * @description
  1104. * Executes a provided function once per array element, for an array of rows resolved by method {@link Database#any any}.
  1105. *
  1106. * It is a convenience method to reduce the following code:
  1107. *
  1108. * ```js
  1109. * db.any(query, values)
  1110. * .then(data => {
  1111. * data.forEach((row, index, data) => {
  1112. * // process the row
  1113. * });
  1114. * return data;
  1115. * });
  1116. * ```
  1117. *
  1118. * When receiving a multi-query result, only the last result is processed, ignoring the rest.
  1119. *
  1120. * @param {string|function|object} query
  1121. * Query to be executed, which can be any of the following types:
  1122. * - A non-empty query string
  1123. * - A function that returns a query string or another function, i.e. recursive resolution
  1124. * is supported, passing in `values` as `this`, and as the first parameter.
  1125. * - Prepared Statement `{name, text, values, ...}` or {@link PreparedStatement} object
  1126. * - Parameterized Query `{text, values, ...}` or {@link ParameterizedQuery} object
  1127. * - {@link QueryFile} object
  1128. *
  1129. * @param {array|value|function} [values]
  1130. * Query formatting parameter(s), or a function that returns it.
  1131. *
  1132. * When `query` is of type `string` or a {@link QueryFile} object, the `values` can be:
  1133. * - a single value - to replace all `$1` occurrences
  1134. * - an array of values - to replace all `$1`, `$2`, ... variables
  1135. * - an object - to apply $[Named Parameters] formatting
  1136. *
  1137. * When `query` is a Prepared Statement or a Parameterized Query (or their class types),
  1138. * and `values` is not `null` or `undefined`, it is automatically set within such object,
  1139. * as an override for its internal `values`.
  1140. *
  1141. * @param {function} cb
  1142. * Function to execute for each row, taking three arguments:
  1143. * - `row` - the current row object being processed in the array
  1144. * - `index` - the index of the current row being processed in the array
  1145. * - `data` - the array of rows resolved by method {@link Database#any any}
  1146. *
  1147. * @param {*} [thisArg]
  1148. * Value to use as `this` when executing the callback.
  1149. *
  1150. * @returns {external:Promise<Array<Object>>}
  1151. * Resolves with the original array of rows.
  1152. *
  1153. * @see
  1154. * {@link Database#any any},
  1155. * {@link Database#map map},
  1156. * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach Array.forEach}
  1157. *
  1158. * @example
  1159. *
  1160. * db.each('SELECT id, code, name FROM Events', [], row => {
  1161. * row.code = parseInt(row.code);
  1162. * })
  1163. * .then(data => {
  1164. * // data = array of events, with 'code' converted into integer
  1165. * })
  1166. * .catch(error => {
  1167. * // error
  1168. * });
  1169. *
  1170. */
  1171. obj.each = function (query, values, cb, thisArg) {
  1172. return obj.any.call(this, query, values)
  1173. .then(data => {
  1174. data.forEach(cb, thisArg);
  1175. return data;
  1176. });
  1177. };
  1178. /**
  1179. * @method Database#task
  1180. * @description
  1181. * Executes a callback function with automatically managed connection.
  1182. *
  1183. * When invoked on the root {@link Database} object, the method allocates the connection from the pool,
  1184. * executes the callback, and once finished - releases the connection back to the pool.
  1185. * However, when invoked inside another task or transaction, the method reuses the parent connection.
  1186. *
  1187. * This method should be used whenever executing more than one query at once, so the allocated connection
  1188. * is reused between all queries, and released only after the task has finished (see $[Chaining Queries]).
  1189. *
  1190. * The callback function is called with one parameter - database protocol (same as `this`), extended with methods
  1191. * {@link Task#batch batch}, {@link Task#page page}, {@link Task#sequence sequence}, plus property {@link Task#ctx ctx} -
  1192. * the task context object. See class {@link Task} for more details.
  1193. *
  1194. * @param {string|number|Object} [options]
  1195. * This parameter is optional, and presumed skipped when the first parameter is a function (`cb` parameter).
  1196. *
  1197. * When it is of type `string` or `number`, it is assumed to be option `tag` passed in directly. Otherwise,
  1198. * it is expected to be an object with options as listed below.
  1199. *
  1200. * @param {} [options.tag]
  1201. * Traceable context for the task (see $[tags]).
  1202. *
  1203. * @param {function} cb
  1204. * Task callback function, to return the result that will determine either success or failure for the operation.
  1205. *
  1206. * The function can be either the first of the second parameter passed into the method.
  1207. *
  1208. * It also can be an ES7 `async` function.
  1209. *
  1210. * @returns {external:Promise}
  1211. * A promise object with the result from the callback function.
  1212. *
  1213. * @see
  1214. * {@link Task},
  1215. * {@link Database#taskIf taskIf},
  1216. * {@link Database#tx tx},
  1217. * $[tags],
  1218. * $[Chaining Queries]
  1219. *
  1220. * @example
  1221. *
  1222. * db.task('my-task', t => {
  1223. * // t.ctx = task context object
  1224. *
  1225. * return t.one('SELECT id FROM Users WHERE name = $1', 'John')
  1226. * .then(user => {
  1227. * return t.any('SELECT * FROM Events WHERE userId = $1', user.id);
  1228. * });
  1229. * })
  1230. * .then(data => {
  1231. * // success
  1232. * // data = as returned from the task's callback
  1233. * })
  1234. * .catch(error => {
  1235. * // error
  1236. * });
  1237. *
  1238. * @example
  1239. *
  1240. * // using an ES7 syntax for the callback:
  1241. * db.task('my-task', async t {
  1242. * // t.ctx = task context object
  1243. *
  1244. * const user = await t.one('SELECT id FROM Users WHERE name = $1', 'John');
  1245. * return t.any('SELECT * FROM Events WHERE userId = $1', user.id);
  1246. * })
  1247. * .then(data => {
  1248. * // success
  1249. * // data = as returned from the task's callback
  1250. * })
  1251. * .catch(error => {
  1252. * // error
  1253. * });
  1254. *
  1255. */
  1256. obj.task = function () {
  1257. const args = npm.pubUtils.taskArgs(arguments);
  1258. assert(args.options, ['tag']);
  1259. return taskProcessor.call(this, args, false);
  1260. };
  1261. /**
  1262. * @method Database#taskIf
  1263. * @description
  1264. * Executes a conditional task that results in an actual new {@link Database#task task}, if either condition is met or
  1265. * when it is necessary (on the top level), or else it reuses the current connection context.
  1266. *
  1267. * The default condition is `not in task or transaction`, to start a task only if currently not inside another task or transaction,
  1268. * which is the same as calling the following:
  1269. *
  1270. * ```js
  1271. * db.taskIf({cnd: t => !t.ctx}, cb => {})
  1272. * ```
  1273. *
  1274. * It can be useful, if you want to simplify/reduce the task + log events footprint, by creating new tasks only when necessary.
  1275. *
  1276. * @param {string|number|Object} [options]
  1277. * This parameter is optional, and presumed skipped when the first parameter is a function (`cb` parameter).
  1278. *
  1279. * When it is of type `string` or `number`, it is assumed to be option `tag` passed in directly. Otherwise,
  1280. * it is expected to be an object with options as listed below.
  1281. *
  1282. * @param {} [options.tag]
  1283. * Traceable context for the task/transaction (see $[tags]).
  1284. *
  1285. * @param {boolean|function} [options.cnd]
  1286. * Condition for creating a ({@link Database#task task}), if it is met.
  1287. * It can be either a simple boolean, or a callback function that takes the task context as `this` and as the first parameter.
  1288. *
  1289. * Default condition (when it is not specified):
  1290. *
  1291. * ```js
  1292. * {cnd: t => !t.ctx}
  1293. * ```
  1294. *
  1295. * @param {function} cb
  1296. * Task callback function, to return the result that will determine either success or failure for the operation.
  1297. *
  1298. * The function can be either the first or the second parameter passed into the method.
  1299. *
  1300. * It also can be an ES7 `async` function.
  1301. *
  1302. * @returns {external:Promise}
  1303. * A promise object with the result from the callback function.
  1304. *
  1305. * @see
  1306. * {@link Task},
  1307. * {@link Database#task Database.task},
  1308. * {@link Database#tx Database.tx},
  1309. * {@link Database#txIf Database.txIf},
  1310. * {@link TaskContext}
  1311. *
  1312. */
  1313. obj.taskIf = function () {
  1314. const args = npm.pubUtils.taskArgs(arguments);
  1315. assert(args.options, ['tag', 'cnd']);
  1316. try {
  1317. let cnd = args.options.cnd;
  1318. if ('cnd' in args.options) {
  1319. cnd = typeof cnd === 'function' ? cnd.call(obj, obj) : !!cnd;
  1320. } else {
  1321. cnd = !obj.ctx; // create task, if it is the top level
  1322. }
  1323. // reusable only if condition fails, and not top-level:
  1324. args.options.reusable = !cnd && !!obj.ctx;
  1325. } catch (e) {
  1326. return $p.reject(e);
  1327. }
  1328. return taskProcessor.call(this, args, false);
  1329. };
  1330. /**
  1331. * @method Database#tx
  1332. * @description
  1333. * Executes a callback function as a transaction, with automatically managed connection.
  1334. *
  1335. * When invoked on the root {@link Database} object, the method allocates the connection from the pool,
  1336. * executes the callback, and once finished - releases the connection back to the pool.
  1337. * However, when invoked inside another task or transaction, the method reuses the parent connection.
  1338. *
  1339. * A transaction wraps a regular {@link Database#task task} into additional queries:
  1340. * - it executes `BEGIN` just before invoking the callback function
  1341. * - it executes `COMMIT`, if the callback didn't throw any error or return a rejected promise
  1342. * - it executes `ROLLBACK`, if the callback did throw an error or return a rejected promise
  1343. * - it executes corresponding `SAVEPOINT` commands when the method is called recursively.
  1344. *
  1345. * The callback function is called with one parameter - database protocol (same as `this`), extended with methods
  1346. * {@link Task#batch batch}, {@link Task#page page}, {@link Task#sequence sequence}, plus property {@link Task#ctx ctx} -
  1347. * the transaction context object. See class {@link Task} for more details.
  1348. *
  1349. * Note that transactions should be chosen over tasks only where necessary, because unlike regular tasks,
  1350. * transactions are blocking operations.
  1351. *
  1352. * @param {string|number|Object} [options]
  1353. * This parameter is optional, and presumed skipped when the first parameter is a function (`cb` parameter).
  1354. *
  1355. * When it is of type `string` or `number`, it is assumed to be option `tag` passed in directly. Otherwise,
  1356. * it is expected to be an object with options as listed below.
  1357. *
  1358. * @param {} [options.tag]
  1359. * Traceable context for the transaction (see $[tags]).
  1360. *
  1361. * @param {txMode.TransactionMode} [options.mode]
  1362. * Transaction Configuration Mode - extends the transaction-opening command with additional configuration.
  1363. *
  1364. * @param {function} cb
  1365. * Transaction callback function, to return the result that will determine either success or failure for the operation.
  1366. *
  1367. * The function can be either the first of the second parameter passed into the method.
  1368. *
  1369. * It also can be an ES7 `async` function.
  1370. *
  1371. * @returns {external:Promise}
  1372. * A promise object with the result from the callback function.
  1373. *
  1374. * @see
  1375. * {@link Task},
  1376. * {@link Database#task Database.task},
  1377. * {@link Database#taskIf Database.taskIf},
  1378. * {@link TaskContext},
  1379. * $[tags],
  1380. * $[Chaining Queries]
  1381. *
  1382. * @example
  1383. *
  1384. * db.tx('my-transaction', t => {
  1385. * // t.ctx = transaction context object
  1386. *
  1387. * return t.one('INSERT INTO Users(name, age) VALUES($1, $2) RETURNING id', ['Mike', 25])
  1388. * .then(user => {
  1389. * return t.batch([
  1390. * t.none('INSERT INTO Events(userId, name) VALUES($1, $2)', [user.id, 'created']),
  1391. * t.none('INSERT INTO Events(userId, name) VALUES($1, $2)', [user.id, 'login'])
  1392. * ]);
  1393. * });
  1394. * })
  1395. * .then(data => {
  1396. * // success
  1397. * // data = as returned from the transaction's callback
  1398. * })
  1399. * .catch(error => {
  1400. * // error
  1401. * });
  1402. *
  1403. * @example
  1404. *
  1405. * // using an ES7 syntax for the callback:
  1406. * db.tx('my-transaction', async t {
  1407. * // t.ctx = transaction context object
  1408. *
  1409. * const user = await t.one('INSERT INTO Users(name, age) VALUES($1, $2) RETURNING id', ['Mike', 25]);
  1410. * return t.none('INSERT INTO Events(userId, name) VALUES($1, $2)', [user.id, 'created']);
  1411. * })
  1412. * .then(data => {
  1413. * // success
  1414. * // data = as returned from the transaction's callback
  1415. * })
  1416. * .catch(error => {
  1417. * // error
  1418. * });
  1419. *
  1420. */
  1421. obj.tx = function () {
  1422. const args = npm.pubUtils.taskArgs(arguments);
  1423. assert(args.options, ['tag', 'mode']);
  1424. return taskProcessor.call(this, args, true);
  1425. };
  1426. /**
  1427. * @method Database#txIf
  1428. * @description
  1429. * Executes a conditional transaction that results in an actual transaction ({@link Database#tx tx}), if the condition is met,
  1430. * or else it executes a regular {@link Database#task task}.
  1431. *
  1432. * The default condition is `not in transaction`, to start a transaction only if currently not in transaction,
  1433. * or else start a task, which is the same as calling the following:
  1434. *
  1435. * ```js
  1436. * db.txIf({cnd: t => !t.ctx || !t.ctx.inTransaction}, cb => {})
  1437. * ```
  1438. *
  1439. * It is useful when you want to avoid $[Nested Transactions] - savepoints.
  1440. *
  1441. * @param {string|number|Object} [options]
  1442. * This parameter is optional, and presumed skipped when the first parameter is a function (`cb` parameter).
  1443. *
  1444. * When it is of type `string` or `number`, it is assumed to be option `tag` passed in directly. Otherwise,
  1445. * it is expected to be an object with options as listed below.
  1446. *
  1447. * @param {} [options.tag]
  1448. * Traceable context for the task/transaction (see $[tags]).
  1449. *
  1450. * @param {txMode.TransactionMode} [options.mode]
  1451. * Transaction Configuration Mode - extends the transaction-opening command with additional configuration.
  1452. *
  1453. * @param {boolean|function} [options.cnd]
  1454. * Condition for opening a transaction ({@link Database#tx tx}), if it is met, or a {@link Database#task task} when the condition is not met.
  1455. * It can be either a simple boolean, or a callback function that takes the task/tx context as `this` and as the first parameter.
  1456. *
  1457. * Default condition (when it is not specified):
  1458. *
  1459. * ```js
  1460. * {cnd: t => !t.ctx || !t.ctx.inTransaction}
  1461. * ```
  1462. *
  1463. * @param {boolean|function} [options.reusable=false]
  1464. * When `cnd` is/returns false, reuse context of the current task/transaction, if one exists.
  1465. * It can be either a simple boolean, or a callback function that takes the task/tx context as `this`
  1466. * and as the first parameter.
  1467. *
  1468. * By default, when `cnd` is/returns false, the method creates a new task. This option tells
  1469. * the method to reuse the current task/transaction context, and not create a new task.
  1470. *
  1471. * This option is ignored when executing against the top level of the protocol, because on
  1472. * that level, if no transaction is suddenly needed, a new task becomes necessary.
  1473. *
  1474. * @param {function} cb
  1475. * Transaction/task callback function, to return the result that will determine either
  1476. * success or failure for the operation.
  1477. *
  1478. * The function can be either the first or the second parameter passed into the method.
  1479. *
  1480. * It also can be an ES7 `async` function.
  1481. *
  1482. * @returns {external:Promise}
  1483. * A promise object with the result from the callback function.
  1484. *
  1485. * @see
  1486. * {@link Task},
  1487. * {@link Database#task Database.task},
  1488. * {@link Database#taskIf Database.taskIf},
  1489. * {@link Database#tx Database.tx},
  1490. * {@link TaskContext}
  1491. */
  1492. obj.txIf = function () {
  1493. const args = npm.pubUtils.taskArgs(arguments);
  1494. assert(args.options, ['tag', 'mode', 'cnd', 'reusable']);
  1495. try {
  1496. let cnd;
  1497. if ('cnd' in args.options) {
  1498. cnd = args.options.cnd;
  1499. cnd = typeof cnd === 'function' ? cnd.call(obj, obj) : !!cnd;
  1500. } else {
  1501. cnd = !obj.ctx || !obj.ctx.inTransaction;
  1502. }
  1503. args.options.cnd = cnd;
  1504. const reusable = args.options.reusable;
  1505. args.options.reusable = !cnd && obj.ctx && typeof reusable === 'function' ? reusable.call(obj, obj) : !!reusable;
  1506. } catch (e) {
  1507. return $p.reject(e);
  1508. }
  1509. return taskProcessor.call(this, args, args.options.cnd);
  1510. };
  1511. // Task method;
  1512. // Resolves with result from the callback function;
  1513. function taskProcessor(params, isTX) {
  1514. if (typeof params.cb !== 'function') {
  1515. return $p.reject(new TypeError('Callback function is required.'));
  1516. }
  1517. if (params.options.reusable) {
  1518. return config.$npm.task.callback(obj.ctx, obj, params.cb, config);
  1519. }
  1520. const taskCtx = ctx.clone(); // task context object;
  1521. if (isTX) {
  1522. taskCtx.txLevel = taskCtx.txLevel >= 0 ? (taskCtx.txLevel + 1) : 0;
  1523. }
  1524. taskCtx.inTransaction = taskCtx.txLevel >= 0;
  1525. taskCtx.level = taskCtx.level >= 0 ? (taskCtx.level + 1) : 0;
  1526. taskCtx.cb = params.cb; // callback function;
  1527. taskCtx.mode = params.options.mode; // transaction mode;
  1528. if (this !== obj) {
  1529. taskCtx.context = this; // calling context object;
  1530. }
  1531. const tsk = new config.$npm.task.Task(taskCtx, params.options.tag, isTX, config);
  1532. taskCtx.taskCtx = tsk.ctx;
  1533. extend(taskCtx, tsk);
  1534. if (taskCtx.db) {
  1535. // reuse existing connection;
  1536. npm.utils.addReadProp(tsk.ctx, 'useCount', taskCtx.db.useCount);
  1537. addServerVersion(tsk.ctx, taskCtx.db.client);
  1538. return config.$npm.task.execute(taskCtx, tsk, isTX, config);
  1539. }
  1540. // connection required;
  1541. return config.$npm.connect.pool(taskCtx, dbThis)
  1542. .then(db => {
  1543. taskCtx.connect(db);
  1544. npm.utils.addReadProp(tsk.ctx, 'useCount', db.useCount);
  1545. addServerVersion(tsk.ctx, db.client);
  1546. return config.$npm.task.execute(taskCtx, tsk, isTX, config);
  1547. })
  1548. .then(data => {
  1549. taskCtx.disconnect();
  1550. return data;
  1551. })
  1552. .catch(error => {
  1553. taskCtx.disconnect();
  1554. return $p.reject(error);
  1555. });
  1556. }
  1557. function addServerVersion(target, client) {
  1558. // Exclude else-case from coverage, because it can only occur with Native Bindings.
  1559. // istanbul ignore else
  1560. if (client.serverVersion) {
  1561. npm.utils.addReadProp(target, 'serverVersion', client.serverVersion);
  1562. }
  1563. }
  1564. // extending the protocol;
  1565. Events.extend(ctx.options, obj, ctx.dc);
  1566. }
  1567. }
  1568. // this event only happens when the connection is lost physically,
  1569. // which cannot be tested automatically; removing from coverage:
  1570. // istanbul ignore next
  1571. function onError(err) {
  1572. // this client was never seen by pg-promise, which
  1573. // can happen if it failed to initialize
  1574. if (!err.client.$ctx) {
  1575. return;
  1576. }
  1577. const ctx = err.client.$ctx;
  1578. Events.error(ctx.options, err, {
  1579. cn: npm.utils.getSafeConnection(ctx.cn),
  1580. dc: ctx.dc
  1581. });
  1582. }
  1583. module.exports = config => {
  1584. const npmLocal = config.$npm;
  1585. npmLocal.connect = npmLocal.connect || npm.connect(config);
  1586. npmLocal.query = npmLocal.query || npm.query(config);
  1587. npmLocal.task = npmLocal.task || npm.task(config);
  1588. return Database;
  1589. };
  1590. /**
  1591. * @callback Database.streamInitCB
  1592. * @description
  1593. * Stream initialization callback, used by {@link Database#stream Database.stream}.
  1594. *
  1595. * @param {external:Stream} stream
  1596. * Stream object to initialize streaming.
  1597. *
  1598. * @example
  1599. * const QueryStream = require('pg-query-stream');
  1600. * const JSONStream = require('JSONStream');
  1601. *
  1602. * // you can also use pgp.as.format(query, values, options)
  1603. * // to format queries properly, via pg-promise;
  1604. * const qs = new QueryStream('SELECT * FROM users');
  1605. *
  1606. * db.stream(qs, stream => {
  1607. * // initiate streaming into the console:
  1608. * stream.pipe(JSONStream.stringify()).pipe(process.stdout);
  1609. * })
  1610. * .then(data => {
  1611. * console.log('Total rows processed:', data.processed,
  1612. * 'Duration in milliseconds:', data.duration);
  1613. * })
  1614. * .catch(error => {
  1615. * // error;
  1616. * });
  1617. */
  1618. /**
  1619. * @external Stream
  1620. * @see https://nodejs.org/api/stream.html
  1621. */
  1622. /**
  1623. * @external pg-pool
  1624. * @alias pg-pool
  1625. * @see https://github.com/brianc/node-pg-pool
  1626. */
  1627. /**
  1628. * @external Result
  1629. * @see https://node-postgres.com/api/result
  1630. */