@trenskow/pged 4.0.9 → 4.1.2
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/index.js +4 -21
- package/package.json +3 -3
- package/query-builder.js +82 -15
package/index.js
CHANGED
|
@@ -89,7 +89,8 @@ module.exports = exports = class PGed {
|
|
|
89
89
|
return result;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
_convertResult(result) {
|
|
92
|
+
_convertResult(result, options) {
|
|
93
|
+
if ((options || {}).format === 'raw') return (result || {}).rows;
|
|
93
94
|
return ((result || {}).rows || []).map((row) => {
|
|
94
95
|
let newRow = {};
|
|
95
96
|
Object.keys(row).forEach((key) => {
|
|
@@ -209,7 +210,7 @@ module.exports = exports = class PGed {
|
|
|
209
210
|
|
|
210
211
|
let result;
|
|
211
212
|
|
|
212
|
-
const todo = async () => result = this._convertResult(await this._query(query, parameters));
|
|
213
|
+
const todo = async () => result = this._convertResult(await this._query(query, parameters), options);
|
|
213
214
|
|
|
214
215
|
if (this._transactions.always || options.transaction) await this.transaction(todo);
|
|
215
216
|
else await this.retained(todo);
|
|
@@ -225,25 +226,7 @@ module.exports = exports = class PGed {
|
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
_queryBuild(table) {
|
|
228
|
-
return new QueryBuilder(table, this._options,
|
|
229
|
-
|
|
230
|
-
const [query, parameters] = queryBuilder._build();
|
|
231
|
-
|
|
232
|
-
let result = await this.exec(
|
|
233
|
-
query,
|
|
234
|
-
parameters,
|
|
235
|
-
{
|
|
236
|
-
first: queryBuilder._first,
|
|
237
|
-
transaction: queryBuilder._transaction
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
if (['null', 'undefined'].includes(typeof result)) {
|
|
241
|
-
result = queryBuilder._defaultResult;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return result;
|
|
245
|
-
|
|
246
|
-
});
|
|
229
|
+
return new QueryBuilder(table, this._options, this);
|
|
247
230
|
}
|
|
248
231
|
|
|
249
232
|
from(table) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trenskow/pged",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.2",
|
|
4
4
|
"description": "Just a silly little db management and query builder for PostgreSQL.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
},
|
|
23
23
|
"homepage": "https://github.com/trenskow/pged#readme",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@trenskow/caseit": "^1.1.
|
|
25
|
+
"@trenskow/caseit": "^1.1.4",
|
|
26
26
|
"@trenskow/custom-promise": "^0.10.1",
|
|
27
|
-
"pg": "^8.7.
|
|
27
|
+
"pg": "^8.7.3",
|
|
28
28
|
"puqeue": "^1.0.5"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/query-builder.js
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
const
|
|
4
4
|
caseit = require('@trenskow/caseit'),
|
|
5
|
-
CustomPromise = require('@trenskow/custom-promise')
|
|
5
|
+
CustomPromise = require('@trenskow/custom-promise'),
|
|
6
|
+
Puqeue = require('puqeue');
|
|
7
|
+
|
|
8
|
+
const tableInformationQueue = new Puqeue();
|
|
9
|
+
const tableInformation = {};
|
|
6
10
|
|
|
7
11
|
module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
8
12
|
|
|
9
|
-
constructor(table, options = {},
|
|
13
|
+
constructor(table, options = {}, connection) {
|
|
10
14
|
|
|
11
15
|
super();
|
|
12
16
|
|
|
@@ -36,7 +40,7 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
36
40
|
|
|
37
41
|
this._offset = 0;
|
|
38
42
|
|
|
39
|
-
this.
|
|
43
|
+
this._connection = connection;
|
|
40
44
|
|
|
41
45
|
}
|
|
42
46
|
|
|
@@ -118,9 +122,17 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
118
122
|
return this;
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
sorted(
|
|
122
|
-
if (
|
|
123
|
-
|
|
125
|
+
sorted(sortingKeys) {
|
|
126
|
+
if (typeof sortingKeys === 'string') sortingKeys = sortingKeys.split(/, ?/);
|
|
127
|
+
if (!Array.isArray(sortingKeys)) sortingKeys = [sortingKeys];
|
|
128
|
+
sortingKeys = sortingKeys.map((sortingKey) => {
|
|
129
|
+
if (typeof sortingKey === 'string') return {
|
|
130
|
+
key: sortingKey.substring(0, 1) === '-' ? sortingKey.substring(1) : sortingKey,
|
|
131
|
+
order: sortingKey.substring(0, 1) === '-' ? 'desc' : 'asc'
|
|
132
|
+
};
|
|
133
|
+
return sortingKey;
|
|
134
|
+
});
|
|
135
|
+
this._sortingKeys = this._sortingKeys.concat(sortingKeys);
|
|
124
136
|
return this;
|
|
125
137
|
}
|
|
126
138
|
|
|
@@ -277,6 +289,17 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
277
289
|
}).concat(this._paginated ? `count(${this._table}.*) over() as total` : []).join(', ');
|
|
278
290
|
}
|
|
279
291
|
|
|
292
|
+
_formatParameter(keyPath, value) {
|
|
293
|
+
let [table, key] = keyPath.split('.');
|
|
294
|
+
if (typeof key === 'undefined') [table, key] = [this._table, table];
|
|
295
|
+
switch ((tableInformation[caseit(table, this._options.casing.db)] || {})[caseit(key, this._options.casing.db)]) {
|
|
296
|
+
case 'jsonb':
|
|
297
|
+
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
298
|
+
default:
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
280
303
|
get _operatorMap() {
|
|
281
304
|
return {
|
|
282
305
|
'$or': 'or',
|
|
@@ -373,11 +396,11 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
373
396
|
}
|
|
374
397
|
|
|
375
398
|
if (!Array.isArray(condition[key])) {
|
|
376
|
-
this._queryParameters.push(condition[key]);
|
|
399
|
+
this._queryParameters.push(this._formatParameter(key, condition[key]));
|
|
377
400
|
return this._buildCondition(dbKey, comparer, `$${this._queryParameters.length}`);
|
|
378
401
|
} else {
|
|
379
402
|
const values = condition[key].map((value) => {
|
|
380
|
-
this._queryParameters.push(value);
|
|
403
|
+
this._queryParameters.push(this._formatParameter(key, value));
|
|
381
404
|
return `$${this._queryParameters.length}`;
|
|
382
405
|
});
|
|
383
406
|
return this._buildCondition(dbKey, comparer, `any(array[${values.join(',')}])`);
|
|
@@ -419,15 +442,24 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
419
442
|
}
|
|
420
443
|
|
|
421
444
|
_buildSorting() {
|
|
445
|
+
|
|
422
446
|
if (!this._sortingKeys.length) return;
|
|
447
|
+
|
|
423
448
|
const escapeIfNeeded = (value) => {
|
|
424
449
|
if (value.substring(0, 1) == ':') return value.substring(1);
|
|
425
450
|
return this._dbCase(value, true);
|
|
426
451
|
};
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
452
|
+
|
|
453
|
+
return `order by ${this._sortingKeys.map((sortingKey) => {
|
|
454
|
+
let condition = escapeIfNeeded(sortingKey.key);
|
|
455
|
+
if (Array.isArray(sortingKey.values)) {
|
|
456
|
+
condition = `case ${this._dbCase(sortingKey.key)} ${sortingKey.values.map((value, idx) => {
|
|
457
|
+
return `when '${value}' then ${idx}`;
|
|
458
|
+
}).join(' ')} end`;
|
|
459
|
+
}
|
|
460
|
+
return `${condition}${sortingKey.order === 'desc' ? ' desc' : ''}`;
|
|
430
461
|
}).join(', ')}`;
|
|
462
|
+
|
|
431
463
|
}
|
|
432
464
|
|
|
433
465
|
_buildOffset() {
|
|
@@ -448,7 +480,7 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
448
480
|
} else if (/^:/.test(value)) {
|
|
449
481
|
value = value.substring(1);
|
|
450
482
|
} else {
|
|
451
|
-
this._queryParameters.push(value);
|
|
483
|
+
this._queryParameters.push(this._formatParameter(key, value));
|
|
452
484
|
value = `$${this._queryParameters.length}`;
|
|
453
485
|
}
|
|
454
486
|
return `${this._dbCase(key, true)} = ${value}`;
|
|
@@ -460,8 +492,8 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
460
492
|
}
|
|
461
493
|
|
|
462
494
|
_buildInsertValues() {
|
|
463
|
-
return this._insertValues.map((value) => {
|
|
464
|
-
this._queryParameters.push(value);
|
|
495
|
+
return this._insertValues.map((value, idx) => {
|
|
496
|
+
this._queryParameters.push(this._formatParameter(this._insertKeys[idx], value));
|
|
465
497
|
return `$${this._queryParameters.length}`;
|
|
466
498
|
}).join(', ');
|
|
467
499
|
}
|
|
@@ -547,8 +579,41 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
547
579
|
|
|
548
580
|
}
|
|
549
581
|
|
|
582
|
+
async _resolveTableInformation() {
|
|
583
|
+
await tableInformationQueue.add(async () => {
|
|
584
|
+
|
|
585
|
+
const tables = [this._table]
|
|
586
|
+
.concat(this._joins.map((join) => join.table))
|
|
587
|
+
.filter((table) => !Object.keys(tableInformation).includes(table));
|
|
588
|
+
|
|
589
|
+
await Promise.all(tables.map(async (table) => {
|
|
590
|
+
const rows = await this._connection.exec(`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '${table}';`, [], { format: 'raw' });
|
|
591
|
+
Object.assign(tableInformation, Object.fromEntries([[table, Object.fromEntries(rows.map((row) => {
|
|
592
|
+
return [row.column_name, row.data_type];
|
|
593
|
+
}))]]));
|
|
594
|
+
}));
|
|
595
|
+
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
550
599
|
async _exec() {
|
|
551
|
-
|
|
600
|
+
|
|
601
|
+
await this._resolveTableInformation();
|
|
602
|
+
|
|
603
|
+
const [query, parameters] = this._build();
|
|
604
|
+
|
|
605
|
+
let rows = await this._connection.exec(
|
|
606
|
+
query,
|
|
607
|
+
parameters,
|
|
608
|
+
{
|
|
609
|
+
first: this._first,
|
|
610
|
+
transaction: this._transaction
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
if (['null', 'undefined'].includes(typeof rows)) {
|
|
614
|
+
rows = this._defaultResult;
|
|
615
|
+
}
|
|
616
|
+
|
|
552
617
|
if (this._paginated && !this._first) {
|
|
553
618
|
let total;
|
|
554
619
|
if (rows.length == 0) {
|
|
@@ -563,7 +628,9 @@ module.exports = exports = class QueryBuilder extends CustomPromise {
|
|
|
563
628
|
rows.forEach((item) => delete item.total);
|
|
564
629
|
return { total, items: rows };
|
|
565
630
|
}
|
|
631
|
+
|
|
566
632
|
return rows;
|
|
633
|
+
|
|
567
634
|
}
|
|
568
635
|
|
|
569
636
|
then(resolve, reject) {
|