@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,151 @@
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 {TableName} = require('../table-name');
11
+ const {ColumnSet} = require('../column-set');
12
+
13
+ const npm = {
14
+ formatting: require('../../formatting'),
15
+ utils: require('../../utils')
16
+ };
17
+
18
+ /**
19
+ * @method helpers.insert
20
+ * @description
21
+ * Generates an `INSERT` query for either one object or an array of objects.
22
+ *
23
+ * @param {object|object[]} data
24
+ * An insert object with properties for insert values, or an array of such objects.
25
+ *
26
+ * When `data` is not a non-null object and not an array, it will throw {@link external:TypeError TypeError} = `Invalid parameter 'data' specified.`
27
+ *
28
+ * When `data` is an empty array, it will throw {@link external:TypeError TypeError} = `Cannot generate an INSERT from an empty array.`
29
+ *
30
+ * When `data` is an array that contains a non-object value, the method will throw {@link external:Error Error} =
31
+ * `Invalid insert object at index N.`
32
+ *
33
+ * @param {array|helpers.Column|helpers.ColumnSet} [columns]
34
+ * Set of columns to be inserted.
35
+ *
36
+ * It is optional when `data` is a single object, and required when `data` is an array of objects. If not specified for an array
37
+ * of objects, the method will throw {@link external:TypeError TypeError} = `Parameter 'columns' is required when inserting multiple records.`
38
+ *
39
+ * When `columns` is not a {@link helpers.ColumnSet ColumnSet} object, a temporary {@link helpers.ColumnSet ColumnSet}
40
+ * is created - from the value of `columns` (if it was specified), or from the value of `data` (if it is not an array).
41
+ *
42
+ * When the final {@link helpers.ColumnSet ColumnSet} is empty (no columns in it), the method will throw
43
+ * {@link external:Error Error} = `Cannot generate an INSERT without any columns.`
44
+ *
45
+ * @param {helpers.TableName|Table|string} [table]
46
+ * Destination table.
47
+ *
48
+ * It is normally a required parameter. But when `columns` is passed in as a {@link helpers.ColumnSet ColumnSet} object
49
+ * with `table` set in it, that will be used when this parameter isn't specified. When neither is available, the method
50
+ * will throw {@link external:Error Error} = `Table name is unknown.`
51
+ *
52
+ * @returns {string}
53
+ * An `INSERT` query string.
54
+ *
55
+ * @see
56
+ * {@link helpers.Column Column},
57
+ * {@link helpers.ColumnSet ColumnSet},
58
+ * {@link helpers.TableName TableName}
59
+ *
60
+ * @example
61
+ *
62
+ * const pgp = require('pg-promise')({
63
+ * capSQL: true // if you want all generated SQL capitalized
64
+ * });
65
+ * const {insert} = pgp.helpers;
66
+ *
67
+ * const dataSingle = {val: 123, msg: 'hello'};
68
+ * const dataMulti = [{val: 123, msg: 'hello'}, {val: 456, msg: 'world!'}];
69
+ *
70
+ * // Column details can be taken from the data object:
71
+ *
72
+ * insert(dataSingle, null, 'my-table');
73
+ * //=> INSERT INTO "my-table"("val","msg") VALUES(123,'hello')
74
+ *
75
+ * @example
76
+ *
77
+ * // Column details are required for a multi-row `INSERT`:
78
+ * const {insert} = pgp.helpers;
79
+ *
80
+ * insert(dataMulti, ['val', 'msg'], 'my-table');
81
+ * //=> INSERT INTO "my-table"("val","msg") VALUES(123,'hello'),(456,'world!')
82
+ *
83
+ * @example
84
+ *
85
+ * // Column details from a reusable ColumnSet (recommended for performance):
86
+ * const {ColumnSet, insert} = pgp.helpers;
87
+ *
88
+ * const cs = new ColumnSet(['val', 'msg'], {table: 'my-table'});
89
+ *
90
+ * insert(dataMulti, cs);
91
+ * //=> INSERT INTO "my-table"("val","msg") VALUES(123,'hello'),(456,'world!')
92
+ *
93
+ */
94
+ function insert(data, columns, table, capSQL) {
95
+
96
+ if (!data || typeof data !== 'object') {
97
+ throw new TypeError('Invalid parameter \'data\' specified.');
98
+ }
99
+
100
+ const isArray = Array.isArray(data);
101
+
102
+ if (isArray && !data.length) {
103
+ throw new TypeError('Cannot generate an INSERT from an empty array.');
104
+ }
105
+
106
+ if (columns instanceof ColumnSet) {
107
+ if (npm.utils.isNull(table)) {
108
+ table = columns.table;
109
+ }
110
+ } else {
111
+ if (isArray && npm.utils.isNull(columns)) {
112
+ throw new TypeError('Parameter \'columns\' is required when inserting multiple records.');
113
+ }
114
+ columns = new ColumnSet(columns || data);
115
+ }
116
+
117
+ if (!columns.columns.length) {
118
+ throw new Error('Cannot generate an INSERT without any columns.');
119
+ }
120
+
121
+ if (!table) {
122
+ throw new Error('Table name is unknown.');
123
+ }
124
+
125
+ if (!(table instanceof TableName)) {
126
+ table = new TableName(table);
127
+ }
128
+
129
+ let query = capSQL ? sql.capCase : sql.lowCase;
130
+ const fmOptions = {capSQL};
131
+
132
+ const format = npm.formatting.as.format;
133
+ query = format(query, [table.name, columns.names], fmOptions);
134
+
135
+ if (isArray) {
136
+ return query + data.map((d, index) => {
137
+ if (!d || typeof d !== 'object') {
138
+ throw new Error(`Invalid insert object at index ${index}.`);
139
+ }
140
+ return '(' + format(columns.variables, columns.prepare(d), fmOptions) + ')';
141
+ }).join();
142
+ }
143
+ return query + '(' + format(columns.variables, columns.prepare(data), fmOptions) + ')';
144
+ }
145
+
146
+ const sql = {
147
+ lowCase: 'insert into $1^($2^) values',
148
+ capCase: 'INSERT INTO $1^($2^) VALUES'
149
+ };
150
+
151
+ module.exports = {insert};
@@ -0,0 +1,81 @@
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 {ColumnSet} = require('../column-set');
11
+
12
+ const npm = {
13
+ format: require('../../formatting').as.format,
14
+ utils: require('../../utils')
15
+ };
16
+
17
+ /**
18
+ * @method helpers.sets
19
+ * @description
20
+ * Generates a string of comma-separated value-set statements from a single object: `col1=val1, col2=val2, ...`,
21
+ * to be used as part of a query.
22
+ *
23
+ * Since it is to be used as part of `UPDATE` queries, {@link helpers.Column Column} properties `cnd` and `skip` apply.
24
+ *
25
+ * @param {object} data
26
+ * A simple, non-null and non-array source object.
27
+ *
28
+ * If it is anything else, the method will throw {@link external:TypeError TypeError} = `Invalid parameter 'data' specified.`
29
+ *
30
+ * @param {array|helpers.Column|helpers.ColumnSet} [columns]
31
+ * Columns for which to set values.
32
+ *
33
+ * When not specified, properties of the `data` object are used.
34
+ *
35
+ * When no effective columns are found, an empty string is returned.
36
+ *
37
+ * @returns {string}
38
+ * - comma-separated value-set statements for the `data` object
39
+ * - an empty string, if no effective columns found
40
+ *
41
+ * @see
42
+ * {@link helpers.Column Column},
43
+ * {@link helpers.ColumnSet ColumnSet}
44
+ *
45
+ * @example
46
+ *
47
+ * const pgp = require('pg-promise')();
48
+ *
49
+ * const data = {id: 1, val: 123, msg: 'hello'};
50
+ *
51
+ * // Properties can be pulled automatically from the object:
52
+ *
53
+ * pgp.helpers.sets(data);
54
+ * //=> "id"=1,"val"=123,"msg"='hello'
55
+ *
56
+ * @example
57
+ *
58
+ * // Column details from a reusable ColumnSet (recommended for performance);
59
+ * // NOTE: Conditional columns (start with '?') are skipped:
60
+ * const {ColumnSet, sets} = pgp.helpers;
61
+ *
62
+ * const cs = new ColumnSet(['?id','val', 'msg']);
63
+ *
64
+ * sets(data, cs);
65
+ * //=> "val"=123,"msg"='hello'
66
+ *
67
+ */
68
+ function sets(data, columns, capSQL) {
69
+
70
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
71
+ throw new TypeError('Invalid parameter \'data\' specified.');
72
+ }
73
+
74
+ if (!(columns instanceof ColumnSet)) {
75
+ columns = new ColumnSet(columns || data);
76
+ }
77
+
78
+ return npm.format(columns.assign({source: data}), columns.prepare(data), {capSQL});
79
+ }
80
+
81
+ module.exports = {sets};
@@ -0,0 +1,248 @@
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 {assert} = require('../../assert');
11
+ const {TableName} = require('../table-name');
12
+ const {ColumnSet} = require('../column-set');
13
+
14
+ const npm = {
15
+ formatting: require('../../formatting'),
16
+ utils: require('../../utils')
17
+ };
18
+
19
+ /**
20
+ * @method helpers.update
21
+ * @description
22
+ * Generates a simplified `UPDATE` query for either one object or an array of objects.
23
+ *
24
+ * The resulting query needs a `WHERE` clause to be appended to it, to specify the update logic.
25
+ * This is to allow for update conditions of any complexity that are easy to add.
26
+ *
27
+ * @param {object|object[]} data
28
+ * An update object with properties for update values, or an array of such objects.
29
+ *
30
+ * When `data` is not a non-null object and not an array, it will throw {@link external:TypeError TypeError} = `Invalid parameter 'data' specified.`
31
+ *
32
+ * When `data` is an empty array, it will throw {@link external:TypeError TypeError} = `Cannot generate an UPDATE from an empty array.`
33
+ *
34
+ * When `data` is an array that contains a non-object value, the method will throw {@link external:Error Error} =
35
+ * `Invalid update object at index N.`
36
+ *
37
+ * @param {array|helpers.Column|helpers.ColumnSet} [columns]
38
+ * Set of columns to be updated.
39
+ *
40
+ * It is optional when `data` is a single object, and required when `data` is an array of objects. If not specified for an array
41
+ * of objects, the method will throw {@link external:TypeError TypeError} = `Parameter 'columns' is required when updating multiple records.`
42
+ *
43
+ * When `columns` is not a {@link helpers.ColumnSet ColumnSet} object, a temporary {@link helpers.ColumnSet ColumnSet}
44
+ * is created - from the value of `columns` (if it was specified), or from the value of `data` (if it is not an array).
45
+ *
46
+ * When the final {@link helpers.ColumnSet ColumnSet} is empty (no columns in it), the method will throw
47
+ * {@link external:Error Error} = `Cannot generate an UPDATE without any columns.`, unless option `emptyUpdate` was specified.
48
+ *
49
+ * @param {helpers.TableName|Table|string} [table]
50
+ * Table to be updated.
51
+ *
52
+ * It is normally a required parameter. But when `columns` is passed in as a {@link helpers.ColumnSet ColumnSet} object
53
+ * with `table` set in it, that will be used when this parameter isn't specified. When neither is available, the method
54
+ * will throw {@link external:Error Error} = `Table name is unknown.`
55
+ *
56
+ * @param {{}} [options]
57
+ * An object with formatting options for multi-row `UPDATE` queries.
58
+ *
59
+ * @param {string} [options.tableAlias=t]
60
+ * Name of the SQL variable that represents the destination table.
61
+ *
62
+ * @param {string} [options.valueAlias=v]
63
+ * Name of the SQL variable that represents the values.
64
+ *
65
+ * @param {*} [options.emptyUpdate]
66
+ * This is a convenience option, to avoid throwing an error when generating a conditional update results in no columns.
67
+ *
68
+ * When present, regardless of the value, this option overrides the method's behavior when applying `skip` logic results in no columns,
69
+ * i.e. when every column is being skipped.
70
+ *
71
+ * By default, in that situation the method throws {@link external:Error Error} = `Cannot generate an UPDATE without any columns.`
72
+ * But when this option is present, the method will instead return whatever value the option was passed.
73
+ *
74
+ * @returns {*}
75
+ * An `UPDATE` query string that needs a `WHERE` condition appended.
76
+ *
77
+ * If it results in an empty update, and option `emptyUpdate` was passed in, then the method returns the value
78
+ * to which the option was set.
79
+ *
80
+ * @see
81
+ * {@link helpers.Column Column},
82
+ * {@link helpers.ColumnSet ColumnSet},
83
+ * {@link helpers.TableName TableName}
84
+ *
85
+ * @example
86
+ *
87
+ * const pgp = require('pg-promise')({
88
+ * capSQL: true // if you want all generated SQL capitalized
89
+ * });
90
+ * const {update} = pgp.helpers;
91
+ *
92
+ * const dataSingle = {id: 1, val: 123, msg: 'hello'};
93
+ * const dataMulti = [{id: 1, val: 123, msg: 'hello'}, {id: 2, val: 456, msg: 'world!'}];
94
+ *
95
+ * // Although column details can be taken from the data object, it is not
96
+ * // a likely scenario for an update, unless updating the whole table:
97
+ *
98
+ * update(dataSingle, null, 'my-table');
99
+ * //=> UPDATE "my-table" SET "id"=1,"val"=123,"msg"='hello'
100
+ *
101
+ * @example
102
+ *
103
+ * // A typical single-object update:
104
+ *
105
+ * // Dynamic conditions must be escaped/formatted properly:
106
+ * const condition = pgp.as.format(' WHERE id = ${id}', dataSingle);
107
+ *
108
+ * update(dataSingle, ['val', 'msg'], 'my-table') + condition;
109
+ * //=> UPDATE "my-table" SET "val"=123,"msg"='hello' WHERE id = 1
110
+ *
111
+ * @example
112
+ *
113
+ * // Column details are required for a multi-row `UPDATE`;
114
+ * // Adding '?' in front of a column name means it is only for a WHERE condition:
115
+ *
116
+ * update(dataMulti, ['?id', 'val', 'msg'], 'my-table') + ' WHERE v.id = t.id';
117
+ * //=> UPDATE "my-table" AS t SET "val"=v."val","msg"=v."msg" FROM (VALUES(1,123,'hello'),(2,456,'world!'))
118
+ * // AS v("id","val","msg") WHERE v.id = t.id
119
+ *
120
+ * @example
121
+ *
122
+ * // Column details from a reusable ColumnSet (recommended for performance):
123
+ * const {ColumnSet, update} = pgp.helpers;
124
+ *
125
+ * const cs = new ColumnSet(['?id', 'val', 'msg'], {table: 'my-table'});
126
+ *
127
+ * update(dataMulti, cs) + ' WHERE v.id = t.id';
128
+ * //=> UPDATE "my-table" AS t SET "val"=v."val","msg"=v."msg" FROM (VALUES(1,123,'hello'),(2,456,'world!'))
129
+ * // AS v("id","val","msg") WHERE v.id = t.id
130
+ *
131
+ * @example
132
+ *
133
+ * // Using parameter `options` to change the default alias names:
134
+ *
135
+ * update(dataMulti, cs, null, {tableAlias: 'X', valueAlias: 'Y'}) + ' WHERE Y.id = X.id';
136
+ * //=> UPDATE "my-table" AS X SET "val"=Y."val","msg"=Y."msg" FROM (VALUES(1,123,'hello'),(2,456,'world!'))
137
+ * // AS Y("id","val","msg") WHERE Y.id = X.id
138
+ *
139
+ * @example
140
+ *
141
+ * // Handling an empty update
142
+ * const {ColumnSet, update} = pgp.helpers;
143
+ *
144
+ * const cs = new ColumnSet(['?id', '?name'], {table: 'tt'}); // no actual update-able columns
145
+ * const result = update(dataMulti, cs, null, {emptyUpdate: 123});
146
+ * if(result === 123) {
147
+ * // We know the update is empty, i.e. no columns that can be updated;
148
+ * // And it didn't throw because we specified `emptyUpdate` option.
149
+ * }
150
+ */
151
+ function update(data, columns, table, options, capSQL) {
152
+
153
+ if (!data || typeof data !== 'object') {
154
+ throw new TypeError('Invalid parameter \'data\' specified.');
155
+ }
156
+
157
+ const isArray = Array.isArray(data);
158
+
159
+ if (isArray && !data.length) {
160
+ throw new TypeError('Cannot generate an UPDATE from an empty array.');
161
+ }
162
+
163
+ if (columns instanceof ColumnSet) {
164
+ if (npm.utils.isNull(table)) {
165
+ table = columns.table;
166
+ }
167
+ } else {
168
+ if (isArray && npm.utils.isNull(columns)) {
169
+ throw new TypeError('Parameter \'columns\' is required when updating multiple records.');
170
+ }
171
+ columns = new ColumnSet(columns || data);
172
+ }
173
+
174
+ options = assert(options, ['tableAlias', 'valueAlias', 'emptyUpdate']);
175
+
176
+ const format = npm.formatting.as.format,
177
+ useEmptyUpdate = 'emptyUpdate' in options,
178
+ fmOptions = {capSQL};
179
+
180
+ if (isArray) {
181
+ const tableAlias = npm.formatting.as.alias(npm.utils.isNull(options.tableAlias) ? 't' : options.tableAlias);
182
+ const valueAlias = npm.formatting.as.alias(npm.utils.isNull(options.valueAlias) ? 'v' : options.valueAlias);
183
+
184
+ const q = capSQL ? sql.multi.capCase : sql.multi.lowCase;
185
+
186
+ const actualColumns = columns.columns.filter(c => !c.cnd);
187
+
188
+ if (checkColumns(actualColumns)) {
189
+ return options.emptyUpdate;
190
+ }
191
+
192
+ checkTable();
193
+
194
+ const targetCols = actualColumns.map(c => c.escapedName + '=' + valueAlias + '.' + c.escapedName).join();
195
+
196
+ const values = data.map((d, index) => {
197
+ if (!d || typeof d !== 'object') {
198
+ throw new Error(`Invalid update object at index ${index}.`);
199
+ }
200
+ return '(' + format(columns.variables, columns.prepare(d), fmOptions) + ')';
201
+ }).join();
202
+
203
+ return format(q, [table.name, tableAlias, targetCols, values, valueAlias, columns.names], fmOptions);
204
+ }
205
+
206
+ const updates = columns.assign({source: data});
207
+
208
+ if (checkColumns(updates)) {
209
+ return options.emptyUpdate;
210
+ }
211
+
212
+ checkTable();
213
+
214
+ const query = capSQL ? sql.single.capCase : sql.single.lowCase;
215
+
216
+ return format(query, table.name) + format(updates, columns.prepare(data), fmOptions);
217
+
218
+ function checkTable() {
219
+ if (table && !(table instanceof TableName)) {
220
+ table = new TableName(table);
221
+ }
222
+ if (!table) {
223
+ throw new Error('Table name is unknown.');
224
+ }
225
+ }
226
+
227
+ function checkColumns(cols) {
228
+ if (!cols.length) {
229
+ if (useEmptyUpdate) {
230
+ return true;
231
+ }
232
+ throw new Error('Cannot generate an UPDATE without any columns.');
233
+ }
234
+ }
235
+ }
236
+
237
+ const sql = {
238
+ single: {
239
+ lowCase: 'update $1^ set ',
240
+ capCase: 'UPDATE $1^ SET '
241
+ },
242
+ multi: {
243
+ lowCase: 'update $1^ as $2^ set $3^ from (values$4^) as $5^($6^)',
244
+ capCase: 'UPDATE $1^ AS $2^ SET $3^ FROM (VALUES$4^) AS $5^($6^)'
245
+ }
246
+ };
247
+
248
+ module.exports = {update};
@@ -0,0 +1,116 @@
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 {ColumnSet} = require('../column-set');
11
+
12
+ const npm = {
13
+ formatting: require('../../formatting'),
14
+ utils: require('../../utils')
15
+ };
16
+
17
+ /**
18
+ * @method helpers.values
19
+ * @description
20
+ * Generates a string of comma-separated value groups from either one object or an array of objects,
21
+ * to be used as part of a query:
22
+ *
23
+ * - from a single object: `(val_1, val_2, ...)`
24
+ * - from an array of objects: `(val_11, val_12, ...), (val_21, val_22, ...)`
25
+ *
26
+ * @param {object|object[]} data
27
+ * A source object with properties as values, or an array of such objects.
28
+ *
29
+ * If it is anything else, the method will throw {@link external:TypeError TypeError} = `Invalid parameter 'data' specified.`
30
+ *
31
+ * When `data` is an array that contains a non-object value, the method will throw {@link external:Error Error} =
32
+ * `Invalid object at index N.`
33
+ *
34
+ * When `data` is an empty array, an empty string is returned.
35
+ *
36
+ * @param {array|helpers.Column|helpers.ColumnSet} [columns]
37
+ * Columns for which to return values.
38
+ *
39
+ * It is optional when `data` is a single object, and required when `data` is an array of objects. If not specified for an array
40
+ * of objects, the method will throw {@link external:TypeError TypeError} = `Parameter 'columns' is required when generating multi-row values.`
41
+ *
42
+ * When the final {@link helpers.ColumnSet ColumnSet} is empty (no columns in it), the method will throw
43
+ * {@link external:Error Error} = `Cannot generate values without any columns.`
44
+ *
45
+ * @returns {string}
46
+ * - comma-separated value groups, according to `data`
47
+ * - an empty string, if `data` is an empty array
48
+ *
49
+ * @see
50
+ * {@link helpers.Column Column},
51
+ * {@link helpers.ColumnSet ColumnSet}
52
+ *
53
+ * @example
54
+ *
55
+ * const pgp = require('pg-promise')();
56
+ *
57
+ * const dataSingle = {val: 123, msg: 'hello'};
58
+ * const dataMulti = [{val: 123, msg: 'hello'}, {val: 456, msg: 'world!'}];
59
+ *
60
+ * // Properties can be pulled automatically from a single object:
61
+ *
62
+ * pgp.helpers.values(dataSingle);
63
+ * //=> (123,'hello')
64
+ *
65
+ * @example
66
+ *
67
+ * // Column details are required when using an array of objects:
68
+ *
69
+ * pgp.helpers.values(dataMulti, ['val', 'msg']);
70
+ * //=> (123,'hello'),(456,'world!')
71
+ *
72
+ * @example
73
+ *
74
+ * // Column details from a reusable ColumnSet (recommended for performance):
75
+ * const {ColumnSet, values} = pgp.helpers;
76
+ *
77
+ * const cs = new ColumnSet(['val', 'msg']);
78
+ *
79
+ * values(dataMulti, cs);
80
+ * //=> (123,'hello'),(456,'world!')
81
+ *
82
+ */
83
+ function values(data, columns, capSQL) {
84
+
85
+ if (!data || typeof data !== 'object') {
86
+ throw new TypeError('Invalid parameter \'data\' specified.');
87
+ }
88
+
89
+ const isArray = Array.isArray(data);
90
+
91
+ if (!(columns instanceof ColumnSet)) {
92
+ if (isArray && npm.utils.isNull(columns)) {
93
+ throw new TypeError('Parameter \'columns\' is required when generating multi-row values.');
94
+ }
95
+ columns = new ColumnSet(columns || data);
96
+ }
97
+
98
+ if (!columns.columns.length) {
99
+ throw new Error('Cannot generate values without any columns.');
100
+ }
101
+
102
+ const format = npm.formatting.as.format,
103
+ fmOptions = {capSQL};
104
+
105
+ if (isArray) {
106
+ return data.map((d, index) => {
107
+ if (!d || typeof d !== 'object') {
108
+ throw new Error(`Invalid object at index ${index}.`);
109
+ }
110
+ return '(' + format(columns.variables, columns.prepare(d), fmOptions) + ')';
111
+ }).join();
112
+ }
113
+ return '(' + format(columns.variables, columns.prepare(data), fmOptions) + ')';
114
+ }
115
+
116
+ module.exports = {values};