@depup/pg-promise 12.6.2-depup.0

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