prostgles-server 2.0.144 → 2.0.147
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/dist/AuthHandler.d.ts +15 -13
- package/dist/AuthHandler.d.ts.map +1 -1
- package/dist/AuthHandler.js +41 -43
- package/dist/AuthHandler.js.map +1 -1
- package/dist/DBEventsManager.d.ts +6 -5
- package/dist/DBEventsManager.d.ts.map +1 -1
- package/dist/DBEventsManager.js +8 -2
- package/dist/DBEventsManager.js.map +1 -1
- package/dist/DboBuilder.d.ts +62 -50
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +229 -170
- package/dist/DboBuilder.js.map +1 -1
- package/dist/FileManager.d.ts +5 -5
- package/dist/FileManager.d.ts.map +1 -1
- package/dist/FileManager.js +48 -21
- package/dist/FileManager.js.map +1 -1
- package/dist/Filtering.d.ts.map +1 -1
- package/dist/Filtering.js +11 -9
- package/dist/Filtering.js.map +1 -1
- package/dist/PostgresNotifListenManager.d.ts +3 -3
- package/dist/PostgresNotifListenManager.d.ts.map +1 -1
- package/dist/PostgresNotifListenManager.js +7 -5
- package/dist/PostgresNotifListenManager.js.map +1 -1
- package/dist/Prostgles.d.ts +6 -9
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +122 -83
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager.d.ts +9 -9
- package/dist/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager.js +10 -9
- package/dist/PubSubManager.js.map +1 -1
- package/dist/QueryBuilder.d.ts +26 -8
- package/dist/QueryBuilder.d.ts.map +1 -1
- package/dist/QueryBuilder.js +114 -46
- package/dist/QueryBuilder.js.map +1 -1
- package/dist/SyncReplication.d.ts +1 -1
- package/dist/SyncReplication.d.ts.map +1 -1
- package/dist/SyncReplication.js +31 -29
- package/dist/SyncReplication.js.map +1 -1
- package/dist/TableConfig.d.ts +0 -1
- package/dist/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig.js +25 -17
- package/dist/TableConfig.js.map +1 -1
- package/dist/shortestPath.d.ts.map +1 -1
- package/dist/shortestPath.js.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +6 -0
- package/dist/utils.js.map +1 -1
- package/lib/AuthHandler.ts +50 -40
- package/lib/DBEventsManager.ts +14 -7
- package/lib/DboBuilder.ts +265 -199
- package/lib/FileManager.ts +30 -21
- package/lib/Filtering.ts +19 -16
- package/lib/PostgresNotifListenManager.ts +11 -10
- package/lib/Prostgles.ts +89 -73
- package/lib/PubSubManager.ts +13 -11
- package/lib/QueryBuilder.ts +135 -54
- package/lib/SyncReplication.ts +10 -10
- package/lib/TableConfig.ts +23 -15
- package/lib/shortestPath.ts +6 -4
- package/lib/utils.ts +7 -1
- package/package.json +7 -8
- package/tests/client/PID.txt +1 -1
- package/tests/client/index.js +10 -7
- package/tests/client/index.ts +12 -8
- package/tests/client/package-lock.json +14 -14
- package/tests/client/package.json +2 -2
- package/tests/client/tsconfig.json +2 -2
- package/tests/client_only_queries.js +127 -104
- package/tests/client_only_queries.ts +43 -17
- package/tests/isomorphic_queries.js +44 -6
- package/tests/isomorphic_queries.ts +42 -6
- package/tests/server/package-lock.json +27 -29
- package/tests/server/package.json +2 -2
- package/tests/server/tsconfig.json +2 -2
- package/tsconfig.json +3 -2
package/dist/DboBuilder.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
5
5
|
*--------------------------------------------------------------------------------------------*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.postgresToTsType = exports.isPlainObject = exports.DboBuilder = exports.TableHandler = exports.ViewHandler = exports.EXISTS_KEYS = exports.pgp = void 0;
|
|
7
|
+
exports.postgresToTsType = exports.getKeys = exports.isPlainObject = exports.DboBuilder = exports.TableHandler = exports.ViewHandler = exports.EXISTS_KEYS = exports.pgp = void 0;
|
|
8
8
|
const Bluebird = require("bluebird");
|
|
9
9
|
// declare global { export interface Promise<T> extends Bluebird<T> {} }
|
|
10
10
|
const pgPromise = require("pg-promise");
|
|
@@ -23,7 +23,6 @@ const prostgles_types_1 = require("prostgles-types");
|
|
|
23
23
|
// }>
|
|
24
24
|
const utils_1 = require("./utils");
|
|
25
25
|
const QueryBuilder_1 = require("./QueryBuilder");
|
|
26
|
-
const Prostgles_1 = require("./Prostgles");
|
|
27
26
|
const PubSubManager_1 = require("./PubSubManager");
|
|
28
27
|
const Filtering_1 = require("./Filtering");
|
|
29
28
|
exports.pgp = pgPromise({
|
|
@@ -62,13 +61,17 @@ function escapeTSNames(str, capitalize = true) {
|
|
|
62
61
|
const shortestPath_1 = require("./shortestPath");
|
|
63
62
|
/* DEBUG CLIENT ERRORS HERE */
|
|
64
63
|
function makeErr(err, localParams, view, allowedKeys) {
|
|
65
|
-
var _a;
|
|
66
64
|
// console.trace(err)
|
|
67
65
|
if (process.env.TEST_TYPE || process.env.PRGL_DEBUG) {
|
|
68
66
|
console.trace(err);
|
|
69
67
|
}
|
|
70
|
-
const errObject =
|
|
71
|
-
|
|
68
|
+
const errObject = {
|
|
69
|
+
...((!localParams || !localParams.socket) ? err : {}),
|
|
70
|
+
...PubSubManager_1.filterObj(err, ["column", "code", "table", "constraint"]),
|
|
71
|
+
...(err && err.toString ? { txt: err.toString() } : {}),
|
|
72
|
+
code_info: sqlErrCodeToMsg(err.code)
|
|
73
|
+
};
|
|
74
|
+
if (view?.dboBuilder?.constraints && errObject.constraint && !errObject.column) {
|
|
72
75
|
const constraint = view.dboBuilder.constraints
|
|
73
76
|
.find(c => c.conname === errObject.constraint && c.relname === view.name);
|
|
74
77
|
if (constraint) {
|
|
@@ -108,7 +111,6 @@ class ColSet {
|
|
|
108
111
|
}
|
|
109
112
|
const rowKeys = Object.keys(row);
|
|
110
113
|
return rowKeys.map(key => {
|
|
111
|
-
var _a;
|
|
112
114
|
const col = this.opts.columns.find(c => c.name === key);
|
|
113
115
|
if (!col)
|
|
114
116
|
throw "Unexpected missing col name";
|
|
@@ -126,7 +128,7 @@ class ColSet {
|
|
|
126
128
|
const dataKeys = Object.keys(row[key]);
|
|
127
129
|
const funcName = dataKeys[0];
|
|
128
130
|
const funcExists = basicFuncNames.includes(funcName);
|
|
129
|
-
const funcArgs =
|
|
131
|
+
const funcArgs = row[key]?.[funcName];
|
|
130
132
|
if (dataKeys.length !== 1 || !funcExists || !Array.isArray(funcArgs)) {
|
|
131
133
|
throw `Expecting only one function key (${basicFuncNames.join(", ")}) \nwith an array of arguments \n within column (${key}) data but got: ${JSON.stringify(row[key])} \nExample: { geo_col: { ST_GeomFromText: ["POINT(-71.064544 42.28787)", 4326] } }`;
|
|
132
134
|
}
|
|
@@ -179,7 +181,7 @@ class ViewHandler {
|
|
|
179
181
|
this.column_names = tableOrViewInfo.columns.map(c => c.name);
|
|
180
182
|
// this.pubSubManager = pubSubManager;
|
|
181
183
|
this.dboBuilder = dboBuilder;
|
|
182
|
-
this.joins = this.dboBuilder.joins;
|
|
184
|
+
this.joins = this.dboBuilder.joins ?? [];
|
|
183
185
|
// fix this
|
|
184
186
|
// and also make hot schema reload over ws
|
|
185
187
|
this.colSet = new ColSet(this.columns, this.name);
|
|
@@ -276,7 +278,6 @@ class ViewHandler {
|
|
|
276
278
|
return { query, toOne: false };
|
|
277
279
|
}
|
|
278
280
|
getJoins(source, target, path, checkTableConfig) {
|
|
279
|
-
var _a, _b, _e;
|
|
280
281
|
let paths = [];
|
|
281
282
|
if (!this.joinPaths)
|
|
282
283
|
throw `${source} - ${target} Join info missing or dissallowed`;
|
|
@@ -284,7 +285,7 @@ class ViewHandler {
|
|
|
284
285
|
throw `Empty join path ( $path ) specified for ${source} <-> ${target}`;
|
|
285
286
|
/* Find the join path between tables */
|
|
286
287
|
if (checkTableConfig) {
|
|
287
|
-
const tableConfigJoinInfo =
|
|
288
|
+
const tableConfigJoinInfo = this.dboBuilder?.prostgles?.tableConfigurator?.getJoinInfo(source, target);
|
|
288
289
|
if (tableConfigJoinInfo)
|
|
289
290
|
return tableConfigJoinInfo;
|
|
290
291
|
}
|
|
@@ -351,7 +352,6 @@ class ViewHandler {
|
|
|
351
352
|
throw `invalid filter -> ${JSON.stringify(filter)} \nExpecting: undefined | {} | { field_name: "value" } | { field: { $gt: 22 } } ... `;
|
|
352
353
|
}
|
|
353
354
|
async getInfo(param1, param2, param3, tableRules, localParams) {
|
|
354
|
-
var _a, _b, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
355
355
|
const p = this.getValidatedRules(tableRules, localParams);
|
|
356
356
|
if (!p.getInfo)
|
|
357
357
|
throw "Not allowed";
|
|
@@ -360,18 +360,17 @@ class ViewHandler {
|
|
|
360
360
|
* Media is directly related to this table (does not come from a deeply joined table)
|
|
361
361
|
*/
|
|
362
362
|
let has_direct_media = false;
|
|
363
|
-
const mediaTable =
|
|
363
|
+
const mediaTable = this.dboBuilder.prostgles?.opts?.fileTable?.tableName;
|
|
364
364
|
if (!this.is_media && mediaTable) {
|
|
365
|
-
if (
|
|
366
|
-
has_media =
|
|
365
|
+
if (this.dboBuilder.prostgles?.opts?.fileTable?.referencedTables?.[this.name]) {
|
|
366
|
+
has_media = this.dboBuilder.prostgles?.opts?.fileTable?.referencedTables?.[this.name];
|
|
367
367
|
has_direct_media = true;
|
|
368
368
|
}
|
|
369
369
|
else {
|
|
370
370
|
const jp = this.dboBuilder.joinPaths.find(jp => jp.t1 === this.name && jp.t2 === mediaTable);
|
|
371
371
|
if (jp && jp.path.length <= 3) {
|
|
372
372
|
await Promise.all(jp.path.map(async (tableName) => {
|
|
373
|
-
|
|
374
|
-
const cols = (_g = (await ((_f = (_e = (_b = (_a = this === null || this === void 0 ? void 0 : this.dboBuilder) === null || _a === void 0 ? void 0 : _a.dbo) === null || _b === void 0 ? void 0 : _b[tableName]) === null || _e === void 0 ? void 0 : _e.getColumns) === null || _f === void 0 ? void 0 : _f.call(_e)))) === null || _g === void 0 ? void 0 : _g.filter(c => { var _a; return jp.path.includes((_a = c === null || c === void 0 ? void 0 : c.references) === null || _a === void 0 ? void 0 : _a.ftable); });
|
|
373
|
+
const cols = (await this?.dboBuilder?.dbo?.[tableName]?.getColumns?.())?.filter(c => jp.path.includes(c?.references?.ftable));
|
|
375
374
|
if (cols && cols.length && has_media !== "many") {
|
|
376
375
|
if (cols.find(c => !c.is_pkey)) {
|
|
377
376
|
has_media = "many";
|
|
@@ -406,30 +405,39 @@ class ViewHandler {
|
|
|
406
405
|
.filter(c => {
|
|
407
406
|
const { insert, select, update } = p || {};
|
|
408
407
|
return [
|
|
409
|
-
...(
|
|
410
|
-
...(
|
|
411
|
-
...(
|
|
408
|
+
...(insert?.fields || []),
|
|
409
|
+
...(select?.fields || []),
|
|
410
|
+
...(update?.fields || []),
|
|
412
411
|
].includes(c.name);
|
|
413
412
|
})
|
|
414
413
|
.map(_c => {
|
|
415
|
-
|
|
416
|
-
let c = Object.assign({}, _c);
|
|
414
|
+
let c = { ..._c };
|
|
417
415
|
let label = c.comment || capitalizeFirstLetter(c.name, " ");
|
|
418
|
-
const tblConfig =
|
|
416
|
+
const tblConfig = this.dboBuilder.prostgles?.opts?.tableConfig?.[this.name];
|
|
419
417
|
if (tblConfig && "columns" in tblConfig) {
|
|
420
|
-
const lbl =
|
|
418
|
+
const lbl = tblConfig?.columns[c.name]?.label;
|
|
421
419
|
if (["string", "object"].includes(typeof lbl)) {
|
|
422
420
|
if (typeof lbl === "string") {
|
|
423
421
|
label = lbl;
|
|
424
422
|
}
|
|
425
423
|
else if (lang) {
|
|
426
|
-
label = (lbl
|
|
424
|
+
label = (lbl?.[lang]) || lbl?.en || label;
|
|
427
425
|
}
|
|
428
426
|
}
|
|
429
427
|
}
|
|
430
428
|
const select = c.privileges.some(p => p.privilege_type === "SELECT"), insert = c.privileges.some(p => p.privilege_type === "INSERT"), update = c.privileges.some(p => p.privilege_type === "UPDATE"), _delete = this.tableOrViewInfo.privileges.delete; // c.privileges.some(p => p.privilege_type === "DELETE");
|
|
431
429
|
delete c.privileges;
|
|
432
|
-
return
|
|
430
|
+
return {
|
|
431
|
+
...c,
|
|
432
|
+
label,
|
|
433
|
+
tsDataType: postgresToTsType(c.udt_name),
|
|
434
|
+
insert: insert && Boolean(p.insert && p.insert.fields && p.insert.fields.includes(c.name)),
|
|
435
|
+
select: select && Boolean(p.select && p.select.fields && p.select.fields.includes(c.name)),
|
|
436
|
+
filter: Boolean(p.select && p.select.filterFields && p.select.filterFields.includes(c.name)),
|
|
437
|
+
update: update && Boolean(p.update && p.update.fields && p.update.fields.includes(c.name)),
|
|
438
|
+
delete: _delete && Boolean(p.delete && p.delete.filterFields && p.delete.filterFields.includes(c.name)),
|
|
439
|
+
...(this.dboBuilder?.prostgles?.tableConfigurator?.getColInfo({ table: this.name, col: c.name }) || {})
|
|
440
|
+
};
|
|
433
441
|
}).filter(c => c.select || c.update || c.delete || c.insert);
|
|
434
442
|
//.sort((a, b) => a.ordinal_position - b.ordinal_position);
|
|
435
443
|
// const tblInfo = await this.getInfo();
|
|
@@ -449,7 +457,6 @@ class ViewHandler {
|
|
|
449
457
|
}
|
|
450
458
|
}
|
|
451
459
|
getValidatedRules(tableRules, localParams) {
|
|
452
|
-
var _a, _b, _e, _f, _g, _h;
|
|
453
460
|
if (utils_1.get(localParams, "socket") && !tableRules) {
|
|
454
461
|
throw "INTERNAL ERROR: Unexpected case -> localParams && !tableRules";
|
|
455
462
|
}
|
|
@@ -483,8 +490,8 @@ class ViewHandler {
|
|
|
483
490
|
};
|
|
484
491
|
let res = {
|
|
485
492
|
allColumns,
|
|
486
|
-
getColumns:
|
|
487
|
-
getInfo:
|
|
493
|
+
getColumns: tableRules?.getColumns ?? true,
|
|
494
|
+
getInfo: tableRules?.getColumns ?? true,
|
|
488
495
|
};
|
|
489
496
|
/* SELECT */
|
|
490
497
|
if (tableRules.select) {
|
|
@@ -499,7 +506,7 @@ class ViewHandler {
|
|
|
499
506
|
}
|
|
500
507
|
res.select = {
|
|
501
508
|
fields: this.parseFieldFilter(tableRules.select.fields),
|
|
502
|
-
forcedFilter:
|
|
509
|
+
forcedFilter: { ...tableRules.select.forcedFilter },
|
|
503
510
|
filterFields: this.parseFieldFilter(tableRules.select.filterFields),
|
|
504
511
|
maxLimit
|
|
505
512
|
};
|
|
@@ -510,9 +517,9 @@ class ViewHandler {
|
|
|
510
517
|
return throwFieldsErr("update");
|
|
511
518
|
res.update = {
|
|
512
519
|
fields: this.parseFieldFilter(tableRules.update.fields),
|
|
513
|
-
forcedData:
|
|
514
|
-
forcedFilter:
|
|
515
|
-
returningFields: getFirstSpecified(
|
|
520
|
+
forcedData: { ...tableRules.update.forcedData },
|
|
521
|
+
forcedFilter: { ...tableRules.update.forcedFilter },
|
|
522
|
+
returningFields: getFirstSpecified(tableRules.update?.returningFields, tableRules?.select?.fields, tableRules.update.fields),
|
|
516
523
|
filterFields: this.parseFieldFilter(tableRules.update.filterFields)
|
|
517
524
|
};
|
|
518
525
|
}
|
|
@@ -522,8 +529,8 @@ class ViewHandler {
|
|
|
522
529
|
return throwFieldsErr("insert");
|
|
523
530
|
res.insert = {
|
|
524
531
|
fields: this.parseFieldFilter(tableRules.insert.fields),
|
|
525
|
-
forcedData:
|
|
526
|
-
returningFields: getFirstSpecified(tableRules.insert.returningFields,
|
|
532
|
+
forcedData: { ...tableRules.insert.forcedData },
|
|
533
|
+
returningFields: getFirstSpecified(tableRules.insert.returningFields, tableRules?.select?.fields, tableRules.insert.fields)
|
|
527
534
|
};
|
|
528
535
|
}
|
|
529
536
|
/* DELETE */
|
|
@@ -531,9 +538,9 @@ class ViewHandler {
|
|
|
531
538
|
if (!tableRules.delete.filterFields)
|
|
532
539
|
return throwFieldsErr("delete", "filterFields");
|
|
533
540
|
res.delete = {
|
|
534
|
-
forcedFilter:
|
|
541
|
+
forcedFilter: { ...tableRules.delete.forcedFilter },
|
|
535
542
|
filterFields: this.parseFieldFilter(tableRules.delete.filterFields),
|
|
536
|
-
returningFields: getFirstSpecified(tableRules.delete.returningFields,
|
|
543
|
+
returningFields: getFirstSpecified(tableRules.delete.returningFields, tableRules?.select?.fields, tableRules.delete.filterFields)
|
|
537
544
|
};
|
|
538
545
|
}
|
|
539
546
|
if (!tableRules.select && !tableRules.update && !tableRules.delete && !tableRules.insert) {
|
|
@@ -576,7 +583,7 @@ class ViewHandler {
|
|
|
576
583
|
};
|
|
577
584
|
}
|
|
578
585
|
}
|
|
579
|
-
async find(filter, selectParams, param3_unused
|
|
586
|
+
async find(filter, selectParams, param3_unused, tableRules, localParams) {
|
|
580
587
|
try {
|
|
581
588
|
filter = filter || {};
|
|
582
589
|
const allowedReturnTypes = ["row", "value", "values"];
|
|
@@ -646,14 +653,14 @@ class ViewHandler {
|
|
|
646
653
|
}
|
|
647
654
|
findOne(filter, selectParams, param3_unused, table_rules, localParams) {
|
|
648
655
|
try {
|
|
649
|
-
const { select = "*", orderBy
|
|
656
|
+
const { select = "*", orderBy, offset = 0 } = selectParams || {};
|
|
650
657
|
if (selectParams) {
|
|
651
658
|
const good_params = ["select", "orderBy", "offset"];
|
|
652
659
|
const bad_params = Object.keys(selectParams).filter(k => !good_params.includes(k));
|
|
653
660
|
if (bad_params && bad_params.length)
|
|
654
661
|
throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
|
|
655
662
|
}
|
|
656
|
-
return this.find(filter, { select, orderBy, limit: 1, offset, returnType: "row" },
|
|
663
|
+
return this.find(filter, { select, orderBy, limit: 1, offset, returnType: "row" }, undefined, table_rules, localParams);
|
|
657
664
|
}
|
|
658
665
|
catch (e) {
|
|
659
666
|
if (localParams && localParams.testRule)
|
|
@@ -664,7 +671,7 @@ class ViewHandler {
|
|
|
664
671
|
async count(filter, param2_unused, param3_unused, table_rules, localParams = {}) {
|
|
665
672
|
filter = filter || {};
|
|
666
673
|
try {
|
|
667
|
-
return await this.find(filter, { select: "", limit: 0 },
|
|
674
|
+
return await this.find(filter, { select: "", limit: 0 }, undefined, table_rules, localParams)
|
|
668
675
|
.then(async (allowed) => {
|
|
669
676
|
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {};
|
|
670
677
|
const where = (await this.prepareWhere({ filter, forcedFilter, filterFields, addKeywords: true, localParams, tableRule: table_rules }));
|
|
@@ -681,13 +688,12 @@ class ViewHandler {
|
|
|
681
688
|
async size(filter, selectParams, param3_unused, table_rules, localParams = {}) {
|
|
682
689
|
filter = filter || {};
|
|
683
690
|
try {
|
|
684
|
-
return await this.find(filter,
|
|
691
|
+
return await this.find(filter, { ...selectParams, limit: 2 }, undefined, table_rules, localParams)
|
|
685
692
|
.then(async (_allowed) => {
|
|
686
693
|
// let rules: TableRule = table_rules || {};
|
|
687
694
|
// rules.select.maxLimit = Number.MAX_SAFE_INTEGER;
|
|
688
695
|
// rules.select.fields = rules.select.fields || "*";
|
|
689
|
-
|
|
690
|
-
const q = await this.find(filter, Object.assign(Object.assign({}, selectParams), { limit: (_a = selectParams === null || selectParams === void 0 ? void 0 : selectParams.limit) !== null && _a !== void 0 ? _a : Number.MAX_SAFE_INTEGER }), null, table_rules, Object.assign(Object.assign({}, localParams), { returnQuery: true }));
|
|
696
|
+
const q = await this.find(filter, { ...selectParams, limit: selectParams?.limit ?? Number.MAX_SAFE_INTEGER }, undefined, table_rules, { ...localParams, returnQuery: true });
|
|
691
697
|
const query = `
|
|
692
698
|
SELECT sum(pg_column_size((prgl_size_query.*))) as size
|
|
693
699
|
FROM (
|
|
@@ -744,7 +750,7 @@ class ViewHandler {
|
|
|
744
750
|
* Parses group or simple filter
|
|
745
751
|
*/
|
|
746
752
|
async prepareWhere(params) {
|
|
747
|
-
const { filter, select, forcedFilter, filterFields: ff, addKeywords = true, tableAlias
|
|
753
|
+
const { filter, select, forcedFilter, filterFields: ff, addKeywords = true, tableAlias, localParams, tableRule } = params;
|
|
748
754
|
const { $and: $and_key, $or: $or_key } = this.dboBuilder.prostgles.keywords;
|
|
749
755
|
let filterFields = ff;
|
|
750
756
|
/* Local update allow all. TODO -> FIX THIS */
|
|
@@ -754,7 +760,7 @@ class ViewHandler {
|
|
|
754
760
|
if (!f)
|
|
755
761
|
throw "Invalid/missing group filter provided";
|
|
756
762
|
let result = "";
|
|
757
|
-
let keys =
|
|
763
|
+
let keys = getKeys(f);
|
|
758
764
|
if (!keys.length)
|
|
759
765
|
return result;
|
|
760
766
|
if ((keys.includes($and_key) || keys.includes($or_key))) {
|
|
@@ -776,7 +782,7 @@ class ViewHandler {
|
|
|
776
782
|
}
|
|
777
783
|
else if (!group) {
|
|
778
784
|
result = await this.getCondition({
|
|
779
|
-
filter:
|
|
785
|
+
filter: { ...f },
|
|
780
786
|
select,
|
|
781
787
|
allowed_colnames: this.parseFieldFilter(filterFields),
|
|
782
788
|
tableAlias,
|
|
@@ -788,7 +794,7 @@ class ViewHandler {
|
|
|
788
794
|
};
|
|
789
795
|
if (!isPlainObject(filter))
|
|
790
796
|
throw "\nInvalid filter\nExpecting an object but got -> " + JSON.stringify(filter);
|
|
791
|
-
let _filter =
|
|
797
|
+
let _filter = { ...filter };
|
|
792
798
|
if (forcedFilter) {
|
|
793
799
|
_filter = {
|
|
794
800
|
[$and_key]: [forcedFilter, _filter].filter(f => f)
|
|
@@ -801,7 +807,7 @@ class ViewHandler {
|
|
|
801
807
|
cond = "WHERE " + cond;
|
|
802
808
|
return cond || "";
|
|
803
809
|
}
|
|
804
|
-
async prepareExistCondition(eConfig, localParams
|
|
810
|
+
async prepareExistCondition(eConfig, localParams) {
|
|
805
811
|
let res = "";
|
|
806
812
|
const thisTable = this.name;
|
|
807
813
|
const isNotExists = ["$notExists", "$notExistsJoined"].includes(eConfig.existType);
|
|
@@ -824,7 +830,7 @@ class ViewHandler {
|
|
|
824
830
|
if (!depth && eConfig.shortestJoin)
|
|
825
831
|
exactPaths = undefined;
|
|
826
832
|
const jinf = this.getJoins(t1, t2, exactPaths, true);
|
|
827
|
-
expectOne = expectOne && jinf.expectOne;
|
|
833
|
+
expectOne = Boolean(expectOne && jinf.expectOne);
|
|
828
834
|
joinPaths = joinPaths.concat(jinf.paths);
|
|
829
835
|
});
|
|
830
836
|
let r = makeJoin({ paths: joinPaths, expectOne }, 0);
|
|
@@ -832,7 +838,7 @@ class ViewHandler {
|
|
|
832
838
|
function makeJoin(joinInfo, ji) {
|
|
833
839
|
const { paths } = joinInfo;
|
|
834
840
|
const jp = paths[ji];
|
|
835
|
-
let prevTable = ji
|
|
841
|
+
// let prevTable = ji? paths[ji - 1].table : jp.source;
|
|
836
842
|
let table = paths[ji].table;
|
|
837
843
|
let tableAlias = prostgles_types_1.asName(ji < paths.length - 1 ? `jd${ji}` : table);
|
|
838
844
|
let prevTableAlias = prostgles_types_1.asName(ji ? `jd${ji - 1}` : thisTable);
|
|
@@ -896,9 +902,9 @@ class ViewHandler {
|
|
|
896
902
|
*/
|
|
897
903
|
async getCondition(params) {
|
|
898
904
|
const { filter, select, allowed_colnames, tableAlias, localParams, tableRules } = params;
|
|
899
|
-
let data =
|
|
905
|
+
let data = { ...filter };
|
|
900
906
|
/* Exists join filter */
|
|
901
|
-
const ERR = "Invalid exists filter. \nExpecting somethibng like: { $exists: { tableName.tableName2: Filter } } | { $exists: { \"**.tableName3\": Filter } }";
|
|
907
|
+
const ERR = "Invalid exists filter. \nExpecting somethibng like: { $exists: { tableName.tableName2: Filter } } | { $exists: { \"**.tableName3\": Filter } }\n";
|
|
902
908
|
const SP_WILDCARD = "**";
|
|
903
909
|
let existsKeys = Object.keys(data)
|
|
904
910
|
.filter(k => exports.EXISTS_KEYS.includes(k) && Object.keys(data[k] || {}).length)
|
|
@@ -946,7 +952,7 @@ class ViewHandler {
|
|
|
946
952
|
const funcArgs = data[f.name];
|
|
947
953
|
if (!Array.isArray(funcArgs))
|
|
948
954
|
throw `A function filter must contain an array. E.g: { $funcFilterName: ["col1"] } \n but got: ${JSON.stringify(PubSubManager_1.filterObj(data, [f.name]))} `;
|
|
949
|
-
const fields = this.parseFieldFilter(f.getFields(funcArgs
|
|
955
|
+
const fields = this.parseFieldFilter(f.getFields(funcArgs), true, allowed_colnames);
|
|
950
956
|
const dissallowedCols = fields.filter(fname => !allowed_colnames.includes(fname));
|
|
951
957
|
if (dissallowedCols.length) {
|
|
952
958
|
throw `Invalid/disallowed columns found in function filter: ${dissallowedCols}`;
|
|
@@ -955,7 +961,7 @@ class ViewHandler {
|
|
|
955
961
|
});
|
|
956
962
|
let existsCond = "";
|
|
957
963
|
if (existsKeys.length) {
|
|
958
|
-
existsCond = (await Promise.all(existsKeys.map(async (k) => await this.prepareExistCondition(k, localParams
|
|
964
|
+
existsCond = (await Promise.all(existsKeys.map(async (k) => await this.prepareExistCondition(k, localParams)))).join(" AND ");
|
|
959
965
|
}
|
|
960
966
|
/* Computed field queries */
|
|
961
967
|
const p = this.getValidatedRules(tableRules, localParams);
|
|
@@ -1002,7 +1008,43 @@ class ViewHandler {
|
|
|
1002
1008
|
selected: false,
|
|
1003
1009
|
getFields: () => [f.name]
|
|
1004
1010
|
})));
|
|
1005
|
-
|
|
1011
|
+
/* Parse complex filters
|
|
1012
|
+
{ $filter: [{ $func: [...] }, "=", value | { $func: [..] }] }
|
|
1013
|
+
*/
|
|
1014
|
+
const complexFilters = [];
|
|
1015
|
+
const complexFilterKey = "$filter";
|
|
1016
|
+
const allowedComparators = [">", "<", "=", "<=", ">=", "<>", "!="];
|
|
1017
|
+
if (complexFilterKey in data) {
|
|
1018
|
+
const getFuncQuery = (funcData) => {
|
|
1019
|
+
const { funcName, args } = QueryBuilder_1.parseFunctionObject(funcData);
|
|
1020
|
+
const funcDef = QueryBuilder_1.parseFunction({ func: funcName, args, functions: QueryBuilder_1.FUNCTIONS, allowedFields: allowed_colnames });
|
|
1021
|
+
return funcDef.getQuery({ args, tableAlias, allColumns: this.columns, allowedFields: allowed_colnames });
|
|
1022
|
+
};
|
|
1023
|
+
const complexFilter = data[complexFilterKey];
|
|
1024
|
+
if (!Array.isArray(complexFilter))
|
|
1025
|
+
throw `Invalid $filter. Must contain an array of at least element but got: ${JSON.stringify(complexFilter)} `;
|
|
1026
|
+
const leftFilter = complexFilter[0];
|
|
1027
|
+
const comparator = complexFilter[1];
|
|
1028
|
+
const rightFilterOrValue = complexFilter[2];
|
|
1029
|
+
const leftVal = getFuncQuery(leftFilter);
|
|
1030
|
+
let result = leftVal;
|
|
1031
|
+
if (comparator) {
|
|
1032
|
+
if (!allowedComparators.includes(comparator))
|
|
1033
|
+
throw `Invalid $filter. comparator ${JSON.stringify(comparator)} is not valid. Expecting one of: ${allowedComparators}`;
|
|
1034
|
+
if (!rightFilterOrValue)
|
|
1035
|
+
throw "Invalid $filter. Expecting a value or function after the comparator";
|
|
1036
|
+
const rightVal = utils_1.isObject(rightFilterOrValue) ? getFuncQuery(rightFilterOrValue) : PubSubManager_1.asValue(rightFilterOrValue);
|
|
1037
|
+
if (leftVal === rightVal)
|
|
1038
|
+
throw "Invalid $filter. Cannot compare two identical function signatures: " + JSON.stringify(leftFilter);
|
|
1039
|
+
result += ` ${comparator} ${rightVal}`;
|
|
1040
|
+
}
|
|
1041
|
+
complexFilters.push(result);
|
|
1042
|
+
}
|
|
1043
|
+
/* Parse join filters
|
|
1044
|
+
{ $joinFilter: { $ST_DWithin: [table.col, foreignTable.col, distance] }
|
|
1045
|
+
will make an exists filter
|
|
1046
|
+
*/
|
|
1047
|
+
let filterKeys = Object.keys(data).filter(k => k !== complexFilterKey && !funcFilterkeys.find(ek => ek.name === k) && !computedFields.find(cf => cf.name === k) && !existsKeys.find(ek => ek.key === k));
|
|
1006
1048
|
// if(allowed_colnames){
|
|
1007
1049
|
// const aliasedColumns = (select || []).filter(s =>
|
|
1008
1050
|
// ["function", "computed", "column"].includes(s.type) && allowed_colnames.includes(s.alias) ||
|
|
@@ -1032,6 +1074,7 @@ class ViewHandler {
|
|
|
1032
1074
|
templates.push(existsCond);
|
|
1033
1075
|
templates = templates.concat(funcConds);
|
|
1034
1076
|
templates = templates.concat(computedColConditions);
|
|
1077
|
+
templates = templates.concat(complexFilters);
|
|
1035
1078
|
return templates.sort() /* sorted to ensure duplicate subscription channels are not created due to different condition order */
|
|
1036
1079
|
.join(" AND \n");
|
|
1037
1080
|
// return templates; //pgp.as.format(template, data);
|
|
@@ -1135,7 +1178,7 @@ class ViewHandler {
|
|
|
1135
1178
|
const orderType = asc ? " ASC " : " DESC ";
|
|
1136
1179
|
const index = selectedAliases.indexOf(key) + 1;
|
|
1137
1180
|
const nullOrder = nulls ? ` NULLS ${nulls === "first" ? " FIRST " : " LAST "}` : "";
|
|
1138
|
-
let colKey = (index > 0 && !nullEmpty) ? index : [tableAlias, key].filter(
|
|
1181
|
+
let colKey = (index > 0 && !nullEmpty) ? index : [tableAlias, key].filter(utils_1.isDefined).map(prostgles_types_1.asName).join(".");
|
|
1139
1182
|
if (nullEmpty) {
|
|
1140
1183
|
colKey = `nullif(trim(${colKey}::text), '')`;
|
|
1141
1184
|
}
|
|
@@ -1203,11 +1246,11 @@ class ViewHandler {
|
|
|
1203
1246
|
if (!column_names || !column_names.length)
|
|
1204
1247
|
throw "table column_names mising";
|
|
1205
1248
|
let _allowed_cols = column_names.slice(0);
|
|
1206
|
-
let _obj =
|
|
1249
|
+
let _obj = { ...obj };
|
|
1207
1250
|
if (allowed_cols) {
|
|
1208
1251
|
_allowed_cols = this.parseFieldFilter(allowed_cols, false);
|
|
1209
1252
|
}
|
|
1210
|
-
let final_filter =
|
|
1253
|
+
let final_filter = { ..._obj }, filter_keys = Object.keys(final_filter);
|
|
1211
1254
|
if (fixIssues && filter_keys.length) {
|
|
1212
1255
|
final_filter = {};
|
|
1213
1256
|
filter_keys
|
|
@@ -1221,7 +1264,7 @@ class ViewHandler {
|
|
|
1221
1264
|
validateObj(final_filter, _allowed_cols);
|
|
1222
1265
|
}
|
|
1223
1266
|
if (forcedData && Object.keys(forcedData).length) {
|
|
1224
|
-
final_filter =
|
|
1267
|
+
final_filter = { ...final_filter, ...forcedData };
|
|
1225
1268
|
}
|
|
1226
1269
|
validateObj(final_filter, column_names.slice(0));
|
|
1227
1270
|
return final_filter;
|
|
@@ -1238,7 +1281,7 @@ class ViewHandler {
|
|
|
1238
1281
|
if (!all_cols)
|
|
1239
1282
|
throw "all_cols missing";
|
|
1240
1283
|
const all_fields = all_cols; // || this.column_names.slice(0);
|
|
1241
|
-
let colNames =
|
|
1284
|
+
let colNames = [], initialParams = JSON.stringify(fieldParams);
|
|
1242
1285
|
if (fieldParams) {
|
|
1243
1286
|
/*
|
|
1244
1287
|
"field1, field2, field4" | "*"
|
|
@@ -1381,7 +1424,7 @@ class TableHandler extends ViewHandler {
|
|
|
1381
1424
|
console.error({ localParams, localFunc });
|
|
1382
1425
|
throw " Cannot have localFunc AND socket ";
|
|
1383
1426
|
}
|
|
1384
|
-
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {}, condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias:
|
|
1427
|
+
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {}, condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }), throttle = utils_1.get(params, "throttle") || 0, selectParams = PubSubManager_1.filterObj(params || {}, [], ["throttle"]);
|
|
1385
1428
|
// const { subOne = false } = localParams || {};
|
|
1386
1429
|
const filterSize = JSON.stringify(filter || {}).length;
|
|
1387
1430
|
if (filterSize * 4 > 2704) {
|
|
@@ -1390,20 +1433,19 @@ class TableHandler extends ViewHandler {
|
|
|
1390
1433
|
if (!localFunc) {
|
|
1391
1434
|
if (!this.dboBuilder.prostgles.isSuperUser)
|
|
1392
1435
|
throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
1393
|
-
return await this.find(filter,
|
|
1436
|
+
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
1394
1437
|
.then(async (isValid) => {
|
|
1395
|
-
const { socket
|
|
1438
|
+
const { socket } = localParams ?? {};
|
|
1396
1439
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
1397
1440
|
return pubSubManager.addSub({
|
|
1398
1441
|
table_info: this.tableOrViewInfo,
|
|
1399
1442
|
socket,
|
|
1400
1443
|
table_rules,
|
|
1401
1444
|
condition: condition,
|
|
1402
|
-
func:
|
|
1403
|
-
filter:
|
|
1404
|
-
params:
|
|
1405
|
-
|
|
1406
|
-
socket_id: socket.id,
|
|
1445
|
+
func: undefined,
|
|
1446
|
+
filter: { ...filter },
|
|
1447
|
+
params: { ...selectParams },
|
|
1448
|
+
socket_id: socket?.id,
|
|
1407
1449
|
table_name: this.name,
|
|
1408
1450
|
throttle,
|
|
1409
1451
|
last_throttled: 0,
|
|
@@ -1414,14 +1456,13 @@ class TableHandler extends ViewHandler {
|
|
|
1414
1456
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
1415
1457
|
pubSubManager.addSub({
|
|
1416
1458
|
table_info: this.tableOrViewInfo,
|
|
1417
|
-
socket:
|
|
1459
|
+
socket: undefined,
|
|
1418
1460
|
table_rules,
|
|
1419
1461
|
condition,
|
|
1420
1462
|
func: localFunc,
|
|
1421
|
-
filter:
|
|
1422
|
-
params:
|
|
1423
|
-
|
|
1424
|
-
socket_id: null,
|
|
1463
|
+
filter: { ...filter },
|
|
1464
|
+
params: { ...selectParams },
|
|
1465
|
+
socket_id: undefined,
|
|
1425
1466
|
table_name: this.name,
|
|
1426
1467
|
throttle,
|
|
1427
1468
|
last_throttled: 0,
|
|
@@ -1442,11 +1483,11 @@ class TableHandler extends ViewHandler {
|
|
|
1442
1483
|
}
|
|
1443
1484
|
subscribeOne(filter, params = {}, localFunc, table_rules, localParams) {
|
|
1444
1485
|
let func = localParams ? undefined : (rows) => localFunc(rows[0]);
|
|
1445
|
-
return this.subscribe(filter,
|
|
1486
|
+
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
1446
1487
|
}
|
|
1447
|
-
async updateBatch(data, params, tableRules, localParams
|
|
1488
|
+
async updateBatch(data, params, tableRules, localParams) {
|
|
1448
1489
|
try {
|
|
1449
|
-
const queries = await Promise.all(data.map(async ([filter, data]) => await this.update(filter, data,
|
|
1490
|
+
const queries = await Promise.all(data.map(async ([filter, data]) => await this.update(filter, data, { ...(params || {}), returning: undefined }, tableRules, { ...(localParams || {}), returnQuery: true })));
|
|
1450
1491
|
const keys = (data && data.length) ? Object.keys(data[0]) : [];
|
|
1451
1492
|
return this.db.tx(t => {
|
|
1452
1493
|
const _queries = queries.map(q => t.none(q));
|
|
@@ -1459,10 +1500,9 @@ class TableHandler extends ViewHandler {
|
|
|
1459
1500
|
throw { err: parseError(e), msg: `Issue with dbo.${this.name}.update()` };
|
|
1460
1501
|
}
|
|
1461
1502
|
}
|
|
1462
|
-
async update(filter, newData, params, tableRules, localParams
|
|
1463
|
-
var _a;
|
|
1503
|
+
async update(filter, newData, params, tableRules, localParams) {
|
|
1464
1504
|
try {
|
|
1465
|
-
const { testRule = false, returnQuery = false } = localParams
|
|
1505
|
+
const { testRule = false, returnQuery = false } = localParams ?? {};
|
|
1466
1506
|
if (!testRule) {
|
|
1467
1507
|
if (!newData || !Object.keys(newData).length)
|
|
1468
1508
|
throw "no update data provided\nEXPECTING db.table.update(filter, updateData, options)";
|
|
@@ -1482,7 +1522,7 @@ class TableHandler extends ViewHandler {
|
|
|
1482
1522
|
await this.validateViewRules(fields, filterFields, returningFields, forcedFilter, "update");
|
|
1483
1523
|
if (forcedData) {
|
|
1484
1524
|
try {
|
|
1485
|
-
const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData:
|
|
1525
|
+
const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData: undefined, allowedFields: "*", tableRules, fixIssues: false });
|
|
1486
1526
|
const updateQ = await this.colSet.getUpdateQuery(data, allowedCols, validate); //pgp.helpers.update(data, columnSet)
|
|
1487
1527
|
let query = updateQ + " WHERE FALSE ";
|
|
1488
1528
|
await this.db.any("EXPLAIN " + query);
|
|
@@ -1516,13 +1556,13 @@ class TableHandler extends ViewHandler {
|
|
|
1516
1556
|
const unrecProps = Object.keys(d).filter(k => !["from", "to", "text", "md5"].includes(k));
|
|
1517
1557
|
if (unrecProps.length)
|
|
1518
1558
|
throw "Unrecognised params in textPatch field: " + unrecProps.join(", ");
|
|
1519
|
-
patchedTextData.push(
|
|
1559
|
+
patchedTextData.push({ ...d, fieldName: c.name });
|
|
1520
1560
|
}
|
|
1521
1561
|
});
|
|
1522
1562
|
if (patchedTextData && patchedTextData.length) {
|
|
1523
1563
|
if (tableRules && !tableRules.select)
|
|
1524
1564
|
throw "Select needs to be permitted to patch data";
|
|
1525
|
-
const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => (
|
|
1565
|
+
const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) }, undefined, tableRules);
|
|
1526
1566
|
if (rows.length !== 1) {
|
|
1527
1567
|
throw "Cannot patch data within a filter that affects more/less than 1 row";
|
|
1528
1568
|
}
|
|
@@ -1532,11 +1572,11 @@ class TableHandler extends ViewHandler {
|
|
|
1532
1572
|
// https://w3resource.com/PostgreSQL/overlay-function.p hp
|
|
1533
1573
|
// overlay(coalesce(status, '') placing 'hom' from 2 for 0)
|
|
1534
1574
|
}
|
|
1535
|
-
let nData =
|
|
1575
|
+
let nData = { ...data };
|
|
1536
1576
|
// if(tableRules && tableRules.update && tableRules?.update?.validate){
|
|
1537
1577
|
// nData = await tableRules.update.validate(nData);
|
|
1538
1578
|
// }
|
|
1539
|
-
let query = await this.colSet.getUpdateQuery(nData, allowedCols,
|
|
1579
|
+
let query = await this.colSet.getUpdateQuery(nData, allowedCols, tableRules?.update?.validate); //pgp.helpers.update(nData, columnSet) + " ";
|
|
1540
1580
|
query += (await this.prepareWhere({
|
|
1541
1581
|
filter,
|
|
1542
1582
|
forcedFilter,
|
|
@@ -1554,7 +1594,7 @@ class TableHandler extends ViewHandler {
|
|
|
1554
1594
|
if (returnQuery)
|
|
1555
1595
|
return query;
|
|
1556
1596
|
if (this.t) {
|
|
1557
|
-
return this.t[qType](query).catch(err => makeErr(err, localParams, this, _fields));
|
|
1597
|
+
return this.t[qType](query).catch((err) => makeErr(err, localParams, this, _fields));
|
|
1558
1598
|
}
|
|
1559
1599
|
return this.db.tx(t => t[qType](query)).catch(err => makeErr(err, localParams, this, _fields));
|
|
1560
1600
|
}
|
|
@@ -1566,17 +1606,16 @@ class TableHandler extends ViewHandler {
|
|
|
1566
1606
|
}
|
|
1567
1607
|
;
|
|
1568
1608
|
validateNewData({ row, forcedData, allowedFields, tableRules, fixIssues = false }) {
|
|
1569
|
-
const synced_field = utils_1.get(tableRules
|
|
1609
|
+
const synced_field = utils_1.get(tableRules ?? {}, "sync.synced_field");
|
|
1570
1610
|
/* Update synced_field if sync is on and missing */
|
|
1571
1611
|
if (synced_field && !row[synced_field]) {
|
|
1572
1612
|
row[synced_field] = Date.now();
|
|
1573
1613
|
}
|
|
1574
1614
|
let data = this.prepareFieldValues(row, forcedData, allowedFields, fixIssues);
|
|
1575
|
-
const dataKeys =
|
|
1615
|
+
const dataKeys = getKeys(data);
|
|
1576
1616
|
dataKeys.map(col => {
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
const colConfig = (_f = (_e = this.dboBuilder.prostgles) === null || _e === void 0 ? void 0 : _e.tableConfigurator) === null || _f === void 0 ? void 0 : _f.getColumnConfig(this.name, col);
|
|
1617
|
+
this.dboBuilder.prostgles?.tableConfigurator?.checkColVal({ table: this.name, col, value: data[col] });
|
|
1618
|
+
const colConfig = this.dboBuilder.prostgles?.tableConfigurator?.getColumnConfig(this.name, col);
|
|
1580
1619
|
if (colConfig && "isText" in colConfig && data[col]) {
|
|
1581
1620
|
if (colConfig.lowerCased) {
|
|
1582
1621
|
data[col] = data[col].toString().toLowerCase();
|
|
@@ -1588,12 +1627,11 @@ class TableHandler extends ViewHandler {
|
|
|
1588
1627
|
});
|
|
1589
1628
|
return { data, allowedCols: this.columns.filter(c => dataKeys.includes(c.name)).map(c => c.name) };
|
|
1590
1629
|
}
|
|
1591
|
-
async insertDataParse(data, param2, param3_unused, tableRules, _localParams
|
|
1592
|
-
var _a, _b;
|
|
1630
|
+
async insertDataParse(data, param2, param3_unused, tableRules, _localParams) {
|
|
1593
1631
|
const localParams = _localParams || {};
|
|
1594
|
-
let dbTX =
|
|
1632
|
+
let dbTX = localParams?.dbTX || this.dbTX;
|
|
1595
1633
|
const isMultiInsert = Array.isArray(data);
|
|
1596
|
-
const getExtraKeys = d => Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
|
|
1634
|
+
const getExtraKeys = (d) => Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
|
|
1597
1635
|
/* Nested insert is not allowed for the file table */
|
|
1598
1636
|
const isNestedInsert = this.is_media ? false : (Array.isArray(data) ? data : [data]).some(d => getExtraKeys(d).length);
|
|
1599
1637
|
/**
|
|
@@ -1601,13 +1639,12 @@ class TableHandler extends ViewHandler {
|
|
|
1601
1639
|
*/
|
|
1602
1640
|
if (isNestedInsert && !dbTX) {
|
|
1603
1641
|
return {
|
|
1604
|
-
insertResult: await this.dboBuilder.getTX((dbTX) => dbTX[this.name].insert(data, param2, param3_unused, tableRules,
|
|
1642
|
+
insertResult: await this.dboBuilder.getTX((dbTX) => dbTX[this.name].insert(data, param2, param3_unused, tableRules, { dbTX, ...localParams }))
|
|
1605
1643
|
};
|
|
1606
1644
|
}
|
|
1607
1645
|
// if(!dbTX && this.t) dbTX = this.d;
|
|
1608
|
-
const preValidate =
|
|
1646
|
+
const preValidate = tableRules?.insert?.preValidate, validate = tableRules?.insert?.validate;
|
|
1609
1647
|
let _data = await Promise.all((Array.isArray(data) ? data : [data]).map(async (row) => {
|
|
1610
|
-
var _a, _b;
|
|
1611
1648
|
if (preValidate) {
|
|
1612
1649
|
row = await preValidate(row);
|
|
1613
1650
|
}
|
|
@@ -1615,7 +1652,7 @@ class TableHandler extends ViewHandler {
|
|
|
1615
1652
|
const extraKeys = getExtraKeys(row);
|
|
1616
1653
|
/* Upload file then continue insert */
|
|
1617
1654
|
if (this.is_media) {
|
|
1618
|
-
if (!
|
|
1655
|
+
if (!this.dboBuilder.prostgles?.fileManager)
|
|
1619
1656
|
throw "fileManager not set up";
|
|
1620
1657
|
const { data, name } = row;
|
|
1621
1658
|
if (dataKeys.length !== 2)
|
|
@@ -1642,35 +1679,37 @@ class TableHandler extends ViewHandler {
|
|
|
1642
1679
|
const _media = await this.dboBuilder.prostgles.fileManager.uploadAsMedia({
|
|
1643
1680
|
item: {
|
|
1644
1681
|
data,
|
|
1645
|
-
name: media.name,
|
|
1682
|
+
name: media.name ?? "????",
|
|
1646
1683
|
content_type: media.content_type
|
|
1647
1684
|
},
|
|
1648
1685
|
});
|
|
1649
|
-
return
|
|
1686
|
+
return {
|
|
1687
|
+
...media,
|
|
1688
|
+
..._media,
|
|
1689
|
+
};
|
|
1650
1690
|
/* Potentially a nested join */
|
|
1651
1691
|
}
|
|
1652
1692
|
else if (extraKeys.length) {
|
|
1653
1693
|
/* Ensure we're using the same transaction */
|
|
1654
1694
|
const _this = this.t ? this : dbTX[this.name];
|
|
1655
|
-
let rootData = PubSubManager_1.filterObj(data,
|
|
1695
|
+
let rootData = PubSubManager_1.filterObj(data, undefined, extraKeys);
|
|
1656
1696
|
let insertedChildren;
|
|
1657
1697
|
let targetTableRules;
|
|
1658
|
-
const fullRootResult = await _this.insert(rootData, { returning: "*" },
|
|
1698
|
+
const fullRootResult = await _this.insert(rootData, { returning: "*" }, undefined, tableRules, localParams);
|
|
1659
1699
|
let returnData;
|
|
1660
|
-
const returning = param2
|
|
1700
|
+
const returning = param2?.returning;
|
|
1661
1701
|
if (returning) {
|
|
1662
1702
|
returnData = {};
|
|
1663
|
-
const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(
|
|
1703
|
+
const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(tableRules?.insert?.returningFields));
|
|
1664
1704
|
returningItems.filter(s => s.selected).map(rs => {
|
|
1665
1705
|
returnData[rs.alias] = fullRootResult[rs.alias];
|
|
1666
1706
|
});
|
|
1667
1707
|
}
|
|
1668
1708
|
await Promise.all(extraKeys.map(async (targetTable) => {
|
|
1669
|
-
var _a;
|
|
1670
1709
|
const childDataItems = Array.isArray(row[targetTable]) ? row[targetTable] : [row[targetTable]];
|
|
1671
1710
|
/* Must be allowed to insert into media table */
|
|
1672
1711
|
const canInsert = async (tbl) => {
|
|
1673
|
-
const childRules = await this.dboBuilder.publishParser
|
|
1712
|
+
const childRules = await this.dboBuilder.publishParser?.getValidatedRequestRuleWusr({ tableName: tbl, command: "insert", localParams });
|
|
1674
1713
|
if (!childRules || !childRules.insert)
|
|
1675
1714
|
throw "Dissallowed nested insert into table " + childRules;
|
|
1676
1715
|
return childRules;
|
|
@@ -1682,7 +1721,7 @@ class TableHandler extends ViewHandler {
|
|
|
1682
1721
|
const thisInfo = await this.getInfo();
|
|
1683
1722
|
const childInsert = async (cdata, tableName) => {
|
|
1684
1723
|
// console.log("childInsert", {data, tableName})
|
|
1685
|
-
if (!cdata || !dbTX[tableName] || !("insert" in dbTX[tableName]))
|
|
1724
|
+
if (!cdata || !dbTX?.[tableName] || !("insert" in dbTX[tableName]))
|
|
1686
1725
|
throw "childInsertErr: Child table handler missing for: " + tableName;
|
|
1687
1726
|
const tableRules = await canInsert(tableName);
|
|
1688
1727
|
if (thisInfo.has_media === "one" && thisInfo.media_table_name === tableName && Array.isArray(cdata) && cdata.length > 1) {
|
|
@@ -1690,7 +1729,7 @@ class TableHandler extends ViewHandler {
|
|
|
1690
1729
|
}
|
|
1691
1730
|
return Promise.all((Array.isArray(cdata) ? cdata : [cdata])
|
|
1692
1731
|
.map(m => dbTX[tableName]
|
|
1693
|
-
.insert(m, { returning: "*" },
|
|
1732
|
+
.insert(m, { returning: "*" }, undefined, tableRules, localParams)
|
|
1694
1733
|
.catch(e => {
|
|
1695
1734
|
console.trace({ childInsertErr: e });
|
|
1696
1735
|
return Promise.reject({ childInsertErr: e });
|
|
@@ -1702,7 +1741,7 @@ class TableHandler extends ViewHandler {
|
|
|
1702
1741
|
const cols2 = this.dboBuilder.dbo[tbl2].columns || [];
|
|
1703
1742
|
if (!this.dboBuilder.dbo[tbl2])
|
|
1704
1743
|
throw "Invalid/disallowed table: " + tbl2;
|
|
1705
|
-
const colsRefT1 = cols2
|
|
1744
|
+
const colsRefT1 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl1);
|
|
1706
1745
|
if (!path.length) {
|
|
1707
1746
|
throw "Nested inserts join path not found for " + [this.name, targetTable];
|
|
1708
1747
|
}
|
|
@@ -1712,8 +1751,8 @@ class TableHandler extends ViewHandler {
|
|
|
1712
1751
|
if (!colsRefT1.length)
|
|
1713
1752
|
throw `Target table ${tbl2} does not reference any columns from the root table ${this.name}. Cannot do nested insert`;
|
|
1714
1753
|
// console.log(childDataItems, JSON.stringify(colsRefT1, null, 2))
|
|
1715
|
-
insertedChildren = await childInsert(childDataItems.map(d => {
|
|
1716
|
-
let result =
|
|
1754
|
+
insertedChildren = await childInsert(childDataItems.map((d) => {
|
|
1755
|
+
let result = { ...d };
|
|
1717
1756
|
colsRefT1.map(col => {
|
|
1718
1757
|
result[col.references.cols[0]] = fullRootResult[col.references.fcols[0]];
|
|
1719
1758
|
});
|
|
@@ -1724,10 +1763,10 @@ class TableHandler extends ViewHandler {
|
|
|
1724
1763
|
else if (path.length === 3) {
|
|
1725
1764
|
if (targetTable !== tbl3)
|
|
1726
1765
|
throw "Did not expect this";
|
|
1727
|
-
const colsRefT3 = cols2
|
|
1766
|
+
const colsRefT3 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl3);
|
|
1728
1767
|
if (!colsRefT1.length || !colsRefT3.length)
|
|
1729
1768
|
throw "Incorrectly referenced or missing columns for nested insert";
|
|
1730
|
-
if (targetTable !== this.dboBuilder.prostgles.fileManager
|
|
1769
|
+
if (targetTable !== this.dboBuilder.prostgles.fileManager?.tableName) {
|
|
1731
1770
|
throw "Only media allowed to have nested inserts more than 2 tables apart";
|
|
1732
1771
|
}
|
|
1733
1772
|
/* We expect tbl2 to have only 2 columns (media_id and foreign_id) */
|
|
@@ -1753,11 +1792,11 @@ class TableHandler extends ViewHandler {
|
|
|
1753
1792
|
throw "Unexpected path for Nested inserts";
|
|
1754
1793
|
}
|
|
1755
1794
|
/* Return also the nested inserted data */
|
|
1756
|
-
if (targetTableRules &&
|
|
1795
|
+
if (targetTableRules && insertedChildren?.length && returning) {
|
|
1757
1796
|
const targetTableHandler = dbTX[targetTable];
|
|
1758
|
-
const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(
|
|
1797
|
+
const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(targetTableRules?.insert?.returningFields));
|
|
1759
1798
|
let clientTargetInserts = insertedChildren.map(d => {
|
|
1760
|
-
let _d =
|
|
1799
|
+
let _d = { ...d };
|
|
1761
1800
|
let res = {};
|
|
1762
1801
|
targetReturning.map(r => {
|
|
1763
1802
|
res[r.alias] = _d[r.alias];
|
|
@@ -1780,8 +1819,7 @@ class TableHandler extends ViewHandler {
|
|
|
1780
1819
|
{ data: result };
|
|
1781
1820
|
return res;
|
|
1782
1821
|
}
|
|
1783
|
-
async insert(rowOrRows, param2, param3_unused, tableRules, _localParams
|
|
1784
|
-
var _a, _b, _e;
|
|
1822
|
+
async insert(rowOrRows, param2, param3_unused, tableRules, _localParams) {
|
|
1785
1823
|
const localParams = _localParams || {};
|
|
1786
1824
|
const { dbTX } = localParams;
|
|
1787
1825
|
try {
|
|
@@ -1802,7 +1840,7 @@ class TableHandler extends ViewHandler {
|
|
|
1802
1840
|
/* Safely test publish rules */
|
|
1803
1841
|
if (testRule) {
|
|
1804
1842
|
// if(this.is_media && tableRules.insert.preValidate) throw "Media table cannot have a preValidate. It already is used internally by prostgles for file upload";
|
|
1805
|
-
await this.validateViewRules(fields,
|
|
1843
|
+
await this.validateViewRules(fields, undefined, returningFields, undefined, "insert");
|
|
1806
1844
|
if (forcedData) {
|
|
1807
1845
|
const keys = Object.keys(forcedData);
|
|
1808
1846
|
if (keys.length) {
|
|
@@ -1832,19 +1870,18 @@ class TableHandler extends ViewHandler {
|
|
|
1832
1870
|
rowOrRows = {}; //throw "Provide data in param1";
|
|
1833
1871
|
let returningSelect = this.makeReturnQuery(await this.prepareReturning(returning, this.parseFieldFilter(returningFields)));
|
|
1834
1872
|
const makeQuery = async (_row, isOne = false) => {
|
|
1835
|
-
|
|
1836
|
-
let row = Object.assign({}, _row);
|
|
1873
|
+
let row = { ..._row };
|
|
1837
1874
|
if (!isPojoObject(row)) {
|
|
1838
1875
|
console.trace(row);
|
|
1839
1876
|
throw "\ninvalid insert data provided -> " + JSON.stringify(row);
|
|
1840
1877
|
}
|
|
1841
1878
|
const { data, allowedCols } = this.validateNewData({ row, forcedData, allowedFields: fields, tableRules, fixIssues });
|
|
1842
|
-
let _data =
|
|
1879
|
+
let _data = { ...data };
|
|
1843
1880
|
let insertQ = "";
|
|
1844
1881
|
if (!Object.keys(_data).length)
|
|
1845
1882
|
insertQ = `INSERT INTO ${prostgles_types_1.asName(this.name)} DEFAULT VALUES `;
|
|
1846
1883
|
else
|
|
1847
|
-
insertQ = await this.colSet.getInsertQuery(_data, allowedCols,
|
|
1884
|
+
insertQ = await this.colSet.getInsertQuery(_data, allowedCols, tableRules?.insert?.validate); // pgp.helpers.insert(_data, columnSet);
|
|
1848
1885
|
return insertQ + conflict_query + returningSelect;
|
|
1849
1886
|
};
|
|
1850
1887
|
let query = "";
|
|
@@ -1877,12 +1914,12 @@ class TableHandler extends ViewHandler {
|
|
|
1877
1914
|
return query;
|
|
1878
1915
|
let result;
|
|
1879
1916
|
if (this.dboBuilder.prostgles.opts.DEBUG_MODE) {
|
|
1880
|
-
console.log(
|
|
1917
|
+
console.log(this.t?.ctx?.start, "insert in " + this.name, data);
|
|
1881
1918
|
}
|
|
1882
|
-
const tx =
|
|
1919
|
+
const tx = dbTX?.[this.name]?.t || this.t;
|
|
1883
1920
|
const allowedFieldKeys = this.parseFieldFilter(fields);
|
|
1884
1921
|
if (tx) {
|
|
1885
|
-
result = tx[queryType](query).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
1922
|
+
result = tx[queryType](query).catch((err) => makeErr(err, localParams, this, allowedFieldKeys));
|
|
1886
1923
|
}
|
|
1887
1924
|
else {
|
|
1888
1925
|
result = this.db.tx(t => t[queryType](query)).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
@@ -1900,11 +1937,11 @@ class TableHandler extends ViewHandler {
|
|
|
1900
1937
|
}
|
|
1901
1938
|
;
|
|
1902
1939
|
makeReturnQuery(items) {
|
|
1903
|
-
if (items
|
|
1940
|
+
if (items?.length)
|
|
1904
1941
|
return " RETURNING " + items.map(s => s.getQuery() + " AS " + prostgles_types_1.asName(s.alias)).join(", ");
|
|
1905
1942
|
return "";
|
|
1906
1943
|
}
|
|
1907
|
-
async delete(filter, params, param3_unused, table_rules, localParams
|
|
1944
|
+
async delete(filter, params, param3_unused, table_rules, localParams) {
|
|
1908
1945
|
try {
|
|
1909
1946
|
const { returning } = params || {};
|
|
1910
1947
|
filter = filter || {};
|
|
@@ -1926,7 +1963,7 @@ class TableHandler extends ViewHandler {
|
|
|
1926
1963
|
throw ` Invalid delete rule for ${this.name}. filterFields missing `;
|
|
1927
1964
|
/* Safely test publish rules */
|
|
1928
1965
|
if (testRule) {
|
|
1929
|
-
await this.validateViewRules(
|
|
1966
|
+
await this.validateViewRules(undefined, filterFields, returningFields, forcedFilter, "delete");
|
|
1930
1967
|
return true;
|
|
1931
1968
|
}
|
|
1932
1969
|
}
|
|
@@ -1954,7 +1991,7 @@ class TableHandler extends ViewHandler {
|
|
|
1954
1991
|
}
|
|
1955
1992
|
if (returnQuery)
|
|
1956
1993
|
return _query;
|
|
1957
|
-
return (this.t || this.db)[queryType](_query).catch(err => makeErr(err, localParams));
|
|
1994
|
+
return (this.t || this.db)[queryType](_query).catch((err) => makeErr(err, localParams));
|
|
1958
1995
|
}
|
|
1959
1996
|
catch (e) {
|
|
1960
1997
|
// console.trace(e)
|
|
@@ -1964,10 +2001,10 @@ class TableHandler extends ViewHandler {
|
|
|
1964
2001
|
}
|
|
1965
2002
|
}
|
|
1966
2003
|
;
|
|
1967
|
-
remove(filter, params, param3_unused, tableRules, localParams
|
|
2004
|
+
remove(filter, params, param3_unused, tableRules, localParams) {
|
|
1968
2005
|
return this.delete(filter, params, param3_unused, tableRules, localParams);
|
|
1969
2006
|
}
|
|
1970
|
-
async upsert(filter, newData, params, table_rules, localParams
|
|
2007
|
+
async upsert(filter, newData, params, table_rules, localParams) {
|
|
1971
2008
|
try {
|
|
1972
2009
|
/* Do it within a transaction to ensure consisency */
|
|
1973
2010
|
if (!this.t) {
|
|
@@ -1977,13 +2014,13 @@ class TableHandler extends ViewHandler {
|
|
|
1977
2014
|
return _upsert(this);
|
|
1978
2015
|
}
|
|
1979
2016
|
async function _upsert(tblH) {
|
|
1980
|
-
return tblH.find(filter, { select: "", limit: 1 },
|
|
2017
|
+
return tblH.find(filter, { select: "", limit: 1 }, undefined, table_rules, localParams)
|
|
1981
2018
|
.then(exists => {
|
|
1982
2019
|
if (exists && exists.length) {
|
|
1983
2020
|
return tblH.update(filter, newData, params, table_rules, localParams);
|
|
1984
2021
|
}
|
|
1985
2022
|
else {
|
|
1986
|
-
return tblH.insert(
|
|
2023
|
+
return tblH.insert({ ...newData, ...filter }, params, undefined, table_rules, localParams);
|
|
1987
2024
|
}
|
|
1988
2025
|
});
|
|
1989
2026
|
}
|
|
@@ -2032,7 +2069,7 @@ class TableHandler extends ViewHandler {
|
|
|
2032
2069
|
select.push(sf);
|
|
2033
2070
|
});
|
|
2034
2071
|
/* Step 1: parse command and params */
|
|
2035
|
-
return this.find(filter, { select, limit: 0 },
|
|
2072
|
+
return this.find(filter, { select, limit: 0 }, undefined, table_rules, localParams)
|
|
2036
2073
|
.then(async (isValid) => {
|
|
2037
2074
|
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {};
|
|
2038
2075
|
const condition = await this.prepareWhere({ filter, forcedFilter, filterFields, addKeywords: false, localParams, tableRule: table_rules });
|
|
@@ -2041,10 +2078,11 @@ class TableHandler extends ViewHandler {
|
|
|
2041
2078
|
return pubSubManager.addSync({
|
|
2042
2079
|
table_info: this.tableOrViewInfo,
|
|
2043
2080
|
condition,
|
|
2044
|
-
id_fields, synced_field,
|
|
2081
|
+
id_fields, synced_field,
|
|
2082
|
+
allow_delete,
|
|
2045
2083
|
socket,
|
|
2046
2084
|
table_rules,
|
|
2047
|
-
filter:
|
|
2085
|
+
filter: { ...filter },
|
|
2048
2086
|
params: { select }
|
|
2049
2087
|
}).then(channelName => ({ channelName, id_fields, synced_field }));
|
|
2050
2088
|
});
|
|
@@ -2082,7 +2120,7 @@ class TableHandler extends ViewHandler {
|
|
|
2082
2120
|
}
|
|
2083
2121
|
}
|
|
2084
2122
|
exports.TableHandler = TableHandler;
|
|
2085
|
-
const
|
|
2123
|
+
const Prostgles_1 = require("./Prostgles");
|
|
2086
2124
|
class DboBuilder {
|
|
2087
2125
|
constructor(prostgles) {
|
|
2088
2126
|
this.schema = "public";
|
|
@@ -2111,8 +2149,11 @@ class DboBuilder {
|
|
|
2111
2149
|
console.warn(`subscribe and sync cannot be used because db user is not a superuser `);
|
|
2112
2150
|
}
|
|
2113
2151
|
}
|
|
2152
|
+
if (!this._pubSubManager)
|
|
2153
|
+
throw "Could not create this._pubSubManager";
|
|
2114
2154
|
return this._pubSubManager;
|
|
2115
2155
|
};
|
|
2156
|
+
this.joinPaths = [];
|
|
2116
2157
|
this.init = async () => {
|
|
2117
2158
|
/* If watchSchema then PubSubManager must be created */
|
|
2118
2159
|
await this.build();
|
|
@@ -2124,7 +2165,7 @@ class DboBuilder {
|
|
|
2124
2165
|
this.getTX = (cb) => {
|
|
2125
2166
|
return this.db.tx((t) => {
|
|
2126
2167
|
let dbTX = {};
|
|
2127
|
-
this.tablesOrViews
|
|
2168
|
+
this.tablesOrViews?.map(tov => {
|
|
2128
2169
|
if (tov.is_view) {
|
|
2129
2170
|
dbTX[tov.name] = new ViewHandler(this.db, tov, this, t, dbTX, this.joinPaths);
|
|
2130
2171
|
}
|
|
@@ -2145,14 +2186,15 @@ class DboBuilder {
|
|
|
2145
2186
|
});
|
|
2146
2187
|
};
|
|
2147
2188
|
this.prostgles = prostgles;
|
|
2189
|
+
if (!this.prostgles.db)
|
|
2190
|
+
throw "db missing";
|
|
2148
2191
|
this.db = this.prostgles.db;
|
|
2149
2192
|
this.schema = this.prostgles.opts.schema || "public";
|
|
2150
2193
|
this.dbo = {};
|
|
2151
2194
|
// this.joins = this.prostgles.joins;
|
|
2152
2195
|
}
|
|
2153
2196
|
destroy() {
|
|
2154
|
-
|
|
2155
|
-
(_a = this._pubSubManager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
2197
|
+
this._pubSubManager?.destroy();
|
|
2156
2198
|
}
|
|
2157
2199
|
getJoins() {
|
|
2158
2200
|
return this.joins;
|
|
@@ -2185,7 +2227,7 @@ class DboBuilder {
|
|
|
2185
2227
|
}
|
|
2186
2228
|
const tovNames = this.tablesOrViews.map(t => t.name);
|
|
2187
2229
|
// 2 find incorrect tables
|
|
2188
|
-
const missing =
|
|
2230
|
+
const missing = joins.flatMap(j => j.tables).find(t => !tovNames.includes(t));
|
|
2189
2231
|
if (missing) {
|
|
2190
2232
|
throw "Table not found: " + missing;
|
|
2191
2233
|
}
|
|
@@ -2204,11 +2246,11 @@ class DboBuilder {
|
|
|
2204
2246
|
});
|
|
2205
2247
|
});
|
|
2206
2248
|
// 4 find incorrect/missing join types
|
|
2207
|
-
const expected_types = " \n\n-> Expecting: " +
|
|
2249
|
+
const expected_types = " \n\n-> Expecting: " + Prostgles_1.JOIN_TYPES.map(t => JSON.stringify(t)).join(` | `);
|
|
2208
2250
|
const mt = joins.find(j => !j.type);
|
|
2209
2251
|
if (mt)
|
|
2210
2252
|
throw "Join type missing for: " + JSON.stringify(mt, null, 2) + expected_types;
|
|
2211
|
-
const it = joins.find(j => !
|
|
2253
|
+
const it = joins.find(j => !Prostgles_1.JOIN_TYPES.includes(j.type));
|
|
2212
2254
|
if (it)
|
|
2213
2255
|
throw "Incorrect join type for: " + JSON.stringify(it, null, 2) + expected_types;
|
|
2214
2256
|
}
|
|
@@ -2224,7 +2266,7 @@ class DboBuilder {
|
|
|
2224
2266
|
this.joinGraph[t2] = this.joinGraph[t2] || {};
|
|
2225
2267
|
this.joinGraph[t2][t1] = 1;
|
|
2226
2268
|
});
|
|
2227
|
-
const tables =
|
|
2269
|
+
const tables = this.joins.flatMap(t => t.tables);
|
|
2228
2270
|
this.joinPaths = [];
|
|
2229
2271
|
tables.map(t1 => {
|
|
2230
2272
|
tables.map(t2 => {
|
|
@@ -2283,11 +2325,11 @@ export type TxCB = {
|
|
|
2283
2325
|
const TSTableDataName = snakify(tov.name, true);
|
|
2284
2326
|
const TSTableHandlerName = JSON.stringify(tov.name);
|
|
2285
2327
|
if (tov.is_view) {
|
|
2286
|
-
this.dbo[tov.name] = new ViewHandler(this.db, tov, this,
|
|
2328
|
+
this.dbo[tov.name] = new ViewHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
|
|
2287
2329
|
this.dboDefinition += ` ${TSTableHandlerName}: ViewHandler<${TSTableDataName}> \n`;
|
|
2288
2330
|
}
|
|
2289
2331
|
else {
|
|
2290
|
-
this.dbo[tov.name] = new TableHandler(this.db, tov, this,
|
|
2332
|
+
this.dbo[tov.name] = new TableHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
|
|
2291
2333
|
this.dboDefinition += ` ${TSTableHandlerName}: TableHandler<${TSTableDataName}> \n`;
|
|
2292
2334
|
}
|
|
2293
2335
|
allDataDefs += `export type ${TSTableDataName} = { \n` +
|
|
@@ -2297,6 +2339,14 @@ export type TxCB = {
|
|
|
2297
2339
|
if (this.joinPaths && this.joinPaths.find(jp => [jp.t1, jp.t2].includes(tov.name))) {
|
|
2298
2340
|
let table = tov.name;
|
|
2299
2341
|
joinTableNames.push(table);
|
|
2342
|
+
const makeJoin = (isLeft = true, filter, select, options) => {
|
|
2343
|
+
return {
|
|
2344
|
+
[isLeft ? "$leftJoin" : "$innerJoin"]: table,
|
|
2345
|
+
filter,
|
|
2346
|
+
select,
|
|
2347
|
+
...options
|
|
2348
|
+
};
|
|
2349
|
+
};
|
|
2300
2350
|
this.dbo.innerJoin = this.dbo.innerJoin || {};
|
|
2301
2351
|
this.dbo.leftJoin = this.dbo.leftJoin || {};
|
|
2302
2352
|
this.dbo.innerJoinOne = this.dbo.innerJoinOne || {};
|
|
@@ -2308,15 +2358,11 @@ export type TxCB = {
|
|
|
2308
2358
|
return makeJoin(false, filter, select, options);
|
|
2309
2359
|
};
|
|
2310
2360
|
this.dbo.leftJoinOne[table] = (filter, select, options = {}) => {
|
|
2311
|
-
return makeJoin(true, filter, select,
|
|
2361
|
+
return makeJoin(true, filter, select, { ...options, limit: 1 });
|
|
2312
2362
|
};
|
|
2313
2363
|
this.dbo.innerJoinOne[table] = (filter, select, options = {}) => {
|
|
2314
|
-
return makeJoin(false, filter, select,
|
|
2364
|
+
return makeJoin(false, filter, select, { ...options, limit: 1 });
|
|
2315
2365
|
};
|
|
2316
|
-
function makeJoin(isLeft = true, filter, select, options) {
|
|
2317
|
-
return Object.assign({ [isLeft ? "$leftJoin" : "$innerJoin"]: table, filter,
|
|
2318
|
-
select }, options);
|
|
2319
|
-
}
|
|
2320
2366
|
}
|
|
2321
2367
|
});
|
|
2322
2368
|
i18nDef += " }> \n";
|
|
@@ -2344,13 +2390,12 @@ export type TxCB = {
|
|
|
2344
2390
|
let DATA_TYPES = !needType ? [] : await this.db.any("SELECT oid, typname FROM pg_type");
|
|
2345
2391
|
let USER_TABLES = !needType ? [] : await this.db.any("SELECT relid, relname FROM pg_catalog.pg_statio_user_tables");
|
|
2346
2392
|
this.dbo.sql = async (query, params, options, localParams) => {
|
|
2347
|
-
var _a, _b;
|
|
2348
2393
|
const canRunSQL = async (localParams) => {
|
|
2349
2394
|
if (!localParams)
|
|
2350
2395
|
return true;
|
|
2351
2396
|
const { socket } = localParams;
|
|
2352
2397
|
const publishParams = await this.prostgles.publishParser.getPublishParams({ socket });
|
|
2353
|
-
let res = await this.prostgles.opts.publishRawSQL(publishParams);
|
|
2398
|
+
let res = await this.prostgles.opts.publishRawSQL?.(publishParams);
|
|
2354
2399
|
return Boolean(res && typeof res === "boolean" || res === "*");
|
|
2355
2400
|
};
|
|
2356
2401
|
if (!(await canRunSQL(localParams)))
|
|
@@ -2360,7 +2405,7 @@ export type TxCB = {
|
|
|
2360
2405
|
if (returnType === "noticeSubscription") {
|
|
2361
2406
|
if (!socket)
|
|
2362
2407
|
throw "Only allowed with client socket";
|
|
2363
|
-
return await this.prostgles.dbEventsManager
|
|
2408
|
+
return await this.prostgles.dbEventsManager?.addNotice(socket);
|
|
2364
2409
|
}
|
|
2365
2410
|
else if (returnType === "statement") {
|
|
2366
2411
|
try {
|
|
@@ -2375,12 +2420,12 @@ export type TxCB = {
|
|
|
2375
2420
|
if (returnType === "arrayMode") {
|
|
2376
2421
|
finalQuery = new PQ({ text: exports.pgp.as.format(query, params), rowMode: "array" });
|
|
2377
2422
|
}
|
|
2378
|
-
let
|
|
2379
|
-
const {
|
|
2423
|
+
let _qres = await this.db.result(finalQuery, params);
|
|
2424
|
+
const { fields, rows, command } = _qres;
|
|
2380
2425
|
/**
|
|
2381
2426
|
* Fallback for watchSchema in case not superuser and cannot add db event listener
|
|
2382
2427
|
*/
|
|
2383
|
-
const { watchSchema, watchSchemaType } =
|
|
2428
|
+
const { watchSchema, watchSchemaType } = this.prostgles?.opts || {};
|
|
2384
2429
|
if (watchSchema &&
|
|
2385
2430
|
(!this.prostgles.isSuperUser || watchSchemaType === "queries") &&
|
|
2386
2431
|
(["CREATE", "ALTER", "DROP"].includes(command) ||
|
|
@@ -2391,7 +2436,7 @@ export type TxCB = {
|
|
|
2391
2436
|
if (command === "LISTEN") {
|
|
2392
2437
|
if (!socket)
|
|
2393
2438
|
throw "Only allowed with client socket";
|
|
2394
|
-
return await this.prostgles.dbEventsManager
|
|
2439
|
+
return await this.prostgles.dbEventsManager?.addNotify(query, socket);
|
|
2395
2440
|
}
|
|
2396
2441
|
else if (returnType === "rows") {
|
|
2397
2442
|
return rows;
|
|
@@ -2400,18 +2445,26 @@ export type TxCB = {
|
|
|
2400
2445
|
return rows[0];
|
|
2401
2446
|
}
|
|
2402
2447
|
else if (returnType === "value") {
|
|
2403
|
-
return
|
|
2448
|
+
return Object.values(rows?.[0] || {})?.[0];
|
|
2404
2449
|
}
|
|
2405
2450
|
else if (returnType === "values") {
|
|
2406
2451
|
return rows.map(r => Object.values(r[0]));
|
|
2407
2452
|
}
|
|
2408
2453
|
else {
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2454
|
+
let qres = {
|
|
2455
|
+
duration: 0,
|
|
2456
|
+
..._qres,
|
|
2457
|
+
fields: fields?.map(f => {
|
|
2458
|
+
const dataType = DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID)?.typname ?? "text", tableName = USER_TABLES.find(t => +t.relid === +f.tableID), tsDataType = postgresToTsType(dataType);
|
|
2459
|
+
return {
|
|
2460
|
+
...f,
|
|
2461
|
+
tsDataType,
|
|
2462
|
+
dataType,
|
|
2463
|
+
udt_name: dataType,
|
|
2464
|
+
tableName: tableName?.relname
|
|
2465
|
+
};
|
|
2466
|
+
}) ?? []
|
|
2467
|
+
};
|
|
2415
2468
|
return qres;
|
|
2416
2469
|
}
|
|
2417
2470
|
}
|
|
@@ -2608,8 +2661,13 @@ function isPlainObject(o) {
|
|
|
2608
2661
|
return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
|
|
2609
2662
|
}
|
|
2610
2663
|
exports.isPlainObject = isPlainObject;
|
|
2664
|
+
function getKeys(o) {
|
|
2665
|
+
return Object.keys(o);
|
|
2666
|
+
}
|
|
2667
|
+
exports.getKeys = getKeys;
|
|
2611
2668
|
function postgresToTsType(udt_data_type) {
|
|
2612
|
-
return
|
|
2669
|
+
return getKeys(prostgles_types_1.TS_PG_Types).find(k => {
|
|
2670
|
+
// @ts-ignore
|
|
2613
2671
|
return prostgles_types_1.TS_PG_Types[k].includes(udt_data_type) || !prostgles_types_1.TS_PG_Types[k].length;
|
|
2614
2672
|
});
|
|
2615
2673
|
}
|
|
@@ -2857,6 +2915,7 @@ function sqlErrCodeToMsg(code) {
|
|
|
2857
2915
|
"XX001": "data_corrupted",
|
|
2858
2916
|
"XX002": "index_corrupted"
|
|
2859
2917
|
}, c2 = { "20000": "case_not_found", "21000": "cardinality_violation", "22000": "data_exception", "22001": "string_data_right_truncation", "22002": "null_value_no_indicator_parameter", "22003": "numeric_value_out_of_range", "22004": "null_value_not_allowed", "22005": "error_in_assignment", "22007": "invalid_datetime_format", "22008": "datetime_field_overflow", "22009": "invalid_time_zone_displacement_value", "22010": "invalid_indicator_parameter_value", "22011": "substring_error", "22012": "division_by_zero", "22013": "invalid_preceding_or_following_size", "22014": "invalid_argument_for_ntile_function", "22015": "interval_field_overflow", "22016": "invalid_argument_for_nth_value_function", "22018": "invalid_character_value_for_cast", "22019": "invalid_escape_character", "22021": "character_not_in_repertoire", "22022": "indicator_overflow", "22023": "invalid_parameter_value", "22024": "unterminated_c_string", "22025": "invalid_escape_sequence", "22026": "string_data_length_mismatch", "22027": "trim_error", "22030": "duplicate_json_object_key_value", "22031": "invalid_argument_for_sql_json_datetime_function", "22032": "invalid_json_text", "22033": "invalid_sql_json_subscript", "22034": "more_than_one_sql_json_item", "22035": "no_sql_json_item", "22036": "non_numeric_sql_json_item", "22037": "non_unique_keys_in_a_json_object", "22038": "singleton_sql_json_item_required", "22039": "sql_json_array_not_found", "23000": "integrity_constraint_violation", "23001": "restrict_violation", "23502": "not_null_violation", "23503": "foreign_key_violation", "23505": "unique_violation", "23514": "check_violation", "24000": "invalid_cursor_state", "25000": "invalid_transaction_state", "25001": "active_sql_transaction", "25002": "branch_transaction_already_active", "25003": "inappropriate_access_mode_for_branch_transaction", "25004": "inappropriate_isolation_level_for_branch_transaction", "25005": "no_active_sql_transaction_for_branch_transaction", "25006": "read_only_sql_transaction", "25007": "schema_and_data_statement_mixing_not_supported", "25008": "held_cursor_requires_same_isolation_level", "26000": "invalid_sql_statement_name", "27000": "triggered_data_change_violation", "28000": "invalid_authorization_specification", "34000": "invalid_cursor_name", "38000": "external_routine_exception", "38001": "containing_sql_not_permitted", "38002": "modifying_sql_data_not_permitted", "38003": "prohibited_sql_statement_attempted", "38004": "reading_sql_data_not_permitted", "39000": "external_routine_invocation_exception", "39001": "invalid_sqlstate_returned", "39004": "null_value_not_allowed", "40000": "transaction_rollback", "40001": "serialization_failure", "40002": "transaction_integrity_constraint_violation", "40003": "statement_completion_unknown", "42000": "syntax_error_or_access_rule_violation", "42501": "insufficient_privilege", "42601": "syntax_error", "42602": "invalid_name", "42611": "invalid_column_definition", "42622": "name_too_long", "42701": "duplicate_column", "42702": "ambiguous_column", "42703": "undefined_column", "42704": "undefined_object", "42710": "duplicate_object", "42712": "duplicate_alias", "42723": "duplicate_function", "42725": "ambiguous_function", "42803": "grouping_error", "42804": "datatype_mismatch", "42809": "wrong_object_type", "42830": "invalid_foreign_key", "42846": "cannot_coerce", "42883": "undefined_function", "42939": "reserved_name", "44000": "with_check_option_violation", "53000": "insufficient_resources", "53100": "disk_full", "53200": "out_of_memory", "53300": "too_many_connections", "53400": "configuration_limit_exceeded", "54000": "program_limit_exceeded", "54001": "statement_too_complex", "54011": "too_many_columns", "54023": "too_many_arguments", "55000": "object_not_in_prerequisite_state", "55006": "object_in_use", "57000": "operator_intervention", "57014": "query_canceled", "58000": "system_error", "58030": "io_error", "72000": "snapshot_too_old", "00000": "successful_completion", "01000": "warning", "0100C": "dynamic_result_sets_returned", "01008": "implicit_zero_bit_padding", "01003": "null_value_eliminated_in_set_function", "01007": "privilege_not_granted", "01006": "privilege_not_revoked", "01004": "string_data_right_truncation", "01P01": "deprecated_feature", "02000": "no_data", "02001": "no_additional_dynamic_result_sets_returned", "03000": "sql_statement_not_yet_complete", "08000": "connection_exception", "08003": "connection_does_not_exist", "08006": "connection_failure", "08001": "sqlclient_unable_to_establish_sqlconnection", "08004": "sqlserver_rejected_establishment_of_sqlconnection", "08007": "transaction_resolution_unknown", "08P01": "protocol_violation", "09000": "triggered_action_exception", "0A000": "feature_not_supported", "0B000": "invalid_transaction_initiation", "0F000": "locator_exception", "0F001": "invalid_locator_specification", "0L000": "invalid_grantor", "0LP01": "invalid_grant_operation", "0P000": "invalid_role_specification", "0Z000": "diagnostics_exception", "0Z002": "stacked_diagnostics_accessed_without_active_handler", "2202E": "array_subscript_error", "2200B": "escape_character_conflict", "2201E": "invalid_argument_for_logarithm", "2201F": "invalid_argument_for_power_function", "2201G": "invalid_argument_for_width_bucket_function", "2200D": "invalid_escape_octet", "22P06": "nonstandard_use_of_escape_character", "2201B": "invalid_regular_expression", "2201W": "invalid_row_count_in_limit_clause", "2201X": "invalid_row_count_in_result_offset_clause", "2202H": "invalid_tablesample_argument", "2202G": "invalid_tablesample_repeat", "2200C": "invalid_use_of_escape_character", "2200G": "most_specific_type_mismatch", "2200H": "sequence_generator_limit_exceeded", "2200F": "zero_length_character_string", "22P01": "floating_point_exception", "22P02": "invalid_text_representation", "22P03": "invalid_binary_representation", "22P04": "bad_copy_file_format", "22P05": "untranslatable_character", "2200L": "not_an_xml_document", "2200M": "invalid_xml_document", "2200N": "invalid_xml_content", "2200S": "invalid_xml_comment", "2200T": "invalid_xml_processing_instruction", "2203A": "sql_json_member_not_found", "2203B": "sql_json_number_not_found", "2203C": "sql_json_object_not_found", "2203D": "too_many_json_array_elements", "2203E": "too_many_json_object_members", "2203F": "sql_json_scalar_required", "23P01": "exclusion_violation", "25P01": "no_active_sql_transaction", "25P02": "in_failed_sql_transaction", "25P03": "idle_in_transaction_session_timeout", "28P01": "invalid_password", "2B000": "dependent_privilege_descriptors_still_exist", "2BP01": "dependent_objects_still_exist", "2D000": "invalid_transaction_termination", "2F000": "sql_routine_exception", "2F005": "function_executed_no_return_statement", "2F002": "modifying_sql_data_not_permitted", "2F003": "prohibited_sql_statement_attempted", "2F004": "reading_sql_data_not_permitted", "39P01": "trigger_protocol_violated", "39P02": "srf_protocol_violated", "39P03": "event_trigger_protocol_violated", "3B000": "savepoint_exception", "3B001": "invalid_savepoint_specification", "3D000": "invalid_catalog_name", "3F000": "invalid_schema_name", "40P01": "deadlock_detected", "42P20": "windowing_error", "42P19": "invalid_recursion", "42P18": "indeterminate_datatype", "42P21": "collation_mismatch", "42P22": "indeterminate_collation", "428C9": "generated_always", "42P01": "undefined_table", "42P02": "undefined_parameter", "42P03": "duplicate_cursor", "42P04": "duplicate_database", "42P05": "duplicate_prepared_statement", "42P06": "duplicate_schema", "42P07": "duplicate_table", "42P08": "ambiguous_parameter", "42P09": "ambiguous_alias", "42P10": "invalid_column_reference", "42P11": "invalid_cursor_definition", "42P12": "invalid_database_definition", "42P13": "invalid_function_definition", "42P14": "invalid_prepared_statement_definition", "42P15": "invalid_schema_definition", "42P16": "invalid_table_definition", "42P17": "invalid_object_definition", "55P02": "cant_change_runtime_param", "55P03": "lock_not_available", "55P04": "unsafe_new_enum_value_usage", "57P01": "admin_shutdown", "57P02": "crash_shutdown", "57P03": "cannot_connect_now", "57P04": "database_dropped", "58P01": "undefined_file", "58P02": "duplicate_file", "F0000": "config_file_error", "F0001": "lock_file_exists", "HV000": "fdw_error", "HV005": "fdw_column_name_not_found", "HV002": "fdw_dynamic_parameter_value_needed", "HV010": "fdw_function_sequence_error", "HV021": "fdw_inconsistent_descriptor_information", "HV024": "fdw_invalid_attribute_value", "HV007": "fdw_invalid_column_name", "HV008": "fdw_invalid_column_number", "HV004": "fdw_invalid_data_type", "HV006": "fdw_invalid_data_type_descriptors", "HV091": "fdw_invalid_descriptor_field_identifier", "HV00B": "fdw_invalid_handle", "HV00C": "fdw_invalid_option_index", "HV00D": "fdw_invalid_option_name", "HV090": "fdw_invalid_string_length_or_buffer_length", "HV00A": "fdw_invalid_string_format", "HV009": "fdw_invalid_use_of_null_pointer", "HV014": "fdw_too_many_handles", "HV001": "fdw_out_of_memory", "HV00P": "fdw_no_schemas", "HV00J": "fdw_option_name_not_found", "HV00K": "fdw_reply_handle", "HV00Q": "fdw_schema_not_found", "HV00R": "fdw_table_not_found", "HV00L": "fdw_unable_to_create_execution", "HV00M": "fdw_unable_to_create_reply", "HV00N": "fdw_unable_to_establish_connection", "P0000": "plpgsql_error", "P0001": "raise_exception", "P0002": "no_data_found", "P0003": "too_many_rows", "P0004": "assert_failure", "XX000": "internal_error", "XX001": "data_corrupted", "XX002": "index_corrupted" };
|
|
2918
|
+
//@ts-ignore
|
|
2860
2919
|
return c2[code] || errs[code] || code;
|
|
2861
2920
|
/*
|
|
2862
2921
|
https://www.postgresql.org/docs/13/errcodes-appendix.html
|
|
@@ -2891,10 +2950,10 @@ async function getInferredJoins(db, schema = "public") {
|
|
|
2891
2950
|
let existing = joins[eIdx];
|
|
2892
2951
|
if (existing) {
|
|
2893
2952
|
if (existing.tables[0] === d.table_name) {
|
|
2894
|
-
existing.on =
|
|
2953
|
+
existing.on = { ...existing.on, [d.column_name]: d.foreign_column_name };
|
|
2895
2954
|
}
|
|
2896
2955
|
else {
|
|
2897
|
-
existing.on =
|
|
2956
|
+
existing.on = { ...existing.on, [d.foreign_column_name]: d.column_name };
|
|
2898
2957
|
}
|
|
2899
2958
|
joins[eIdx] = existing;
|
|
2900
2959
|
}
|