@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.
- package/LICENSE +21 -0
- package/README.md +25 -0
- package/lib/assert.js +10 -0
- package/lib/connect.js +178 -0
- package/lib/context.js +93 -0
- package/lib/database-pool.js +115 -0
- package/lib/database.js +1643 -0
- package/lib/errors/README.md +13 -0
- package/lib/errors/index.js +51 -0
- package/lib/errors/parameterized-query-error.js +71 -0
- package/lib/errors/prepared-statement-error.js +71 -0
- package/lib/errors/query-file-error.js +75 -0
- package/lib/errors/query-result-error.js +157 -0
- package/lib/events.js +543 -0
- package/lib/formatting.js +932 -0
- package/lib/helpers/README.md +10 -0
- package/lib/helpers/column-set.js +614 -0
- package/lib/helpers/column.js +406 -0
- package/lib/helpers/index.js +75 -0
- package/lib/helpers/methods/concat.js +103 -0
- package/lib/helpers/methods/index.js +13 -0
- package/lib/helpers/methods/insert.js +151 -0
- package/lib/helpers/methods/sets.js +81 -0
- package/lib/helpers/methods/update.js +248 -0
- package/lib/helpers/methods/values.js +116 -0
- package/lib/helpers/table-name.js +175 -0
- package/lib/index.js +29 -0
- package/lib/inner-state.js +39 -0
- package/lib/main.js +394 -0
- package/lib/patterns.js +43 -0
- package/lib/query-file.js +379 -0
- package/lib/query-result.js +39 -0
- package/lib/query.js +273 -0
- package/lib/special-query.js +30 -0
- package/lib/stream.js +125 -0
- package/lib/task.js +404 -0
- package/lib/text.js +40 -0
- package/lib/tx-mode.js +194 -0
- package/lib/types/index.js +18 -0
- package/lib/types/parameterized-query.js +247 -0
- package/lib/types/prepared-statement.js +298 -0
- package/lib/types/server-formatting.js +92 -0
- package/lib/utils/README.md +13 -0
- package/lib/utils/color.js +68 -0
- package/lib/utils/index.js +199 -0
- package/lib/utils/public.js +312 -0
- package/package.json +77 -0
- package/typescript/README.md +63 -0
- package/typescript/pg-promise.d.ts +728 -0
- package/typescript/pg-subset.d.ts +359 -0
- package/typescript/tslint.json +21 -0
|
@@ -0,0 +1,406 @@
|
|
|
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 {InnerState} = require('../inner-state');
|
|
11
|
+
const {assert} = require('../assert');
|
|
12
|
+
|
|
13
|
+
const npm = {
|
|
14
|
+
os: require('os'),
|
|
15
|
+
utils: require('../utils'),
|
|
16
|
+
formatting: require('../formatting'),
|
|
17
|
+
patterns: require('../patterns')
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @class helpers.Column
|
|
23
|
+
* @description
|
|
24
|
+
*
|
|
25
|
+
* Read-only structure with details for a single column. Used primarily by {@link helpers.ColumnSet ColumnSet}.
|
|
26
|
+
*
|
|
27
|
+
* The class parses details into a template, to be used for query generation.
|
|
28
|
+
*
|
|
29
|
+
* @param {string|helpers.ColumnConfig} col
|
|
30
|
+
* Column details, depending on the type.
|
|
31
|
+
*
|
|
32
|
+
* When it is a string, it is expected to contain a name for both the column and the source property, assuming that the two are the same.
|
|
33
|
+
* The name must adhere to JavaScript syntax for variable names. The name can be appended with any format modifier as supported by
|
|
34
|
+
* {@link formatting.format as.format} (`^`, `~`, `#`, `:csv`, `:list`, `:json`, `:alias`, `:name`, `:raw`, `:value`), which is then removed from the name and put
|
|
35
|
+
* into property `mod`. If the name starts with `?`, it is removed, while setting flag `cnd` = `true`.
|
|
36
|
+
*
|
|
37
|
+
* If the string doesn't adhere to the above requirements, the method will throw {@link external:TypeError TypeError} = `Invalid column syntax`.
|
|
38
|
+
*
|
|
39
|
+
* When `col` is a simple {@link helpers.ColumnConfig ColumnConfig}-like object, it is used as an input configurator to set all the properties
|
|
40
|
+
* of the class.
|
|
41
|
+
*
|
|
42
|
+
* @property {string} name
|
|
43
|
+
* Destination column name + source property name (if `prop` is skipped). The name must adhere to JavaScript syntax for variables,
|
|
44
|
+
* unless `prop` is specified, in which case `name` represents only the column name, and therefore can be any non-empty string.
|
|
45
|
+
*
|
|
46
|
+
* @property {string} [prop]
|
|
47
|
+
* Source property name, if different from the column's name. It must adhere to JavaScript syntax for variables.
|
|
48
|
+
*
|
|
49
|
+
* It is ignored when it is the same as `name`.
|
|
50
|
+
*
|
|
51
|
+
* @property {string} [mod]
|
|
52
|
+
* Formatting modifier, as supported by method {@link formatting.format as.format}: `^`, `~`, `#`, `:csv`, `:list`, `:json`, `:alias`, `:name`, `:raw`, `:value`.
|
|
53
|
+
*
|
|
54
|
+
* @property {string} [cast]
|
|
55
|
+
* Server-side type casting, without `::` in front.
|
|
56
|
+
*
|
|
57
|
+
* @property {boolean} [cnd]
|
|
58
|
+
* Conditional column flag.
|
|
59
|
+
*
|
|
60
|
+
* Used by methods {@link helpers.update update} and {@link helpers.sets sets}, ignored by methods {@link helpers.insert insert} and
|
|
61
|
+
* {@link helpers.values values}. It indicates that the column is reserved for a `WHERE` condition, not to be set or updated.
|
|
62
|
+
*
|
|
63
|
+
* It can be set from a string initialization, by adding `?` in front of the name.
|
|
64
|
+
*
|
|
65
|
+
* @property {*} [def]
|
|
66
|
+
* Default value for the property, to be used only when the source object doesn't have the property.
|
|
67
|
+
* It is ignored when property `init` is set.
|
|
68
|
+
*
|
|
69
|
+
* @property {helpers.initCB} [init]
|
|
70
|
+
* Override callback for the value.
|
|
71
|
+
*
|
|
72
|
+
* @property {helpers.skipCB} [skip]
|
|
73
|
+
* An override for skipping columns dynamically.
|
|
74
|
+
*
|
|
75
|
+
* Used by methods {@link helpers.update update} (for a single object) and {@link helpers.sets sets}, ignored by methods
|
|
76
|
+
* {@link helpers.insert insert} and {@link helpers.values values}.
|
|
77
|
+
*
|
|
78
|
+
* It is also ignored when conditional flag `cnd` is set.
|
|
79
|
+
*
|
|
80
|
+
* @returns {helpers.Column}
|
|
81
|
+
*
|
|
82
|
+
* @see
|
|
83
|
+
* {@link helpers.ColumnConfig ColumnConfig},
|
|
84
|
+
* {@link helpers.Column#castText castText},
|
|
85
|
+
* {@link helpers.Column#escapedName escapedName},
|
|
86
|
+
* {@link helpers.Column#variable variable}
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
*
|
|
90
|
+
* const pgp = require('pg-promise')({
|
|
91
|
+
* capSQL: true // if you want all generated SQL capitalized
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* const {Column} = pgp.helpers;
|
|
95
|
+
*
|
|
96
|
+
* // creating a column from just a name:
|
|
97
|
+
* const col1 = new Column('colName');
|
|
98
|
+
* console.log(col1);
|
|
99
|
+
* //=>
|
|
100
|
+
* // Column {
|
|
101
|
+
* // name: "colName"
|
|
102
|
+
* // }
|
|
103
|
+
*
|
|
104
|
+
* // creating a column from a name + modifier:
|
|
105
|
+
* const col2 = new Column('colName:csv');
|
|
106
|
+
* console.log(col2);
|
|
107
|
+
* //=>
|
|
108
|
+
* // Column {
|
|
109
|
+
* // name: "colName"
|
|
110
|
+
* // mod: ":csv"
|
|
111
|
+
* // }
|
|
112
|
+
*
|
|
113
|
+
* // creating a column from a configurator:
|
|
114
|
+
* const col3 = new Column({
|
|
115
|
+
* name: 'colName', // required
|
|
116
|
+
* prop: 'propName', // optional
|
|
117
|
+
* mod: '^', // optional
|
|
118
|
+
* def: 123 // optional
|
|
119
|
+
* });
|
|
120
|
+
* console.log(col3);
|
|
121
|
+
* //=>
|
|
122
|
+
* // Column {
|
|
123
|
+
* // name: "colName"
|
|
124
|
+
* // prop: "propName"
|
|
125
|
+
* // mod: "^"
|
|
126
|
+
* // def: 123
|
|
127
|
+
* // }
|
|
128
|
+
*
|
|
129
|
+
*/
|
|
130
|
+
class Column extends InnerState {
|
|
131
|
+
|
|
132
|
+
constructor(col) {
|
|
133
|
+
super();
|
|
134
|
+
|
|
135
|
+
if (typeof col === 'string') {
|
|
136
|
+
const info = parseColumn(col);
|
|
137
|
+
this.name = info.name;
|
|
138
|
+
if ('mod' in info) {
|
|
139
|
+
this.mod = info.mod;
|
|
140
|
+
}
|
|
141
|
+
if ('cnd' in info) {
|
|
142
|
+
this.cnd = info.cnd;
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
col = assert(col, ['name', 'prop', 'mod', 'cast', 'cnd', 'def', 'init', 'skip']);
|
|
146
|
+
if ('name' in col) {
|
|
147
|
+
if (!npm.utils.isText(col.name)) {
|
|
148
|
+
throw new TypeError(`Invalid 'name' value: ${npm.utils.toJson(col.name)}. A non-empty string was expected.`);
|
|
149
|
+
}
|
|
150
|
+
if (npm.utils.isNull(col.prop) && !isValidVariable(col.name)) {
|
|
151
|
+
throw new TypeError(`Invalid 'name' syntax: ${npm.utils.toJson(col.name)}.`);
|
|
152
|
+
}
|
|
153
|
+
this.name = col.name; // column name + property name (if 'prop' isn't specified)
|
|
154
|
+
|
|
155
|
+
if (!npm.utils.isNull(col.prop)) {
|
|
156
|
+
if (!npm.utils.isText(col.prop)) {
|
|
157
|
+
throw new TypeError(`Invalid 'prop' value: ${npm.utils.toJson(col.prop)}. A non-empty string was expected.`);
|
|
158
|
+
}
|
|
159
|
+
if (!isValidVariable(col.prop)) {
|
|
160
|
+
throw new TypeError(`Invalid 'prop' syntax: ${npm.utils.toJson(col.prop)}.`);
|
|
161
|
+
}
|
|
162
|
+
if (col.prop !== col.name) {
|
|
163
|
+
// optional property name, if different from the column's name;
|
|
164
|
+
this.prop = col.prop;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (!npm.utils.isNull(col.mod)) {
|
|
168
|
+
if (typeof col.mod !== 'string' || !isValidMod(col.mod)) {
|
|
169
|
+
throw new TypeError(`Invalid 'mod' value: ${npm.utils.toJson(col.mod)}.`);
|
|
170
|
+
}
|
|
171
|
+
this.mod = col.mod; // optional format modifier;
|
|
172
|
+
}
|
|
173
|
+
if (!npm.utils.isNull(col.cast)) {
|
|
174
|
+
this.cast = parseCast(col.cast); // optional SQL type casting
|
|
175
|
+
}
|
|
176
|
+
if ('cnd' in col) {
|
|
177
|
+
this.cnd = !!col.cnd;
|
|
178
|
+
}
|
|
179
|
+
if ('def' in col) {
|
|
180
|
+
this.def = col.def; // optional default
|
|
181
|
+
}
|
|
182
|
+
if (typeof col.init === 'function') {
|
|
183
|
+
this.init = col.init; // optional value override (overrides 'def' also)
|
|
184
|
+
}
|
|
185
|
+
if (typeof col.skip === 'function') {
|
|
186
|
+
this.skip = col.skip;
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
throw new TypeError('Invalid column details.');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const variable = '${' + (this.prop || this.name) + (this.mod || '') + '}';
|
|
194
|
+
const castText = this.cast ? ('::' + this.cast) : '';
|
|
195
|
+
const escapedName = npm.formatting.as.name(this.name);
|
|
196
|
+
|
|
197
|
+
this.extendState({variable, castText, escapedName});
|
|
198
|
+
Object.freeze(this);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* @name helpers.Column#variable
|
|
203
|
+
* @type string
|
|
204
|
+
* @readonly
|
|
205
|
+
* @description
|
|
206
|
+
* Full-syntax formatting variable, ready for direct use in query templates.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
*
|
|
210
|
+
* const cs = new ColumnSet([
|
|
211
|
+
* 'id',
|
|
212
|
+
* 'coordinate:json',
|
|
213
|
+
* {
|
|
214
|
+
* name: 'places',
|
|
215
|
+
* mod: ':csv',
|
|
216
|
+
* cast: 'int[]'
|
|
217
|
+
* }
|
|
218
|
+
* ]);
|
|
219
|
+
*
|
|
220
|
+
* // cs.columns[0].variable = ${id}
|
|
221
|
+
* // cs.columns[1].variable = ${coordinate:json}
|
|
222
|
+
* // cs.columns[2].variable = ${places:csv}::int[]
|
|
223
|
+
*/
|
|
224
|
+
get variable() {
|
|
225
|
+
return this._inner.variable;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @name helpers.Column#castText
|
|
230
|
+
* @type string
|
|
231
|
+
* @readonly
|
|
232
|
+
* @description
|
|
233
|
+
* Full-syntax sql type casting, if there is any, or else an empty string.
|
|
234
|
+
*/
|
|
235
|
+
get castText() {
|
|
236
|
+
return this._inner.castText;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @name helpers.Column#escapedName
|
|
241
|
+
* @type string
|
|
242
|
+
* @readonly
|
|
243
|
+
* @description
|
|
244
|
+
* Escaped name of the column, ready to be injected into queries directly.
|
|
245
|
+
*
|
|
246
|
+
*/
|
|
247
|
+
get escapedName() {
|
|
248
|
+
return this._inner.escapedName;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function parseCast(name) {
|
|
254
|
+
if (typeof name === 'string') {
|
|
255
|
+
const s = name.replace(/^[:\s]*|\s*$/g, '');
|
|
256
|
+
if (s) {
|
|
257
|
+
return s;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
throw new TypeError(`Invalid 'cast' value: ${npm.utils.toJson(name)}.`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function parseColumn(name) {
|
|
264
|
+
const m = name.match(npm.patterns.validColumn);
|
|
265
|
+
if (m && m[0] === name) {
|
|
266
|
+
const res = {};
|
|
267
|
+
if (name[0] === '?') {
|
|
268
|
+
res.cnd = true;
|
|
269
|
+
name = name.substring(1);
|
|
270
|
+
}
|
|
271
|
+
const mod = name.match(npm.patterns.hasValidModifier);
|
|
272
|
+
if (mod) {
|
|
273
|
+
res.name = name.substring(0, mod.index);
|
|
274
|
+
res.mod = mod[0];
|
|
275
|
+
} else {
|
|
276
|
+
res.name = name;
|
|
277
|
+
}
|
|
278
|
+
return res;
|
|
279
|
+
}
|
|
280
|
+
throw new TypeError(`Invalid column syntax: ${npm.utils.toJson(name)}.`);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function isValidMod(mod) {
|
|
284
|
+
return npm.patterns.validModifiers.indexOf(mod) !== -1;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function isValidVariable(name) {
|
|
288
|
+
const m = name.match(npm.patterns.validVariable);
|
|
289
|
+
return !!m && m[0] === name;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @typedef helpers.ColumnConfig
|
|
294
|
+
* @description
|
|
295
|
+
* A simple structure with column details, to be passed into the {@link helpers.Column Column} constructor for initialization.
|
|
296
|
+
*
|
|
297
|
+
* @property {string} name
|
|
298
|
+
* Destination column name + source property name (if `prop` is skipped). The name must adhere to JavaScript syntax for variables,
|
|
299
|
+
* unless `prop` is specified, in which case `name` represents only the column name, and therefore can be any non-empty string.
|
|
300
|
+
*
|
|
301
|
+
* @property {string} [prop]
|
|
302
|
+
* Source property name, if different from the column's name. It must adhere to JavaScript syntax for variables.
|
|
303
|
+
*
|
|
304
|
+
* It is ignored when it is the same as `name`.
|
|
305
|
+
*
|
|
306
|
+
* @property {string} [mod]
|
|
307
|
+
* Formatting modifier, as supported by method {@link formatting.format as.format}: `^`, `~`, `#`, `:csv`, `:list`, `:json`, `:alias`, `:name`, `:raw`, `:value`.
|
|
308
|
+
*
|
|
309
|
+
* @property {string} [cast]
|
|
310
|
+
* Server-side type casting. Leading `::` is allowed, but not needed (automatically removed when specified).
|
|
311
|
+
*
|
|
312
|
+
* @property {boolean} [cnd]
|
|
313
|
+
* Conditional column flag.
|
|
314
|
+
*
|
|
315
|
+
* Used by methods {@link helpers.update update} and {@link helpers.sets sets}, ignored by methods {@link helpers.insert insert} and
|
|
316
|
+
* {@link helpers.values values}. It indicates that the column is reserved for a `WHERE` condition, not to be set or updated.
|
|
317
|
+
*
|
|
318
|
+
* It can be set from a string initialization by adding `?` in front of the name.
|
|
319
|
+
*
|
|
320
|
+
* @property {*} [def]
|
|
321
|
+
* Default value for the property, to be used only when the source object doesn't have the property.
|
|
322
|
+
* It is ignored when property `init` is set.
|
|
323
|
+
*
|
|
324
|
+
* @property {helpers.initCB} [init]
|
|
325
|
+
* Override callback for the value.
|
|
326
|
+
*
|
|
327
|
+
* @property {helpers.skipCB} [skip]
|
|
328
|
+
* An override for skipping columns dynamically.
|
|
329
|
+
*
|
|
330
|
+
* Used by methods {@link helpers.update update} (for a single object) and {@link helpers.sets sets}, ignored by methods
|
|
331
|
+
* {@link helpers.insert insert} and {@link helpers.values values}.
|
|
332
|
+
*
|
|
333
|
+
* It is also ignored when the conditional flag `cnd` is set.
|
|
334
|
+
*
|
|
335
|
+
*/
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @callback helpers.initCB
|
|
339
|
+
* @description
|
|
340
|
+
* A callback function type used by parameter `init` within {@link helpers.ColumnConfig ColumnConfig}.
|
|
341
|
+
*
|
|
342
|
+
* It works as an override for the corresponding property value in the `source` object.
|
|
343
|
+
*
|
|
344
|
+
* The function is called with `this` set to the `source` object.
|
|
345
|
+
*
|
|
346
|
+
* @param {*} col
|
|
347
|
+
* Column-to-property descriptor.
|
|
348
|
+
*
|
|
349
|
+
* @param {object} col.source
|
|
350
|
+
* The source object, equals to `this` that's passed into the function.
|
|
351
|
+
*
|
|
352
|
+
* @param {string} col.name
|
|
353
|
+
* Resolved name of the property within the `source` object, i.e. the value of `name` when `prop` is not used
|
|
354
|
+
* for the column, or the value of `prop` when it is specified.
|
|
355
|
+
*
|
|
356
|
+
* @param {*} col.value
|
|
357
|
+
*
|
|
358
|
+
* Property value, set to one of the following:
|
|
359
|
+
*
|
|
360
|
+
* - Value of the property within the `source` object (`value` = `source[name]`), if the property exists
|
|
361
|
+
* - If the property doesn't exist and `def` is set in the column, then `value` is set to the value of `def`
|
|
362
|
+
* - If the property doesn't exist and `def` is not set in the column, then `value` is set to `undefined`
|
|
363
|
+
*
|
|
364
|
+
* @param {boolean} col.exists
|
|
365
|
+
* Indicates whether the property exists in the `source` object (`exists = name in source`).
|
|
366
|
+
*
|
|
367
|
+
* @returns {*}
|
|
368
|
+
* The new value to be used for the corresponding column.
|
|
369
|
+
*/
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @callback helpers.skipCB
|
|
373
|
+
* @description
|
|
374
|
+
* A callback function type used by parameter `skip` within {@link helpers.ColumnConfig ColumnConfig}.
|
|
375
|
+
*
|
|
376
|
+
* It is to dynamically determine when the property with specified `name` in the `source` object is to be skipped.
|
|
377
|
+
*
|
|
378
|
+
* The function is called with `this` set to the `source` object.
|
|
379
|
+
*
|
|
380
|
+
* @param {*} col
|
|
381
|
+
* Column-to-property descriptor.
|
|
382
|
+
*
|
|
383
|
+
* @param {object} col.source
|
|
384
|
+
* The source object, equals to `this` that's passed into the function.
|
|
385
|
+
*
|
|
386
|
+
* @param {string} col.name
|
|
387
|
+
* Resolved name of the property within the `source` object, i.e. the value of `name` when `prop` is not used
|
|
388
|
+
* for the column, or the value of `prop` when it is specified.
|
|
389
|
+
*
|
|
390
|
+
* @param {*} col.value
|
|
391
|
+
*
|
|
392
|
+
* Property value, set to one of the following:
|
|
393
|
+
*
|
|
394
|
+
* - Value of the property within the `source` object (`value` = `source[name]`), if the property exists
|
|
395
|
+
* - If the property doesn't exist and `def` is set in the column, then `value` is set to the value of `def`
|
|
396
|
+
* - If the property doesn't exist and `def` is not set in the column, then `value` is set to `undefined`
|
|
397
|
+
*
|
|
398
|
+
* @param {boolean} col.exists
|
|
399
|
+
* Indicates whether the property exists in the `source` object (`exists = name in source`).
|
|
400
|
+
*
|
|
401
|
+
* @returns {boolean}
|
|
402
|
+
* A truthy value that indicates whether the column is to be skipped.
|
|
403
|
+
*
|
|
404
|
+
*/
|
|
405
|
+
|
|
406
|
+
module.exports = {Column};
|
|
@@ -0,0 +1,75 @@
|
|
|
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 {Column} = require('./column');
|
|
11
|
+
const {ColumnSet} = require('./column-set');
|
|
12
|
+
const {TableName, _TN} = require('./table-name');
|
|
13
|
+
const method = require('./methods');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @namespace helpers
|
|
17
|
+
* @description
|
|
18
|
+
* Namespace for query-formatting generators, available as {@link module:pg-promise~helpers pgp.helpers}, after initializing the library.
|
|
19
|
+
*
|
|
20
|
+
* It unifies the approach to generating multi-row `INSERT` / `UPDATE` queries with the single-row ones.
|
|
21
|
+
*
|
|
22
|
+
* See also: $[Performance Boost].
|
|
23
|
+
*
|
|
24
|
+
* @property {function} TableName
|
|
25
|
+
* {@link helpers.TableName TableName} class constructor.
|
|
26
|
+
*
|
|
27
|
+
* @property {function} _TN
|
|
28
|
+
* {@link helpers._TN _TN} Table-Name conversion function.
|
|
29
|
+
*
|
|
30
|
+
* @property {function} ColumnSet
|
|
31
|
+
* {@link helpers.ColumnSet ColumnSet} class constructor.
|
|
32
|
+
*
|
|
33
|
+
* @property {function} Column
|
|
34
|
+
* {@link helpers.Column Column} class constructor.
|
|
35
|
+
*
|
|
36
|
+
* @property {function} insert
|
|
37
|
+
* {@link helpers.insert insert} static method.
|
|
38
|
+
*
|
|
39
|
+
* @property {function} update
|
|
40
|
+
* {@link helpers.update update} static method.
|
|
41
|
+
*
|
|
42
|
+
* @property {function} values
|
|
43
|
+
* {@link helpers.values values} static method.
|
|
44
|
+
*
|
|
45
|
+
* @property {function} sets
|
|
46
|
+
* {@link helpers.sets sets} static method.
|
|
47
|
+
*
|
|
48
|
+
* @property {function} concat
|
|
49
|
+
* {@link helpers.concat concat} static method.
|
|
50
|
+
*/
|
|
51
|
+
module.exports = config => {
|
|
52
|
+
const capSQL = () => config.options && config.options.capSQL;
|
|
53
|
+
const res = {
|
|
54
|
+
insert(data, columns, table) {
|
|
55
|
+
return method.insert(data, columns, table, capSQL());
|
|
56
|
+
},
|
|
57
|
+
update(data, columns, table, options) {
|
|
58
|
+
return method.update(data, columns, table, options, capSQL());
|
|
59
|
+
},
|
|
60
|
+
concat(queries) {
|
|
61
|
+
return method.concat(queries, capSQL());
|
|
62
|
+
},
|
|
63
|
+
values(data, columns) {
|
|
64
|
+
return method.values(data, columns, capSQL());
|
|
65
|
+
},
|
|
66
|
+
sets(data, columns) {
|
|
67
|
+
return method.sets(data, columns, capSQL());
|
|
68
|
+
},
|
|
69
|
+
TableName,
|
|
70
|
+
_TN,
|
|
71
|
+
ColumnSet,
|
|
72
|
+
Column
|
|
73
|
+
};
|
|
74
|
+
return res;
|
|
75
|
+
};
|
|
@@ -0,0 +1,103 @@
|
|
|
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 {QueryFile} = require('../../query-file');
|
|
11
|
+
|
|
12
|
+
const npm = {
|
|
13
|
+
formatting: require('../../formatting')
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @method helpers.concat
|
|
18
|
+
* @description
|
|
19
|
+
* Formats and concatenates multiple queries into a single query string.
|
|
20
|
+
*
|
|
21
|
+
* Before joining the queries, the method does the following:
|
|
22
|
+
* - Formats each query, if `values` are provided;
|
|
23
|
+
* - Removes all leading and trailing spaces, tabs and semi-colons;
|
|
24
|
+
* - Automatically skips all empty queries.
|
|
25
|
+
*
|
|
26
|
+
* @param {array<string|helpers.QueryFormat|QueryFile>} queries
|
|
27
|
+
* Array of mixed-type elements:
|
|
28
|
+
* - a simple query string, to be used as is
|
|
29
|
+
* - a {@link helpers.QueryFormat QueryFormat}-like object = `{query, [values], [options]}`
|
|
30
|
+
* - a {@link QueryFile} object
|
|
31
|
+
*
|
|
32
|
+
* @returns {string}
|
|
33
|
+
* Concatenated string with all queries.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
*
|
|
37
|
+
* const pgp = require('pg-promise')();
|
|
38
|
+
*
|
|
39
|
+
* const qf1 = new pgp.QueryFile('./query1.sql', {minify: true});
|
|
40
|
+
* const qf2 = new pgp.QueryFile('./query2.sql', {minify: true});
|
|
41
|
+
*
|
|
42
|
+
* const query = pgp.helpers.concat([
|
|
43
|
+
* {query: 'INSERT INTO Users(name, age) VALUES($1, $2)', values: ['John', 23]}, // QueryFormat-like object
|
|
44
|
+
* {query: qf1, values: [1, 'Name']}, // QueryFile with formatting parameters
|
|
45
|
+
* 'SELECT count(*) FROM Users', // a simple-string query,
|
|
46
|
+
* qf2 // direct QueryFile object
|
|
47
|
+
* ]);
|
|
48
|
+
*
|
|
49
|
+
* // query = concatenated string with all the queries
|
|
50
|
+
*/
|
|
51
|
+
function concat(queries, capSQL) {
|
|
52
|
+
if (!Array.isArray(queries)) {
|
|
53
|
+
throw new TypeError('Parameter \'queries\' must be an array.');
|
|
54
|
+
}
|
|
55
|
+
const fmOptions = {capSQL};
|
|
56
|
+
const all = queries.map((q, index) => {
|
|
57
|
+
if (typeof q === 'string') {
|
|
58
|
+
// a simple query string without parameters:
|
|
59
|
+
return clean(q);
|
|
60
|
+
}
|
|
61
|
+
if (q && typeof q === 'object') {
|
|
62
|
+
if (q instanceof QueryFile) {
|
|
63
|
+
// QueryFile object:
|
|
64
|
+
return clean(q[npm.formatting.as.ctf.toPostgres]());
|
|
65
|
+
}
|
|
66
|
+
if ('query' in q) {
|
|
67
|
+
// object {query, values, options}:
|
|
68
|
+
let opt = q.options && typeof q.options === 'object' ? q.options : {};
|
|
69
|
+
opt = opt.capSQL === undefined ? Object.assign(opt, fmOptions) : opt;
|
|
70
|
+
return clean(npm.formatting.as.format(q.query, q.values, opt));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Invalid query element at index ${index}.`);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return all.filter(q => q).join(';');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function clean(q) {
|
|
80
|
+
// removes from the query all leading and trailing symbols ' ', '\t' and ';'
|
|
81
|
+
return q.replace(/^[\s;]*|[\s;]*$/g, '');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {concat};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @typedef helpers.QueryFormat
|
|
88
|
+
* @description
|
|
89
|
+
* A simple structure of parameters to be passed into method {@link formatting.format as.format} exactly as they are,
|
|
90
|
+
* used by {@link helpers.concat}.
|
|
91
|
+
*
|
|
92
|
+
* @property {string|value|object} query
|
|
93
|
+
* A query string or a value/object that implements $[Custom Type Formatting], to be formatted according to `values`.
|
|
94
|
+
*
|
|
95
|
+
* @property {array|object|value} [values]
|
|
96
|
+
* Query-formatting values.
|
|
97
|
+
*
|
|
98
|
+
* @property {object} [options]
|
|
99
|
+
* Query-formatting options, as supported by method {@link formatting.format as.format}.
|
|
100
|
+
*
|
|
101
|
+
* @see
|
|
102
|
+
* {@link formatting.format as.format}
|
|
103
|
+
*/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const {concat} = require('./concat');
|
|
2
|
+
const {insert} = require('./insert');
|
|
3
|
+
const {update} = require('./update');
|
|
4
|
+
const {values} = require('./values');
|
|
5
|
+
const {sets} = require('./sets');
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
concat,
|
|
9
|
+
insert,
|
|
10
|
+
update,
|
|
11
|
+
values,
|
|
12
|
+
sets
|
|
13
|
+
};
|