@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,932 @@
|
|
|
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
|
+
|
|
12
|
+
const npm = {
|
|
13
|
+
pgUtils: require('pg/lib/utils'),
|
|
14
|
+
patterns: require('./patterns'),
|
|
15
|
+
utils: require('./utils')
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Format Modification Flags;
|
|
19
|
+
const fmFlags = {
|
|
20
|
+
raw: 1, // Raw-Text variable
|
|
21
|
+
alias: 2, // SQL Alias
|
|
22
|
+
name: 4, // SQL Name/Identifier
|
|
23
|
+
json: 8, // JSON modifier
|
|
24
|
+
csv: 16, // CSV modifier
|
|
25
|
+
value: 32 // escaped, but without ''
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Format Modification Map;
|
|
29
|
+
const fmMap = {
|
|
30
|
+
'^': fmFlags.raw,
|
|
31
|
+
':raw': fmFlags.raw,
|
|
32
|
+
':alias': fmFlags.alias,
|
|
33
|
+
'~': fmFlags.name,
|
|
34
|
+
':name': fmFlags.name,
|
|
35
|
+
':json': fmFlags.json,
|
|
36
|
+
':csv': fmFlags.csv,
|
|
37
|
+
':list': fmFlags.csv,
|
|
38
|
+
':value': fmFlags.value,
|
|
39
|
+
'#': fmFlags.value
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Global symbols for Custom Type Formatting:
|
|
43
|
+
const ctfSymbols = {
|
|
44
|
+
toPostgres: Symbol.for('ctf.toPostgres'),
|
|
45
|
+
rawType: Symbol.for('ctf.rawType')
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const maxVariable = 100000; // maximum supported variable is '$100000'
|
|
49
|
+
|
|
50
|
+
////////////////////////////////////////////////////
|
|
51
|
+
// Converts a single value into its Postgres format.
|
|
52
|
+
function formatValue({value, fm, cc, options}) {
|
|
53
|
+
|
|
54
|
+
if (typeof value === 'function') {
|
|
55
|
+
return formatValue({value: resolveFunc(value, cc), fm, cc});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const ctf = getCTF(value); // Custom Type Formatting
|
|
59
|
+
if (ctf) {
|
|
60
|
+
fm |= ctf.rawType ? fmFlags.raw : 0;
|
|
61
|
+
return formatValue({value: resolveFunc(ctf.toPostgres, value), fm, cc});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const isRaw = !!(fm & fmFlags.raw);
|
|
65
|
+
fm &= ~fmFlags.raw;
|
|
66
|
+
|
|
67
|
+
switch (fm) {
|
|
68
|
+
case fmFlags.alias:
|
|
69
|
+
return $as.alias(value);
|
|
70
|
+
case fmFlags.name:
|
|
71
|
+
return $as.name(value);
|
|
72
|
+
case fmFlags.json:
|
|
73
|
+
return $as.json(value, isRaw);
|
|
74
|
+
case fmFlags.csv:
|
|
75
|
+
return $to.csv(value, options);
|
|
76
|
+
case fmFlags.value:
|
|
77
|
+
return $as.value(value);
|
|
78
|
+
default:
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (isNull(value)) {
|
|
83
|
+
throwIfRaw(isRaw);
|
|
84
|
+
return 'null';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
switch (typeof value) {
|
|
88
|
+
case 'string':
|
|
89
|
+
return $to.text(value, isRaw);
|
|
90
|
+
case 'boolean':
|
|
91
|
+
return $to.bool(value);
|
|
92
|
+
case 'number':
|
|
93
|
+
case 'bigint':
|
|
94
|
+
return $to.number(value);
|
|
95
|
+
case 'symbol':
|
|
96
|
+
throw new TypeError(`Type Symbol has no meaning for PostgreSQL: ${value.toString()}`);
|
|
97
|
+
default:
|
|
98
|
+
if (value instanceof Date) {
|
|
99
|
+
return $to.date(value, isRaw);
|
|
100
|
+
}
|
|
101
|
+
if (Array.isArray(value)) {
|
|
102
|
+
return $to.array(value, options);
|
|
103
|
+
}
|
|
104
|
+
if (Buffer.isBuffer(value)) {
|
|
105
|
+
return $to.buffer(value, isRaw);
|
|
106
|
+
}
|
|
107
|
+
return $to.json(value, isRaw);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
112
|
+
// Converts array of values into PostgreSQL Array Constructor: array[...], as per PostgreSQL documentation:
|
|
113
|
+
// https://www.postgresql.org/docs/17/arrays.html
|
|
114
|
+
//
|
|
115
|
+
// Arrays of any depth/dimension are supported.
|
|
116
|
+
//
|
|
117
|
+
// Top-level empty arrays are formatted as literal '{}' to avoid the necessity of explicit type casting,
|
|
118
|
+
// as the server cannot automatically infer the type of empty non-literal array.
|
|
119
|
+
function formatArray(array, options) {
|
|
120
|
+
const loop = a => '[' + a.map(value => Array.isArray(value) ? loop(value) : formatValue({
|
|
121
|
+
value,
|
|
122
|
+
options
|
|
123
|
+
})).join() + ']';
|
|
124
|
+
const prefix = options && options.capSQL ? 'ARRAY' : 'array';
|
|
125
|
+
return array.length ? (prefix + loop(array)) : '\'{}\'';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
///////////////////////////////////////////////////////////////////
|
|
129
|
+
// Formats array/object/value as a list of comma-separated values.
|
|
130
|
+
function formatCSV(values, options) {
|
|
131
|
+
if (Array.isArray(values)) {
|
|
132
|
+
return values.map(value => formatValue({value, options})).join();
|
|
133
|
+
}
|
|
134
|
+
if (typeof values === 'object' && values !== null) {
|
|
135
|
+
return Object.keys(values).map(v => formatValue({value: values[v], options})).join();
|
|
136
|
+
}
|
|
137
|
+
return values === undefined ? '' : formatValue({value: values, options});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
///////////////////////////////
|
|
141
|
+
// Query formatting helpers;
|
|
142
|
+
const formatAs = {
|
|
143
|
+
|
|
144
|
+
object({query, obj, raw, options}) {
|
|
145
|
+
options = options && typeof options === 'object' ? options : {};
|
|
146
|
+
return query.replace(npm.patterns.namedParameters, name => {
|
|
147
|
+
const v = formatAs.stripName(name.replace(/^\$[{(<[/]|[\s})>\]/]/g, ''), raw),
|
|
148
|
+
c = npm.utils.getIfHas(obj, v.name);
|
|
149
|
+
if (!c.valid) {
|
|
150
|
+
throw new Error(`Invalid property name '${v.name}'.`);
|
|
151
|
+
}
|
|
152
|
+
if (c.has) {
|
|
153
|
+
return formatValue({value: c.value, fm: v.fm, cc: c.target, options});
|
|
154
|
+
}
|
|
155
|
+
if (v.name === 'this') {
|
|
156
|
+
return formatValue({value: obj, fm: v.fm, options});
|
|
157
|
+
}
|
|
158
|
+
if ('def' in options) {
|
|
159
|
+
const d = options.def, value = typeof d === 'function' ? d.call(obj, v.name, obj) : d;
|
|
160
|
+
return formatValue({value, fm: v.fm, cc: obj, options});
|
|
161
|
+
}
|
|
162
|
+
if (options.partial) {
|
|
163
|
+
return name;
|
|
164
|
+
}
|
|
165
|
+
// property must exist as the object's own or inherited;
|
|
166
|
+
throw new Error(`Property '${v.name}' doesn't exist.`);
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
array({query, array, raw, options}) {
|
|
171
|
+
options = options && typeof options === 'object' ? options : {};
|
|
172
|
+
return query.replace(npm.patterns.multipleValues, name => {
|
|
173
|
+
const v = formatAs.stripName(name.substring(1), raw);
|
|
174
|
+
const idx = v.name - 1;
|
|
175
|
+
if (idx >= maxVariable) {
|
|
176
|
+
throw new RangeError(`Variable $${v.name} exceeds supported maximum of $${maxVariable}`);
|
|
177
|
+
}
|
|
178
|
+
if (idx < array.length) {
|
|
179
|
+
return formatValue({value: array[idx], fm: v.fm, options});
|
|
180
|
+
}
|
|
181
|
+
if ('def' in options) {
|
|
182
|
+
const d = options.def, value = typeof d === 'function' ? d.call(array, idx, array) : d;
|
|
183
|
+
return formatValue({value, fm: v.fm, options});
|
|
184
|
+
}
|
|
185
|
+
if (options.partial) {
|
|
186
|
+
return name;
|
|
187
|
+
}
|
|
188
|
+
throw new RangeError(`Variable $${v.name} out of range. Parameters array length: ${array.length}`);
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
value({query, value, raw, options}) {
|
|
193
|
+
return query.replace(npm.patterns.singleValue, name => {
|
|
194
|
+
const v = formatAs.stripName(name, raw);
|
|
195
|
+
return formatValue({value, fm: v.fm, options});
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
stripName(name, raw) {
|
|
200
|
+
const mod = name.match(npm.patterns.hasValidModifier);
|
|
201
|
+
if (mod) {
|
|
202
|
+
return {
|
|
203
|
+
name: name.substring(0, mod.index),
|
|
204
|
+
fm: fmMap[mod[0]] | (raw ? fmFlags.raw : 0)
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
name,
|
|
209
|
+
fm: raw ? fmFlags.raw : null
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
////////////////////////////////////////////
|
|
215
|
+
// Simpler check for null/undefined;
|
|
216
|
+
function isNull(value) {
|
|
217
|
+
return value === undefined || value === null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
//////////////////////////////////////////////////////////////////
|
|
221
|
+
// Checks if the value supports Custom Type Formatting,
|
|
222
|
+
// to return {toPostgres, rawType}, if it does, or null otherwise.
|
|
223
|
+
function getCTF(value) {
|
|
224
|
+
if (!isNull(value)) {
|
|
225
|
+
let toPostgres = value[ctfSymbols.toPostgres], rawType = !!value[ctfSymbols.rawType];
|
|
226
|
+
if (typeof toPostgres !== 'function') {
|
|
227
|
+
toPostgres = value.toPostgres;
|
|
228
|
+
rawType = !!value.rawType;
|
|
229
|
+
}
|
|
230
|
+
if (typeof toPostgres === 'function') {
|
|
231
|
+
if (toPostgres.constructor.name !== 'Function') {
|
|
232
|
+
throw new Error('CTF does not support asynchronous toPostgres functions.');
|
|
233
|
+
}
|
|
234
|
+
return {toPostgres, rawType};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/////////////////////////////////////////
|
|
241
|
+
// Wraps a text string in single quotes;
|
|
242
|
+
function wrapText(text) {
|
|
243
|
+
return `'${text}'`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
////////////////////////////////////////////////
|
|
247
|
+
// Replaces each single-quote symbol ' with two,
|
|
248
|
+
// for compliance with PostgreSQL strings.
|
|
249
|
+
function safeText(text) {
|
|
250
|
+
return text.replace(/'/g, '\'\'');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/////////////////////////////////////////////
|
|
254
|
+
// Throws an exception, if flag 'raw' is set.
|
|
255
|
+
function throwIfRaw(raw) {
|
|
256
|
+
if (raw) {
|
|
257
|
+
throw new TypeError('Values null/undefined cannot be used as raw text.');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/////////////////////////////////////////////////////////////////////////////
|
|
262
|
+
// Recursively resolves parameter-function, with an optional Calling Context.
|
|
263
|
+
function resolveFunc(value, cc) {
|
|
264
|
+
while (typeof value === 'function') {
|
|
265
|
+
if (value.constructor.name !== 'Function') {
|
|
266
|
+
// Constructor name for asynchronous functions have different names:
|
|
267
|
+
// - 'GeneratorFunction' for ES6 generators
|
|
268
|
+
// - 'AsyncFunction' for ES7 async functions
|
|
269
|
+
throw new Error('Cannot use asynchronous functions with query formatting.');
|
|
270
|
+
}
|
|
271
|
+
value = value.call(cc, cc);
|
|
272
|
+
}
|
|
273
|
+
return value;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
///////////////////////////////////////////////////////////////////////////////////
|
|
277
|
+
// It implements two types of formatting, depending on the 'values' passed:
|
|
278
|
+
//
|
|
279
|
+
// 1. format '$1, $2, etc', when 'values' is of type string, boolean, number, date,
|
|
280
|
+
// function or null (or an array of the same types, plus undefined values);
|
|
281
|
+
// 2. format $*propName*, when 'values' is an object (not null and not Date),
|
|
282
|
+
// and where * is any of the supported open-close pairs: {}, (), [], <>, //
|
|
283
|
+
//
|
|
284
|
+
function formatQuery(query, values, raw, options) {
|
|
285
|
+
if (typeof query !== 'string') {
|
|
286
|
+
throw new TypeError('Parameter \'query\' must be a text string.');
|
|
287
|
+
}
|
|
288
|
+
const ctf = getCTF(values);
|
|
289
|
+
if (ctf) {
|
|
290
|
+
// Custom Type Formatting
|
|
291
|
+
return formatQuery(query, resolveFunc(ctf.toPostgres, values), raw || ctf.rawType, options);
|
|
292
|
+
}
|
|
293
|
+
if (typeof values === 'object' && values !== null) {
|
|
294
|
+
if (Array.isArray(values)) {
|
|
295
|
+
// $1, $2,... formatting to be applied;
|
|
296
|
+
return formatAs.array({query, array: values, raw, options});
|
|
297
|
+
}
|
|
298
|
+
if (!(values instanceof Date || values instanceof Buffer)) {
|
|
299
|
+
// $*propName* formatting to be applied;
|
|
300
|
+
return formatAs.object({query, obj: values, raw, options});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// $1 formatting to be applied, if values != undefined;
|
|
304
|
+
return values === undefined ? query : formatAs.value({query, value: values, raw, options});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
//////////////////////////////////////////////////////
|
|
308
|
+
// Formats a function or stored procedure call query;
|
|
309
|
+
function formatEntity(entity, values, {capSQL, type}) {
|
|
310
|
+
let prefix = type === 'func' ? 'select * from' : 'call';
|
|
311
|
+
if (capSQL) {
|
|
312
|
+
prefix = prefix.toUpperCase();
|
|
313
|
+
}
|
|
314
|
+
return `${prefix} ${$as.alias(entity)}(${formatCSV(values, {capSQL})})`;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function formatSqlName(name) {
|
|
318
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @namespace formatting
|
|
323
|
+
* @description
|
|
324
|
+
* Namespace for all query-formatting functions, available from `pgp.as` before and after initializing the library.
|
|
325
|
+
*
|
|
326
|
+
* @property {formatting.ctf} ctf
|
|
327
|
+
* Namespace for symbols used by $[Custom Type Formatting].
|
|
328
|
+
*
|
|
329
|
+
* @property {function} alias
|
|
330
|
+
* {@link formatting.alias alias} - formats an SQL alias.
|
|
331
|
+
*
|
|
332
|
+
* @property {function} name
|
|
333
|
+
* {@link formatting.name name} - formats an SQL Name/Identifier.
|
|
334
|
+
*
|
|
335
|
+
* @property {function} text
|
|
336
|
+
* {@link formatting.text text} - formats a text string.
|
|
337
|
+
*
|
|
338
|
+
* @property {function} number
|
|
339
|
+
* {@link formatting.number number} - formats a number.
|
|
340
|
+
*
|
|
341
|
+
* @property {function} buffer
|
|
342
|
+
* {@link formatting.buffer buffer} - formats a `Buffer` object.
|
|
343
|
+
*
|
|
344
|
+
* @property {function} value
|
|
345
|
+
* {@link formatting.value value} - formats text as an open value.
|
|
346
|
+
*
|
|
347
|
+
* @property {function} json
|
|
348
|
+
* {@link formatting.json json} - formats any value as JSON.
|
|
349
|
+
*
|
|
350
|
+
* @property {function} array
|
|
351
|
+
* {@link formatting.array array} - formats an array of any depth.
|
|
352
|
+
*
|
|
353
|
+
* @property {function} csv
|
|
354
|
+
* {@link formatting.csv csv} - formats an array as a list of comma-separated values.
|
|
355
|
+
*
|
|
356
|
+
* @property {function} func
|
|
357
|
+
* {@link formatting.func func} - formats the value returned from a function.
|
|
358
|
+
*
|
|
359
|
+
* @property {function} format
|
|
360
|
+
* {@link formatting.format format} - formats a query, according to parameters.
|
|
361
|
+
*
|
|
362
|
+
*/
|
|
363
|
+
const $as = {
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @namespace formatting.ctf
|
|
367
|
+
* @description
|
|
368
|
+
* Namespace for ES6 symbols used by $[Custom Type Formatting], available from `pgp.as.ctf` before and after initializing the library.
|
|
369
|
+
*
|
|
370
|
+
* It was added to avoid explicit/enumerable extension of types that need to be used as formatting parameters, to keep their type signature intact.
|
|
371
|
+
*
|
|
372
|
+
* @property {external:Symbol} toPostgres
|
|
373
|
+
* Property name for the $[Custom Type Formatting] callback function `toPostgres`.
|
|
374
|
+
*
|
|
375
|
+
* @property {external:Symbol} rawType
|
|
376
|
+
* Property name for the $[Custom Type Formatting] flag `rawType`.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* const {toPostgres, rawType} = pgp.as.ctf; // Custom Type Formatting symbols
|
|
380
|
+
*
|
|
381
|
+
* class MyType {
|
|
382
|
+
* constructor() {
|
|
383
|
+
* this[rawType] = true; // set it only when toPostgres returns a pre-formatted result
|
|
384
|
+
* }
|
|
385
|
+
*
|
|
386
|
+
* [toPostgres](self) {
|
|
387
|
+
* // self = this
|
|
388
|
+
*
|
|
389
|
+
* // return the custom/actual value here
|
|
390
|
+
* }
|
|
391
|
+
* }
|
|
392
|
+
*
|
|
393
|
+
* const a = new MyType();
|
|
394
|
+
*
|
|
395
|
+
* const s = pgp.as.format('$1', a); // will be custom-formatted
|
|
396
|
+
*/
|
|
397
|
+
ctf: ctfSymbols,
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* @method formatting.text
|
|
401
|
+
* @description
|
|
402
|
+
* Converts a value into PostgreSQL text presentation, escaped as required.
|
|
403
|
+
*
|
|
404
|
+
* Escaping the result means:
|
|
405
|
+
* 1. Every single-quote (apostrophe) is replaced with two
|
|
406
|
+
* 2. The resulting text is wrapped in apostrophes
|
|
407
|
+
*
|
|
408
|
+
* @param {value|function} value
|
|
409
|
+
* Value to be converted, or a function that returns the value.
|
|
410
|
+
*
|
|
411
|
+
* If the `value` resolves as `null` or `undefined`, while `raw`=`true`,
|
|
412
|
+
* it will throw {@link external:TypeError TypeError} = `Values null/undefined cannot be used as raw text.`
|
|
413
|
+
*
|
|
414
|
+
* @param {boolean} [raw=false]
|
|
415
|
+
* Indicates when not to escape the resulting text.
|
|
416
|
+
*
|
|
417
|
+
* @returns {string}
|
|
418
|
+
*
|
|
419
|
+
* - `null` string, if the `value` resolves as `null` or `undefined`
|
|
420
|
+
* - escaped result of `value.toString()`, if the `value` isn't a string
|
|
421
|
+
* - escaped string version, if `value` is a string.
|
|
422
|
+
*
|
|
423
|
+
* The result is not escaped, if `raw` was passed in as `true`.
|
|
424
|
+
*/
|
|
425
|
+
text(value, raw) {
|
|
426
|
+
value = resolveFunc(value);
|
|
427
|
+
if (isNull(value)) {
|
|
428
|
+
throwIfRaw(raw);
|
|
429
|
+
return 'null';
|
|
430
|
+
}
|
|
431
|
+
if (typeof value !== 'string') {
|
|
432
|
+
value = value.toString();
|
|
433
|
+
}
|
|
434
|
+
return $to.text(value, raw);
|
|
435
|
+
},
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* @method formatting.name
|
|
439
|
+
* @description
|
|
440
|
+
* Properly escapes an sql name or identifier, fixing double-quote symbols and wrapping the result in double quotes.
|
|
441
|
+
*
|
|
442
|
+
* Implements a safe way to format $[SQL Names] that neutralizes SQL Injection.
|
|
443
|
+
*
|
|
444
|
+
* When formatting a query, a variable makes use of this method via modifier `:name` or `~`. See method {@link formatting.format format}.
|
|
445
|
+
*
|
|
446
|
+
* @param {string|function|array|object} name
|
|
447
|
+
* SQL name or identifier, or a function that returns it.
|
|
448
|
+
*
|
|
449
|
+
* The name must be at least 1 character long.
|
|
450
|
+
*
|
|
451
|
+
* If `name` doesn't resolve into a non-empty string, it throws {@link external:TypeError TypeError} = `Invalid sql name: ...`
|
|
452
|
+
*
|
|
453
|
+
* If the `name` contains only a single `*` (trailing spaces are ignored), then `name` is returned exactly as is (unescaped).
|
|
454
|
+
*
|
|
455
|
+
* - If `name` is an Array, it is formatted as a comma-separated list of $[SQL Names]
|
|
456
|
+
* - If `name` is a non-Array object, its keys are formatted as a comma-separated list of $[SQL Names]
|
|
457
|
+
*
|
|
458
|
+
* Passing in an empty array/object will throw {@link external:Error Error} = `Cannot retrieve sql names from an empty array/object.`
|
|
459
|
+
*
|
|
460
|
+
* @returns {string}
|
|
461
|
+
* The SQL Name/Identifier, properly escaped for compliance with the PostgreSQL standard for $[SQL Names] and identifiers.
|
|
462
|
+
*
|
|
463
|
+
* @see
|
|
464
|
+
* {@link formatting.alias alias},
|
|
465
|
+
* {@link formatting.format format}
|
|
466
|
+
*
|
|
467
|
+
* @example
|
|
468
|
+
*
|
|
469
|
+
* // automatically list object properties as sql names:
|
|
470
|
+
* format('INSERT INTO table(${this~}) VALUES(${one}, ${two})', {
|
|
471
|
+
* one: 1,
|
|
472
|
+
* two: 2
|
|
473
|
+
* });
|
|
474
|
+
* //=> INSERT INTO table("one","two") VALUES(1, 2)
|
|
475
|
+
*
|
|
476
|
+
*/
|
|
477
|
+
name(name) {
|
|
478
|
+
name = resolveFunc(name);
|
|
479
|
+
if (name) {
|
|
480
|
+
if (typeof name === 'string') {
|
|
481
|
+
return /^\s*\*(\s*)$/.test(name) ? name : formatSqlName(name);
|
|
482
|
+
}
|
|
483
|
+
if (typeof name === 'object') {
|
|
484
|
+
const keys = Array.isArray(name) ? name : Object.keys(name);
|
|
485
|
+
if (!keys.length) {
|
|
486
|
+
throw new Error('Cannot retrieve sql names from an empty array/object.');
|
|
487
|
+
}
|
|
488
|
+
return keys.map(value => {
|
|
489
|
+
if (!value || typeof value !== 'string') {
|
|
490
|
+
throw new Error(`Invalid sql name: ${npm.utils.toJson(value)}`);
|
|
491
|
+
}
|
|
492
|
+
return formatSqlName(value);
|
|
493
|
+
}).join();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
throw new TypeError(`Invalid sql name: ${npm.utils.toJson(name)}`);
|
|
497
|
+
},
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @method formatting.alias
|
|
501
|
+
* @description
|
|
502
|
+
* Simpler (non-verbose) version of method {@link formatting.name name}, to handle only a regular string-identifier
|
|
503
|
+
* that's mostly used as an SQL alias, i.e. it doesn't support `*` or an array/object of names, which in the context of
|
|
504
|
+
* an SQL alias would be incorrect. However, it supports `.` as name-separator, for simpler escaping of composite names.
|
|
505
|
+
*
|
|
506
|
+
* The surrounding double quotes are not added when the alias uses a simple syntax:
|
|
507
|
+
* - it is a same-case single word, without spaces
|
|
508
|
+
* - it can contain underscores, and can even start with them
|
|
509
|
+
* - it can contain digits and `$`, but cannot start with those
|
|
510
|
+
*
|
|
511
|
+
* The method will automatically split the string with `.`, to support composite SQL names.
|
|
512
|
+
*
|
|
513
|
+
* When formatting a query, a variable makes use of this method via modifier `:alias`. See method {@link formatting.format format}.
|
|
514
|
+
*
|
|
515
|
+
* @param {string|function} name
|
|
516
|
+
* SQL alias name, or a function that returns it.
|
|
517
|
+
*
|
|
518
|
+
* The name must be at least 1 character long. And it can contain `.`, to split into multiple SQL names.
|
|
519
|
+
*
|
|
520
|
+
* If `name` doesn't resolve into a non-empty string, it throws {@link external:TypeError TypeError} = `Invalid sql alias: ...`
|
|
521
|
+
*
|
|
522
|
+
* @returns {string}
|
|
523
|
+
* The SQL alias, properly escaped for compliance with the PostgreSQL standard for $[SQL Names] and identifiers.
|
|
524
|
+
*
|
|
525
|
+
* @see
|
|
526
|
+
* {@link formatting.name name},
|
|
527
|
+
* {@link formatting.format format}
|
|
528
|
+
*
|
|
529
|
+
*/
|
|
530
|
+
alias(name) {
|
|
531
|
+
name = resolveFunc(name);
|
|
532
|
+
if (name && typeof name === 'string') {
|
|
533
|
+
return name.split('.')
|
|
534
|
+
.filter(f => f)
|
|
535
|
+
.map(a => {
|
|
536
|
+
const m = a.match(/^([a-z_][a-z0-9_$]*|[A-Z_][A-Z0-9_$]*)$/);
|
|
537
|
+
if (m && m[0] === a) {
|
|
538
|
+
return a;
|
|
539
|
+
}
|
|
540
|
+
return `"${a.replace(/"/g, '""')}"`;
|
|
541
|
+
}).join('.');
|
|
542
|
+
}
|
|
543
|
+
throw new TypeError(`Invalid sql alias: ${npm.utils.toJson(name)}`);
|
|
544
|
+
},
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* @method formatting.value
|
|
548
|
+
* @description
|
|
549
|
+
* Represents an open value, one to be formatted according to its type, properly escaped, but without surrounding quotes for text types.
|
|
550
|
+
*
|
|
551
|
+
* When formatting a query, a variable makes use of this method via modifier `:value` or `#`. See method {@link formatting.format format}.
|
|
552
|
+
*
|
|
553
|
+
* @param {value|function} value
|
|
554
|
+
* Value to be converted, or a function that returns the value.
|
|
555
|
+
*
|
|
556
|
+
* If `value` resolves as `null` or `undefined`, it will throw {@link external:TypeError TypeError} = `Open values cannot be null or undefined.`
|
|
557
|
+
*
|
|
558
|
+
* @returns {string}
|
|
559
|
+
* Formatted and properly escaped string, but without surrounding quotes for text types.
|
|
560
|
+
*
|
|
561
|
+
* @see {@link formatting.format format}
|
|
562
|
+
*
|
|
563
|
+
*/
|
|
564
|
+
value(value) {
|
|
565
|
+
value = resolveFunc(value);
|
|
566
|
+
if (isNull(value)) {
|
|
567
|
+
throw new TypeError('Open values cannot be null or undefined.');
|
|
568
|
+
}
|
|
569
|
+
return safeText(formatValue({value, fm: fmFlags.raw}));
|
|
570
|
+
},
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* @method formatting.buffer
|
|
574
|
+
* @description
|
|
575
|
+
* Converts an object of type `Buffer` into a hex string compatible with PostgreSQL type `bytea`.
|
|
576
|
+
*
|
|
577
|
+
* @param {Buffer|function} obj
|
|
578
|
+
* Object to be converted, or a function that returns one.
|
|
579
|
+
*
|
|
580
|
+
* @param {boolean} [raw=false]
|
|
581
|
+
* Indicates when not to wrap the resulting string in quotes.
|
|
582
|
+
*
|
|
583
|
+
* The generated hex string doesn't need to be escaped.
|
|
584
|
+
*
|
|
585
|
+
* @returns {string}
|
|
586
|
+
*/
|
|
587
|
+
buffer(obj, raw) {
|
|
588
|
+
obj = resolveFunc(obj);
|
|
589
|
+
if (isNull(obj)) {
|
|
590
|
+
throwIfRaw(raw);
|
|
591
|
+
return 'null';
|
|
592
|
+
}
|
|
593
|
+
if (obj instanceof Buffer) {
|
|
594
|
+
return $to.buffer(obj, raw);
|
|
595
|
+
}
|
|
596
|
+
throw new TypeError(`${wrapText(obj)} is not a Buffer object.`);
|
|
597
|
+
},
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* @method formatting.bool
|
|
601
|
+
* @description
|
|
602
|
+
* Converts a truthy value into PostgreSQL boolean presentation.
|
|
603
|
+
*
|
|
604
|
+
* @param {boolean|function} value
|
|
605
|
+
* Value to be converted, or a function that returns the value.
|
|
606
|
+
*
|
|
607
|
+
* @returns {string}
|
|
608
|
+
*/
|
|
609
|
+
bool(value) {
|
|
610
|
+
value = resolveFunc(value);
|
|
611
|
+
if (isNull(value)) {
|
|
612
|
+
return 'null';
|
|
613
|
+
}
|
|
614
|
+
return $to.bool(value);
|
|
615
|
+
},
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* @method formatting.date
|
|
619
|
+
* @description
|
|
620
|
+
* Converts a `Date`-type value into PostgreSQL date/time presentation,
|
|
621
|
+
* wrapped in quotes (unless flag `raw` is set).
|
|
622
|
+
*
|
|
623
|
+
* @param {Date|function} d
|
|
624
|
+
* Date object to be converted, or a function that returns one.
|
|
625
|
+
*
|
|
626
|
+
* @param {boolean} [raw=false]
|
|
627
|
+
* Indicates when not to escape the value.
|
|
628
|
+
*
|
|
629
|
+
* @returns {string}
|
|
630
|
+
*/
|
|
631
|
+
date(d, raw) {
|
|
632
|
+
d = resolveFunc(d);
|
|
633
|
+
if (isNull(d)) {
|
|
634
|
+
throwIfRaw(raw);
|
|
635
|
+
return 'null';
|
|
636
|
+
}
|
|
637
|
+
if (d instanceof Date) {
|
|
638
|
+
return $to.date(d, raw);
|
|
639
|
+
}
|
|
640
|
+
throw new TypeError(`${wrapText(d)} is not a Date object.`);
|
|
641
|
+
},
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* @method formatting.number
|
|
645
|
+
* @description
|
|
646
|
+
* Converts a numeric value into its PostgreSQL number presentation, with support
|
|
647
|
+
* for special values of `NaN`, `+Infinity` and `-Infinity`.
|
|
648
|
+
*
|
|
649
|
+
* @param {number|bigint|function} num
|
|
650
|
+
* Number to be converted, or a function that returns one.
|
|
651
|
+
*
|
|
652
|
+
* @returns {string}
|
|
653
|
+
*/
|
|
654
|
+
number(num) {
|
|
655
|
+
num = resolveFunc(num);
|
|
656
|
+
if (isNull(num)) {
|
|
657
|
+
return 'null';
|
|
658
|
+
}
|
|
659
|
+
const t = typeof num;
|
|
660
|
+
if (t !== 'number' && t !== 'bigint') {
|
|
661
|
+
throw new TypeError(`${wrapText(num)} is not a number.`);
|
|
662
|
+
}
|
|
663
|
+
return $to.number(num);
|
|
664
|
+
},
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* @method formatting.array
|
|
668
|
+
* @description
|
|
669
|
+
* Converts an array of values into its PostgreSQL presentation as an Array-Type constructor string: `array[]`.
|
|
670
|
+
*
|
|
671
|
+
* Top-level empty arrays are formatted as literal `{}`, to avoid the necessity of explicit type casting,
|
|
672
|
+
* as the server cannot automatically infer type of empty non-literal array.
|
|
673
|
+
*
|
|
674
|
+
* @param {Array|function} arr
|
|
675
|
+
* Array to be converted, or a function that returns one.
|
|
676
|
+
*
|
|
677
|
+
* @param {{}} [options]
|
|
678
|
+
* Array-Formatting Options.
|
|
679
|
+
*
|
|
680
|
+
* @param {boolean} [options.capSQL=false]
|
|
681
|
+
* When `true`, outputs `ARRAY` instead of `array`.
|
|
682
|
+
*
|
|
683
|
+
* @returns {string}
|
|
684
|
+
*/
|
|
685
|
+
array(arr, options) {
|
|
686
|
+
options = assert(options, ['capSQL']);
|
|
687
|
+
arr = resolveFunc(arr);
|
|
688
|
+
if (isNull(arr)) {
|
|
689
|
+
return 'null';
|
|
690
|
+
}
|
|
691
|
+
if (Array.isArray(arr)) {
|
|
692
|
+
return $to.array(arr, options);
|
|
693
|
+
}
|
|
694
|
+
throw new TypeError(`${wrapText(arr)} is not an Array object.`);
|
|
695
|
+
},
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* @method formatting.csv
|
|
699
|
+
* @description
|
|
700
|
+
* Converts a single value or an array of values into a CSV (comma-separated values) string, with all values formatted
|
|
701
|
+
* according to their JavaScript type.
|
|
702
|
+
*
|
|
703
|
+
* When formatting a query, a variable makes use of this method via modifier `:csv` or its alias `:list`.
|
|
704
|
+
*
|
|
705
|
+
* When `values` is an object that's not `null` or `Array`, its properties are enumerated for the actual values.
|
|
706
|
+
*
|
|
707
|
+
* @param {Array|Object|value|function} values
|
|
708
|
+
* Value(s) to be converted, or a function that returns it.
|
|
709
|
+
*
|
|
710
|
+
* @returns {string}
|
|
711
|
+
*
|
|
712
|
+
* @see {@link formatting.format format}
|
|
713
|
+
*/
|
|
714
|
+
csv(values) {
|
|
715
|
+
return $to.csv(values);
|
|
716
|
+
},
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* @method formatting.json
|
|
720
|
+
* @description
|
|
721
|
+
* Converts any value into JSON (includes `BigInt` support), and returns it as a valid string,
|
|
722
|
+
* with single-quote symbols fixed, unless flag `raw` is set.
|
|
723
|
+
*
|
|
724
|
+
* When formatting a query, a variable makes use of this method via modifier `:json`. See method {@link formatting.format format}.
|
|
725
|
+
*
|
|
726
|
+
* @param {*} data
|
|
727
|
+
* Object/value to be converted, or a function that returns it.
|
|
728
|
+
*
|
|
729
|
+
* @param {boolean} [raw=false]
|
|
730
|
+
* Indicates when not to escape the result.
|
|
731
|
+
*
|
|
732
|
+
* @returns {string}
|
|
733
|
+
*
|
|
734
|
+
* @see {@link formatting.format format}
|
|
735
|
+
*/
|
|
736
|
+
json(data, raw) {
|
|
737
|
+
data = resolveFunc(data);
|
|
738
|
+
if (isNull(data)) {
|
|
739
|
+
throwIfRaw(raw);
|
|
740
|
+
return 'null';
|
|
741
|
+
}
|
|
742
|
+
return $to.json(data, raw);
|
|
743
|
+
},
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* @method formatting.func
|
|
747
|
+
* @description
|
|
748
|
+
* Calls the function to get the actual value, and then formats the result according to its type + `raw` flag.
|
|
749
|
+
*
|
|
750
|
+
* @param {function} func
|
|
751
|
+
* Function to be called, with support for nesting.
|
|
752
|
+
*
|
|
753
|
+
* @param {boolean} [raw=false]
|
|
754
|
+
* Indicates when not to escape the result.
|
|
755
|
+
*
|
|
756
|
+
* @param {*} [cc]
|
|
757
|
+
* Calling Context: `this` + the only value to be passed into the function on all nested levels.
|
|
758
|
+
*
|
|
759
|
+
* @returns {string}
|
|
760
|
+
*/
|
|
761
|
+
func(func, raw, cc) {
|
|
762
|
+
if (isNull(func)) {
|
|
763
|
+
throwIfRaw(raw);
|
|
764
|
+
return 'null';
|
|
765
|
+
}
|
|
766
|
+
if (typeof func !== 'function') {
|
|
767
|
+
throw new TypeError(`${wrapText(func)} is not a function.`);
|
|
768
|
+
}
|
|
769
|
+
const fm = raw ? fmFlags.raw : null;
|
|
770
|
+
return formatValue({value: resolveFunc(func, cc), fm, cc});
|
|
771
|
+
},
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* @method formatting.format
|
|
775
|
+
* @description
|
|
776
|
+
* Replaces variables in a string according to the type of `values`:
|
|
777
|
+
*
|
|
778
|
+
* - Replaces `$1` occurrences when `values` is of type `string`, `boolean`, `number`, `bigint`, `Date`, `Buffer` or when it is `null`.
|
|
779
|
+
*
|
|
780
|
+
* - Replaces variables `$1`, `$2`, ...`$100000` when `values` is an array of parameters. It throws a {@link external:RangeError RangeError}
|
|
781
|
+
* when the values or variables are out of range.
|
|
782
|
+
*
|
|
783
|
+
* - Replaces `$*propName*`, where `*` is any of `{}`, `()`, `[]`, `<>`, `//`, when `values` is an object that's not a
|
|
784
|
+
* `Date`, `Buffer`, {@link QueryFile} or `null`. Special property name `this` refers to the formatting object itself,
|
|
785
|
+
* to be injected as a JSON string. When referencing a property that doesn't exist in the formatting object, it throws
|
|
786
|
+
* {@link external:Error Error} = `Property 'PropName' doesn't exist`, unless option `partial` is used.
|
|
787
|
+
*
|
|
788
|
+
* - Supports $[Nested Named Parameters] of any depth.
|
|
789
|
+
*
|
|
790
|
+
* By default, each variable is automatically formatted according to its type, unless it is a special variable:
|
|
791
|
+
*
|
|
792
|
+
* - Raw-text variables end with `:raw` or symbol `^`, and prevent escaping the text. Such variables are not
|
|
793
|
+
* allowed to be `null` or `undefined`, or the method will throw {@link external:TypeError TypeError} = `Values null/undefined cannot be used as raw text.`
|
|
794
|
+
* - `$1:raw`, `$2:raw`,..., and `$*propName:raw*` (see `*` above)
|
|
795
|
+
* - `$1^`, `$2^`,..., and `$*propName^*` (see `*` above)
|
|
796
|
+
*
|
|
797
|
+
* - Open-value variables end with `:value` or symbol `#`, to be escaped, but not wrapped in quotes. Such variables are
|
|
798
|
+
* not allowed to be `null` or `undefined`, or the method will throw {@link external:TypeError TypeError} = `Open values cannot be null or undefined.`
|
|
799
|
+
* - `$1:value`, `$2:value`,..., and `$*propName:value*` (see `*` above)
|
|
800
|
+
* - `$1#`, `$2#`,..., and `$*propName#*` (see `*` above)
|
|
801
|
+
*
|
|
802
|
+
* - SQL name variables end with `:name` or symbol `~` (tilde), and provide proper escaping for SQL names/identifiers:
|
|
803
|
+
* - `$1:name`, `$2:name`,..., and `$*propName:name*` (see `*` above)
|
|
804
|
+
* - `$1~`, `$2~`,..., and `$*propName~*` (see `*` above)
|
|
805
|
+
*
|
|
806
|
+
* - Modifier `:alias` - non-verbose $[SQL Names] escaping.
|
|
807
|
+
*
|
|
808
|
+
* - JSON override ends with `:json` to format the value of any type as a JSON string
|
|
809
|
+
*
|
|
810
|
+
* - CSV override ends with `:csv` or `:list` to format an array as a properly escaped comma-separated list of values.
|
|
811
|
+
*
|
|
812
|
+
* @param {string|QueryFile|object} query
|
|
813
|
+
* A query string, a {@link QueryFile} or any object that implements $[Custom Type Formatting], to be formatted according to `values`.
|
|
814
|
+
*
|
|
815
|
+
* @param {array|object|value} [values]
|
|
816
|
+
* Formatting parameter(s) / variable value(s).
|
|
817
|
+
*
|
|
818
|
+
* @param {{}} [options]
|
|
819
|
+
* Formatting Options.
|
|
820
|
+
*
|
|
821
|
+
* @param {boolean} [options.capSQL=false]
|
|
822
|
+
* Formats reserved SQL words capitalized. Presently, this only concerns arrays, to output `ARRAY` when required.
|
|
823
|
+
*
|
|
824
|
+
* @param {boolean} [options.partial=false]
|
|
825
|
+
* Indicates that we intend to do only a partial replacement, i.e. throw no error when encountering a variable or
|
|
826
|
+
* property name that's missing within the formatting parameters.
|
|
827
|
+
*
|
|
828
|
+
* **NOTE:** This option has no meaning when option `def` is used.
|
|
829
|
+
*
|
|
830
|
+
* @param {*} [options.def]
|
|
831
|
+
* Sets default value for every variable that's missing, consequently preventing errors when encountering a variable
|
|
832
|
+
* or property name that's missing within the formatting parameters.
|
|
833
|
+
*
|
|
834
|
+
* It can also be set to a function, to be called with two parameters that depend on the type of formatting being used,
|
|
835
|
+
* and to return the actual default value:
|
|
836
|
+
*
|
|
837
|
+
* - For $[Named Parameters] formatting:
|
|
838
|
+
* - `name` - name of the property missing in the formatting object
|
|
839
|
+
* - `obj` - the formatting object, and is the same as `this` context
|
|
840
|
+
*
|
|
841
|
+
* - For $[Index Variables] formatting:
|
|
842
|
+
* - `index` - element's index (starts with 1) that's outside the input array
|
|
843
|
+
* - `arr` - the formatting/input array, and is the same as `this` context
|
|
844
|
+
*
|
|
845
|
+
* You can tell which type of call it is by checking the type of the first parameter.
|
|
846
|
+
*
|
|
847
|
+
* @returns {string}
|
|
848
|
+
* Formatted query string.
|
|
849
|
+
*
|
|
850
|
+
* The function will throw an error, if any occurs during formatting.
|
|
851
|
+
*/
|
|
852
|
+
format(query, values, options) {
|
|
853
|
+
options = assert(options, ['capSQL', 'partial', 'def']);
|
|
854
|
+
const ctf = getCTF(query);
|
|
855
|
+
if (ctf) {
|
|
856
|
+
query = ctf.toPostgres.call(query, query);
|
|
857
|
+
}
|
|
858
|
+
return formatQuery(query, values, false, options);
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
/* Pre-parsed type formatting */
|
|
863
|
+
const $to = {
|
|
864
|
+
array(arr, options) {
|
|
865
|
+
return formatArray(arr, options);
|
|
866
|
+
},
|
|
867
|
+
csv(values, options) {
|
|
868
|
+
return formatCSV(resolveFunc(values), options);
|
|
869
|
+
},
|
|
870
|
+
bool(value) {
|
|
871
|
+
return value ? 'true' : 'false';
|
|
872
|
+
},
|
|
873
|
+
buffer(obj, raw) {
|
|
874
|
+
const s = `\\x${obj.toString('hex')}`;
|
|
875
|
+
return raw ? s : wrapText(s);
|
|
876
|
+
},
|
|
877
|
+
date(d, raw) {
|
|
878
|
+
const s = npm.pgUtils.prepareValue(d);
|
|
879
|
+
return raw ? s : wrapText(s);
|
|
880
|
+
},
|
|
881
|
+
json(data, raw) {
|
|
882
|
+
const s = npm.utils.toJson(data);
|
|
883
|
+
return raw ? s : wrapText(safeText(s));
|
|
884
|
+
},
|
|
885
|
+
number(num) {
|
|
886
|
+
if (typeof num === 'bigint' || Number.isFinite(num)) {
|
|
887
|
+
const s = num.toString();
|
|
888
|
+
return num < 0 ? `(${s})` : s;
|
|
889
|
+
}
|
|
890
|
+
// Converting NaN/+Infinity/-Infinity according to Postgres documentation:
|
|
891
|
+
// https://www.postgresql.org/docs/17/datatype-numeric.html#DATATYPE-FLOAT
|
|
892
|
+
//
|
|
893
|
+
// NOTE: strings for 'NaN'/'+Infinity'/'-Infinity' are not case-sensitive.
|
|
894
|
+
if (num === Number.POSITIVE_INFINITY) {
|
|
895
|
+
return wrapText('+Infinity');
|
|
896
|
+
}
|
|
897
|
+
if (num === Number.NEGATIVE_INFINITY) {
|
|
898
|
+
return wrapText('-Infinity');
|
|
899
|
+
}
|
|
900
|
+
return wrapText('NaN');
|
|
901
|
+
},
|
|
902
|
+
text(value, raw) {
|
|
903
|
+
return raw ? value : wrapText(safeText(value));
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
|
|
907
|
+
module.exports = {
|
|
908
|
+
formatQuery,
|
|
909
|
+
formatEntity,
|
|
910
|
+
resolveFunc,
|
|
911
|
+
as: $as
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* @external Error
|
|
916
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
|
|
917
|
+
*/
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* @external TypeError
|
|
921
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError
|
|
922
|
+
*/
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* @external RangeError
|
|
926
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError
|
|
927
|
+
*/
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* @external Symbol
|
|
931
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
|
|
932
|
+
*/
|