@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,298 @@
|
|
|
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 {ServerFormatting} = require('./server-formatting');
|
|
11
|
+
const {PreparedStatementError} = require('../errors');
|
|
12
|
+
const {QueryFile} = require('../query-file');
|
|
13
|
+
const {assert} = require('../assert');
|
|
14
|
+
|
|
15
|
+
const npm = {
|
|
16
|
+
EOL: require('os').EOL,
|
|
17
|
+
utils: require('../utils'),
|
|
18
|
+
inspect: require('util').inspect
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @class PreparedStatement
|
|
23
|
+
* @description
|
|
24
|
+
* Constructs a new $[Prepared Statement] object. All properties can also be set after the object's construction.
|
|
25
|
+
*
|
|
26
|
+
* This type extends the basic `{name, text, values}` object, i.e. when the basic object is used
|
|
27
|
+
* with a query method, a new {@link PreparedStatement} object is created in its place.
|
|
28
|
+
*
|
|
29
|
+
* The type can be used in place of the `query` parameter, with any query method directly.
|
|
30
|
+
*
|
|
31
|
+
* The type is available from the library's root: `pgp.PreparedStatement`.
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} [options]
|
|
34
|
+
* Object configuration options / properties.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} [options.name] - See property {@link PreparedStatement#name name}.
|
|
37
|
+
* @param {string|QueryFile} [options.text] - See property {@link PreparedStatement#text text}.
|
|
38
|
+
* @param {array} [options.values] - See property {@link PreparedStatement#values values}.
|
|
39
|
+
* @param {boolean} [options.binary] - See property {@link PreparedStatement#binary binary}.
|
|
40
|
+
* @param {string} [options.rowMode] - See property {@link PreparedStatement#rowMode rowMode}.
|
|
41
|
+
* @param {number} [options.rows] - See property {@link PreparedStatement#rows rows}.
|
|
42
|
+
* @param {ITypes} [options.types] - See property {@link PreparedStatement#types types}.
|
|
43
|
+
*
|
|
44
|
+
* @returns {PreparedStatement}
|
|
45
|
+
*
|
|
46
|
+
* @see
|
|
47
|
+
* {@link errors.PreparedStatementError PreparedStatementError},
|
|
48
|
+
* {@link https://www.postgresql.org/docs/17/sql-prepare.html PostgreSQL Prepared Statements}
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
*
|
|
52
|
+
* const {PreparedStatement: PS} = require('pg-promise');
|
|
53
|
+
*
|
|
54
|
+
* // Creating a complete Prepared Statement with parameters:
|
|
55
|
+
* const findUser = new PS({name: 'find-user', text: 'SELECT * FROM Users WHERE id = $1', values: [123]});
|
|
56
|
+
*
|
|
57
|
+
* db.one(findUser)
|
|
58
|
+
* .then(user => {
|
|
59
|
+
* // user found;
|
|
60
|
+
* })
|
|
61
|
+
* .catch(error => {
|
|
62
|
+
* // error;
|
|
63
|
+
* });
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
*
|
|
67
|
+
* const {PreparedStatement: PS} = require('pg-promise');
|
|
68
|
+
*
|
|
69
|
+
* // Creating a reusable Prepared Statement without values:
|
|
70
|
+
* const addUser = new PS({name: 'add-user', text: 'INSERT INTO Users(name, age) VALUES($1, $2)'});
|
|
71
|
+
*
|
|
72
|
+
* // setting values explicitly:
|
|
73
|
+
* addUser.values = ['John', 30];
|
|
74
|
+
*
|
|
75
|
+
* db.none(addUser)
|
|
76
|
+
* .then(() => {
|
|
77
|
+
* // user added;
|
|
78
|
+
* })
|
|
79
|
+
* .catch(error => {
|
|
80
|
+
* // error;
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* // setting values implicitly, by passing them into the query method:
|
|
84
|
+
* db.none(addUser, ['Mike', 25])
|
|
85
|
+
* .then(() => {
|
|
86
|
+
* // user added;
|
|
87
|
+
* })
|
|
88
|
+
* .catch(error => {
|
|
89
|
+
* // error;
|
|
90
|
+
* });
|
|
91
|
+
*/
|
|
92
|
+
class PreparedStatement extends ServerFormatting {
|
|
93
|
+
constructor(options) {
|
|
94
|
+
options = assert(options, ['name', 'text', 'values', 'binary', 'rowMode', 'rows', 'types']);
|
|
95
|
+
super(options);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @name PreparedStatement#name
|
|
100
|
+
* @type {string}
|
|
101
|
+
* @description
|
|
102
|
+
* An arbitrary name given to this particular prepared statement. It must be unique within a single session and is
|
|
103
|
+
* subsequently used to execute or deallocate a previously prepared statement.
|
|
104
|
+
*/
|
|
105
|
+
get name() {
|
|
106
|
+
return this._inner.options.name;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
set name(value) {
|
|
110
|
+
const _i = this._inner;
|
|
111
|
+
if (value !== _i.options.name) {
|
|
112
|
+
_i.options.name = value;
|
|
113
|
+
_i.changed = true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @name PreparedStatement#rows
|
|
119
|
+
* @type {number}
|
|
120
|
+
* @description
|
|
121
|
+
* Number of rows to return at a time from a Prepared Statement's portal.
|
|
122
|
+
* The default is 0, which means that all rows must be returned at once.
|
|
123
|
+
*/
|
|
124
|
+
get rows() {
|
|
125
|
+
return this._inner.options.rows;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
set rows(value) {
|
|
129
|
+
const _i = this._inner;
|
|
130
|
+
if (value !== _i.options.rows) {
|
|
131
|
+
_i.options.rows = value;
|
|
132
|
+
_i.changed = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @method PreparedStatement#parse
|
|
139
|
+
* @description
|
|
140
|
+
* Parses the current object and returns a simple `{name, text, values}`, if successful,
|
|
141
|
+
* or else it returns a {@link errors.PreparedStatementError PreparedStatementError} object.
|
|
142
|
+
*
|
|
143
|
+
* This method is primarily for internal use by the library.
|
|
144
|
+
*
|
|
145
|
+
* @returns {{name, text, values}|errors.PreparedStatementError}
|
|
146
|
+
*/
|
|
147
|
+
PreparedStatement.prototype.parse = function () {
|
|
148
|
+
|
|
149
|
+
const _i = this._inner, options = _i.options;
|
|
150
|
+
|
|
151
|
+
const qf = options.text instanceof QueryFile ? options.text : null;
|
|
152
|
+
|
|
153
|
+
if (!_i.changed && !qf) {
|
|
154
|
+
return _i.target;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const errors = [], values = _i.target.values;
|
|
158
|
+
_i.target = {
|
|
159
|
+
name: options.name,
|
|
160
|
+
text: options.text
|
|
161
|
+
};
|
|
162
|
+
_i.changed = true;
|
|
163
|
+
_i.currentError = undefined;
|
|
164
|
+
|
|
165
|
+
if (!npm.utils.isText(_i.target.name)) {
|
|
166
|
+
errors.push('Property \'name\' must be a non-empty text string.');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (qf) {
|
|
170
|
+
qf.prepare();
|
|
171
|
+
if (qf.error) {
|
|
172
|
+
errors.push(qf.error);
|
|
173
|
+
} else {
|
|
174
|
+
_i.target.text = qf[QueryFile.$query];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!npm.utils.isText(_i.target.text)) {
|
|
178
|
+
errors.push('Property \'text\' must be a non-empty text string.');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!npm.utils.isNull(values)) {
|
|
182
|
+
_i.target.values = values;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (options.binary !== undefined) {
|
|
186
|
+
_i.target.binary = !!options.binary;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (options.rowMode !== undefined) {
|
|
190
|
+
_i.target.rowMode = options.rowMode;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (options.rows !== undefined) {
|
|
194
|
+
_i.target.rows = options.rows;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (options.types !== undefined) {
|
|
198
|
+
_i.target.types = options.types;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (errors.length) {
|
|
202
|
+
return _i.currentError = new PreparedStatementError(errors[0], _i.target);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
_i.changed = false;
|
|
206
|
+
|
|
207
|
+
return _i.target;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
npm.utils.addInspection(PreparedStatement, function () {
|
|
211
|
+
const pq = this.parse();
|
|
212
|
+
const obj = {
|
|
213
|
+
name: this.name
|
|
214
|
+
};
|
|
215
|
+
if (npm.utils.isText(pq.text)) {
|
|
216
|
+
obj.text = pq.text;
|
|
217
|
+
}
|
|
218
|
+
if (this.values !== undefined) {
|
|
219
|
+
obj.values = this.values;
|
|
220
|
+
}
|
|
221
|
+
if (this.binary !== undefined) {
|
|
222
|
+
obj.binary = this.binary;
|
|
223
|
+
}
|
|
224
|
+
if (this.rowMode !== undefined) {
|
|
225
|
+
obj.rowMode = this.rowMode;
|
|
226
|
+
}
|
|
227
|
+
if (this.rows !== undefined) {
|
|
228
|
+
obj.rows = this.rows;
|
|
229
|
+
}
|
|
230
|
+
if (this.error !== undefined) {
|
|
231
|
+
obj.error = this.error.message;
|
|
232
|
+
}
|
|
233
|
+
return 'PreparedStatement ' + npm.inspect(obj, {breakLength: 100, depth: 5, colors: true});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
module.exports = {PreparedStatement};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* @name PreparedStatement#text
|
|
240
|
+
* @type {string|QueryFile}
|
|
241
|
+
* @description
|
|
242
|
+
* A non-empty query string or a {@link QueryFile} object.
|
|
243
|
+
*
|
|
244
|
+
* Only the basic variables (`$1`, `$2`, etc) can be used in the query, because $[Prepared Statements]
|
|
245
|
+
* are formatted on the server side.
|
|
246
|
+
*
|
|
247
|
+
* Changing this property for the same {@link PreparedStatement#name name} will have no effect, because queries
|
|
248
|
+
* for Prepared Statements are cached by the server, with {@link PreparedStatement#name name} being the cache key.
|
|
249
|
+
*/
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @name PreparedStatement#values
|
|
253
|
+
* @type {array}
|
|
254
|
+
* @description
|
|
255
|
+
* Query formatting parameters, depending on the type:
|
|
256
|
+
*
|
|
257
|
+
* - `null` / `undefined` means the query has no formatting parameters
|
|
258
|
+
* - `Array` - it is an array of formatting parameters
|
|
259
|
+
* - None of the above, means it is a single formatting value, which
|
|
260
|
+
* is then automatically wrapped into an array
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @name PreparedStatement#binary
|
|
265
|
+
* @type {boolean}
|
|
266
|
+
* @default undefined
|
|
267
|
+
* @description
|
|
268
|
+
* Activates binary result mode. The default is the text mode.
|
|
269
|
+
*
|
|
270
|
+
* @see {@link http://www.postgresql.org/docs/devel/static/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY Extended Query}
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* @name PreparedStatement#rowMode
|
|
275
|
+
* @type {string}
|
|
276
|
+
* @default undefined
|
|
277
|
+
* @description
|
|
278
|
+
* Changes the way data arrives to the client, with only one value supported by $[pg]:
|
|
279
|
+
* - `array` will make all data rows arrive as arrays of values. By default, rows arrive as objects.
|
|
280
|
+
*/
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @name PreparedStatement#types
|
|
284
|
+
* @type {ITypes}
|
|
285
|
+
* @default undefined
|
|
286
|
+
* @description
|
|
287
|
+
* Custom type parsers just for this query result.
|
|
288
|
+
*/
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @name PreparedStatement#error
|
|
292
|
+
* @type {errors.PreparedStatementError}
|
|
293
|
+
* @default undefined
|
|
294
|
+
* @description
|
|
295
|
+
* When in an error state, it is set to a {@link errors.PreparedStatementError PreparedStatementError} object. Otherwise, it is `undefined`.
|
|
296
|
+
*
|
|
297
|
+
* This property is primarily for internal use by the library.
|
|
298
|
+
*/
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const {InnerState} = require('../inner-state');
|
|
2
|
+
const utils = require('../utils');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @private
|
|
6
|
+
* @class ServerFormatting
|
|
7
|
+
*/
|
|
8
|
+
class ServerFormatting extends InnerState {
|
|
9
|
+
|
|
10
|
+
constructor(options) {
|
|
11
|
+
const _inner = {
|
|
12
|
+
options,
|
|
13
|
+
changed: true,
|
|
14
|
+
currentError: undefined,
|
|
15
|
+
target: {}
|
|
16
|
+
};
|
|
17
|
+
super(_inner);
|
|
18
|
+
setValues.call(this, options.values);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get error() {
|
|
22
|
+
return this._inner.currentError;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get text() {
|
|
26
|
+
return this._inner.options.text;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
set text(value) {
|
|
30
|
+
const _i = this._inner;
|
|
31
|
+
if (value !== _i.options.text) {
|
|
32
|
+
_i.options.text = value;
|
|
33
|
+
_i.changed = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get binary() {
|
|
38
|
+
return this._inner.options.binary;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
set binary(value) {
|
|
42
|
+
const _i = this._inner;
|
|
43
|
+
if (value !== _i.options.binary) {
|
|
44
|
+
_i.options.binary = value;
|
|
45
|
+
_i.changed = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get rowMode() {
|
|
50
|
+
return this._inner.options.rowMode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
set rowMode(value) {
|
|
54
|
+
const _i = this._inner;
|
|
55
|
+
if (value !== _i.options.rowMode) {
|
|
56
|
+
_i.options.rowMode = value;
|
|
57
|
+
_i.changed = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get values() {
|
|
62
|
+
return this._inner.target.values;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
set values(values) {
|
|
66
|
+
setValues.call(this, values);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @member ServerFormatting#parse
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
function setValues(v) {
|
|
76
|
+
const target = this._inner.target;
|
|
77
|
+
if (Array.isArray(v)) {
|
|
78
|
+
if (v.length) {
|
|
79
|
+
target.values = v;
|
|
80
|
+
} else {
|
|
81
|
+
delete target.values;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
if (utils.isNull(v)) {
|
|
85
|
+
delete target.values;
|
|
86
|
+
} else {
|
|
87
|
+
target.values = [v];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {ServerFormatting};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### `utils` namespace
|
|
2
|
+
|
|
3
|
+
This folder contains everything that's available via the [utils] namespace, before and after initialization:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
const pgpLib = require('pg-promise');
|
|
7
|
+
const pgp = pgpLib(/*initialization options*/);
|
|
8
|
+
|
|
9
|
+
pgpLib.utils; // `utils` namespace
|
|
10
|
+
pgp.utils; // `utils` namespace
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
[utils]:http://vitaly-t.github.io/pg-promise/utils.html
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const {format} = require('util');
|
|
2
|
+
|
|
3
|
+
class ColorConsole {
|
|
4
|
+
|
|
5
|
+
static log() {
|
|
6
|
+
ColorConsole.writeNormal([...arguments], 39); // white
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static info() {
|
|
10
|
+
ColorConsole.writeNormal([...arguments], 36); // cyan
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static success() {
|
|
14
|
+
ColorConsole.writeNormal([...arguments], 32); // green
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static warn() {
|
|
18
|
+
ColorConsole.writeNormal([...arguments], 33); // yellow
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static error() {
|
|
22
|
+
ColorConsole.writeError([...arguments], 31); // red
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static writeNormal(params, color) {
|
|
26
|
+
// istanbul ignore else
|
|
27
|
+
if (process.stdout.isTTY) {
|
|
28
|
+
console.log.apply(null, ColorConsole.formatColor(params, color)); // eslint-disable-line no-console
|
|
29
|
+
} else {
|
|
30
|
+
console.log.apply(null, params); // eslint-disable-line no-console
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static writeError(params, color) {
|
|
35
|
+
// istanbul ignore else
|
|
36
|
+
if (process.stderr.isTTY) {
|
|
37
|
+
console.error.apply(null, ColorConsole.formatColor(params, color)); // eslint-disable-line no-console
|
|
38
|
+
} else {
|
|
39
|
+
console.error.apply(null, params); // eslint-disable-line no-console
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static formatColor(args, color) {
|
|
44
|
+
return args.map(a => `\x1b[${color}m${format(a)}\x1b[0m`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
ColorConsole.log.bright = function () {
|
|
49
|
+
ColorConsole.writeNormal([...arguments], 97); // light white
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
ColorConsole.info.bright = function () {
|
|
53
|
+
ColorConsole.writeNormal([...arguments], 93); // light cyan
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
ColorConsole.success.bright = function () {
|
|
57
|
+
ColorConsole.writeNormal([...arguments], 92); // light green
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
ColorConsole.warn.bright = function () {
|
|
61
|
+
ColorConsole.writeNormal([...arguments], 93); // light yellow
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
ColorConsole.error.bright = function () {
|
|
65
|
+
ColorConsole.writeError([...arguments], 91); // light red
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
module.exports = {ColorConsole};
|
|
@@ -0,0 +1,199 @@
|
|
|
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 npm = {
|
|
11
|
+
path: require('path'),
|
|
12
|
+
util: require('util'),
|
|
13
|
+
patterns: require('../patterns')
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
////////////////////////////////////////////
|
|
17
|
+
// Simpler check for null/undefined;
|
|
18
|
+
function isNull(value) {
|
|
19
|
+
return value === null || value === undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
////////////////////////////////////////////////////////
|
|
23
|
+
// Verifies parameter for being a non-empty text string;
|
|
24
|
+
function isText(txt) {
|
|
25
|
+
return txt && typeof txt === 'string' && /\S/.test(txt);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
///////////////////////////////////////////////////////////
|
|
29
|
+
// Approximates the environment as being for development.
|
|
30
|
+
//
|
|
31
|
+
// Proper configuration is having NODE_ENV = 'development', but this
|
|
32
|
+
// method only checks for 'dev' being present, and regardless of the case.
|
|
33
|
+
function isDev() {
|
|
34
|
+
const env = process.env.NODE_ENV || '';
|
|
35
|
+
return env.toLowerCase().indexOf('dev') !== -1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/////////////////////////////////////////////
|
|
39
|
+
// Adds properties from source to the target,
|
|
40
|
+
// making them read-only and enumerable.
|
|
41
|
+
function addReadProperties(target, source) {
|
|
42
|
+
for (const p in source) {
|
|
43
|
+
addReadProp(target, p, source[p]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
///////////////////////////////////////////////////////
|
|
48
|
+
// Adds a read-only, non-deletable enumerable property.
|
|
49
|
+
function addReadProp(obj, name, value, hidden) {
|
|
50
|
+
Object.defineProperty(obj, name, {
|
|
51
|
+
value,
|
|
52
|
+
configurable: false,
|
|
53
|
+
enumerable: !hidden,
|
|
54
|
+
writable: false
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//////////////////////////////////////////////////////////////
|
|
59
|
+
// Converts a connection string or object into its safe copy:
|
|
60
|
+
// if a password is present, it is masked with the symbol '#'.
|
|
61
|
+
function getSafeConnection(cn) {
|
|
62
|
+
const maskPassword = cs => cs.replace(/:(?![/])([^@]+)/, (_, m) => ':' + new Array(m.length + 1).join('#'));
|
|
63
|
+
if (typeof cn === 'object') {
|
|
64
|
+
const copy = {...cn};
|
|
65
|
+
if (typeof copy.password === 'string') {
|
|
66
|
+
copy.password = copy.password.replace(/./g, '#');
|
|
67
|
+
}
|
|
68
|
+
if (typeof copy.connectionString === 'string') {
|
|
69
|
+
copy.connectionString = maskPassword(copy.connectionString);
|
|
70
|
+
}
|
|
71
|
+
return copy;
|
|
72
|
+
}
|
|
73
|
+
return maskPassword(cn);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/////////////////////////////////////////
|
|
77
|
+
// Provides platform-neutral inheritance;
|
|
78
|
+
function inherits(child, parent) {
|
|
79
|
+
child.prototype.__proto__ = parent.prototype;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// istanbul ignore next
|
|
83
|
+
function getLocalStack(startIdx, maxLines) {
|
|
84
|
+
// from the call stack, we take up to maximum lines,
|
|
85
|
+
// starting with the specified line index:
|
|
86
|
+
startIdx = startIdx || 0;
|
|
87
|
+
const endIdx = maxLines > 0 ? startIdx + maxLines : undefined;
|
|
88
|
+
return new Error().stack
|
|
89
|
+
.split('\n')
|
|
90
|
+
.filter(line => line.match(/\(.+\)/))
|
|
91
|
+
.slice(startIdx, endIdx)
|
|
92
|
+
.join('\n');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//////////////////////////////
|
|
96
|
+
// Internal error container;
|
|
97
|
+
function InternalError(error) {
|
|
98
|
+
this.error = error;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/////////////////////////////////////////////////////////////////
|
|
102
|
+
// Parses a property name and gets its name from the object
|
|
103
|
+
// if the property exists. Returns an object {valid, has, target, value}:
|
|
104
|
+
// - valid - true/false, whether the syntax is valid
|
|
105
|
+
// - has - a flag that property exists; set when 'valid' = true
|
|
106
|
+
// - target - the target object that contains the property; set when 'has' = true
|
|
107
|
+
// - value - the value; set when 'has' = true
|
|
108
|
+
function getIfHas(obj, prop) {
|
|
109
|
+
const result = {valid: true};
|
|
110
|
+
if (prop.indexOf('.') === -1) {
|
|
111
|
+
result.has = prop in obj;
|
|
112
|
+
result.target = obj;
|
|
113
|
+
if (result.has) {
|
|
114
|
+
result.value = obj[prop];
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
const names = prop.split('.');
|
|
118
|
+
let missing, target;
|
|
119
|
+
for (let i = 0; i < names.length; i++) {
|
|
120
|
+
const n = names[i];
|
|
121
|
+
if (!n) {
|
|
122
|
+
result.valid = false;
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
if (!missing && hasProperty(obj, n)) {
|
|
126
|
+
target = obj;
|
|
127
|
+
obj = obj[n];
|
|
128
|
+
} else {
|
|
129
|
+
missing = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
result.has = !missing;
|
|
133
|
+
if (result.has) {
|
|
134
|
+
result.target = target;
|
|
135
|
+
result.value = obj;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/////////////////////////////////////////////////////////////////////////
|
|
142
|
+
// Checks if the property exists in the object or value or its prototype;
|
|
143
|
+
function hasProperty(value, prop) {
|
|
144
|
+
return (value && typeof value === 'object' && prop in value) ||
|
|
145
|
+
value !== null && value !== undefined && value[prop] !== undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
////////////////////////////////////////////////////////
|
|
149
|
+
// Adds prototype inspection
|
|
150
|
+
function addInspection(type, cb) {
|
|
151
|
+
type.prototype[npm.util.inspect.custom] = cb;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/////////////////////////////////////////////////////////////////////////////////////////
|
|
155
|
+
// Identifies a general connectivity error, after which no more queries can be executed.
|
|
156
|
+
// This is for detecting when to skip executing ROLLBACK for a failed transaction.
|
|
157
|
+
function isConnectivityError(err) {
|
|
158
|
+
const code = err && typeof err.code === 'string' && err.code;
|
|
159
|
+
const cls = code && code.substring(0, 2); // Error Class
|
|
160
|
+
// istanbul ignore next (we cannot test-cover all error cases):
|
|
161
|
+
return code === 'ECONNRESET' || (cls === '08' && code !== '08P01') || (cls === '57' && code !== '57014');
|
|
162
|
+
// Code 'ECONNRESET' - Connectivity issue handled by the driver.
|
|
163
|
+
// Class 08 - Connection Exception (except for 08P01, for protocol violation).
|
|
164
|
+
// Class 57 - Operator Intervention (except for 57014, for cancelled queries).
|
|
165
|
+
//
|
|
166
|
+
// ERROR CODES: https://www.postgresql.org/docs/17/errcodes-appendix.html
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
///////////////////////////////////////////////////////////////
|
|
170
|
+
// Does JSON.stringify, with support for BigInt (irreversible)
|
|
171
|
+
function toJson(data) {
|
|
172
|
+
if (data !== undefined) {
|
|
173
|
+
return JSON.stringify(data, (_, v) => typeof v === 'bigint' ? `${v}#bigint` : v)
|
|
174
|
+
.replace(/"(-?\d+)#bigint"/g, (_, a) => a);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const exp = {
|
|
179
|
+
toJson,
|
|
180
|
+
getIfHas,
|
|
181
|
+
addInspection,
|
|
182
|
+
InternalError,
|
|
183
|
+
getLocalStack,
|
|
184
|
+
isText,
|
|
185
|
+
isNull,
|
|
186
|
+
isDev,
|
|
187
|
+
addReadProp,
|
|
188
|
+
addReadProperties,
|
|
189
|
+
getSafeConnection,
|
|
190
|
+
inherits,
|
|
191
|
+
isConnectivityError
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const mainFile = process.argv[1];
|
|
195
|
+
|
|
196
|
+
// istanbul ignore next
|
|
197
|
+
exp.startDir = mainFile ? npm.path.dirname(mainFile) : process.cwd();
|
|
198
|
+
|
|
199
|
+
module.exports = exp;
|