prostgles-server 2.0.145 → 2.0.148
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 +43 -44
- 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 +54 -50
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +275 -206
- 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 +59 -31
- package/dist/FileManager.js.map +1 -1
- package/dist/Filtering.d.ts.map +1 -1
- package/dist/Filtering.js +17 -14
- 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 +125 -86
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager.d.ts +8 -8
- package/dist/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager.js +58 -52
- package/dist/PubSubManager.js.map +1 -1
- package/dist/QueryBuilder.d.ts +21 -8
- package/dist/QueryBuilder.d.ts.map +1 -1
- package/dist/QueryBuilder.js +179 -107
- package/dist/QueryBuilder.js.map +1 -1
- package/dist/SyncReplication.js +38 -35
- 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 +36 -28
- package/dist/TableConfig.js.map +1 -1
- package/dist/shortestPath.d.ts.map +1 -1
- package/dist/shortestPath.js +2 -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 +7 -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 +128 -55
- 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 +8 -9
- 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 +43 -6
- package/tests/isomorphic_queries.ts +41 -6
- package/tests/server/package-lock.json +29 -31
- package/tests/server/package.json +2 -2
- package/tests/server/tsconfig.json +2 -2
- package/tsconfig.json +3 -2
package/dist/DboBuilder.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Copyright (c) Stefan L. All rights reserved.
|
|
4
4
|
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
5
5
|
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
var _a;
|
|
6
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.postgresToTsType = exports.isPlainObject = exports.DboBuilder = exports.TableHandler = exports.ViewHandler = exports.EXISTS_KEYS = exports.pgp = void 0;
|
|
8
|
+
exports.postgresToTsType = exports.getKeys = exports.isPlainObject = exports.DboBuilder = exports.TableHandler = exports.ViewHandler = exports.EXISTS_KEYS = exports.pgp = void 0;
|
|
8
9
|
const Bluebird = require("bluebird");
|
|
9
10
|
// declare global { export interface Promise<T> extends Bluebird<T> {} }
|
|
10
11
|
const pgPromise = require("pg-promise");
|
|
@@ -23,7 +24,6 @@ const prostgles_types_1 = require("prostgles-types");
|
|
|
23
24
|
// }>
|
|
24
25
|
const utils_1 = require("./utils");
|
|
25
26
|
const QueryBuilder_1 = require("./QueryBuilder");
|
|
26
|
-
const Prostgles_1 = require("./Prostgles");
|
|
27
27
|
const PubSubManager_1 = require("./PubSubManager");
|
|
28
28
|
const Filtering_1 = require("./Filtering");
|
|
29
29
|
exports.pgp = pgPromise({
|
|
@@ -62,13 +62,17 @@ function escapeTSNames(str, capitalize = true) {
|
|
|
62
62
|
const shortestPath_1 = require("./shortestPath");
|
|
63
63
|
/* DEBUG CLIENT ERRORS HERE */
|
|
64
64
|
function makeErr(err, localParams, view, allowedKeys) {
|
|
65
|
-
var _a;
|
|
66
65
|
// console.trace(err)
|
|
67
66
|
if (process.env.TEST_TYPE || process.env.PRGL_DEBUG) {
|
|
68
67
|
console.trace(err);
|
|
69
68
|
}
|
|
70
|
-
const errObject =
|
|
71
|
-
|
|
69
|
+
const errObject = {
|
|
70
|
+
...((!localParams || !localParams.socket) ? err : {}),
|
|
71
|
+
...(0, PubSubManager_1.filterObj)(err, ["column", "code", "table", "constraint"]),
|
|
72
|
+
...(err && err.toString ? { txt: err.toString() } : {}),
|
|
73
|
+
code_info: sqlErrCodeToMsg(err.code)
|
|
74
|
+
};
|
|
75
|
+
if (view?.dboBuilder?.constraints && errObject.constraint && !errObject.column) {
|
|
72
76
|
const constraint = view.dboBuilder.constraints
|
|
73
77
|
.find(c => c.conname === errObject.constraint && c.relname === view.name);
|
|
74
78
|
if (constraint) {
|
|
@@ -100,15 +104,14 @@ class ColSet {
|
|
|
100
104
|
if (!allowedCols || badCol) {
|
|
101
105
|
throw "Missing or unexpected columns: " + badCol;
|
|
102
106
|
}
|
|
103
|
-
if (prostgles_types_1.isEmpty(data))
|
|
107
|
+
if ((0, prostgles_types_1.isEmpty)(data))
|
|
104
108
|
throw "No data";
|
|
105
|
-
let row = PubSubManager_1.filterObj(data, allowedCols);
|
|
109
|
+
let row = (0, PubSubManager_1.filterObj)(data, allowedCols);
|
|
106
110
|
if (validate) {
|
|
107
111
|
row = await validate(row);
|
|
108
112
|
}
|
|
109
113
|
const rowKeys = Object.keys(row);
|
|
110
114
|
return rowKeys.map(key => {
|
|
111
|
-
var _a;
|
|
112
115
|
const col = this.opts.columns.find(c => c.name === key);
|
|
113
116
|
if (!col)
|
|
114
117
|
throw "Unexpected missing col name";
|
|
@@ -120,13 +123,13 @@ class ColSet {
|
|
|
120
123
|
let escapedVal;
|
|
121
124
|
if (["geometry", "geography"].includes(col.udt_name) && row[key] && isPlainObject(row[key])) {
|
|
122
125
|
const basicFunc = (args) => {
|
|
123
|
-
return args.map(arg => PubSubManager_1.asValue(arg)).join(", ");
|
|
126
|
+
return args.map(arg => (0, PubSubManager_1.asValue)(arg)).join(", ");
|
|
124
127
|
};
|
|
125
128
|
const basicFuncNames = ["ST_GeomFromText", "ST_Point", "ST_MakePoint", "ST_MakePointM", "ST_PointFromText", "ST_GeomFromEWKT", "ST_GeomFromGeoJSON"];
|
|
126
129
|
const dataKeys = Object.keys(row[key]);
|
|
127
130
|
const funcName = dataKeys[0];
|
|
128
131
|
const funcExists = basicFuncNames.includes(funcName);
|
|
129
|
-
const funcArgs =
|
|
132
|
+
const funcArgs = row[key]?.[funcName];
|
|
130
133
|
if (dataKeys.length !== 1 || !funcExists || !Array.isArray(funcArgs)) {
|
|
131
134
|
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
135
|
}
|
|
@@ -136,7 +139,7 @@ class ColSet {
|
|
|
136
139
|
escapedVal = exports.pgp.as.format(colIsUUID ? "$1::uuid" : colIsJSON ? "$1:json" : "$1", [row[key]]);
|
|
137
140
|
}
|
|
138
141
|
return {
|
|
139
|
-
escapedCol: prostgles_types_1.asName(key),
|
|
142
|
+
escapedCol: (0, prostgles_types_1.asName)(key),
|
|
140
143
|
escapedVal
|
|
141
144
|
};
|
|
142
145
|
});
|
|
@@ -145,14 +148,14 @@ class ColSet {
|
|
|
145
148
|
const res = (await Promise.all((Array.isArray(data) ? data : [data]).map(async (d) => {
|
|
146
149
|
const rowParts = await this.getRow(d, allowedCols, validate);
|
|
147
150
|
const select = rowParts.map(r => r.escapedCol).join(", "), values = rowParts.map(r => r.escapedVal).join(", ");
|
|
148
|
-
return `INSERT INTO ${prostgles_types_1.asName(this.opts.tableName)} (${select}) VALUES (${values})`;
|
|
151
|
+
return `INSERT INTO ${(0, prostgles_types_1.asName)(this.opts.tableName)} (${select}) VALUES (${values})`;
|
|
149
152
|
}))).join(";\n") + " ";
|
|
150
153
|
return res;
|
|
151
154
|
}
|
|
152
155
|
async getUpdateQuery(data, allowedCols, validate) {
|
|
153
156
|
const res = (await Promise.all((Array.isArray(data) ? data : [data]).map(async (d) => {
|
|
154
157
|
const rowParts = await this.getRow(d, allowedCols, validate);
|
|
155
|
-
return `UPDATE ${prostgles_types_1.asName(this.opts.tableName)} SET ` + rowParts.map(r => `${r.escapedCol} = ${r.escapedVal} `).join(",\n");
|
|
158
|
+
return `UPDATE ${(0, prostgles_types_1.asName)(this.opts.tableName)} SET ` + rowParts.map(r => `${r.escapedCol} = ${r.escapedVal} `).join(",\n");
|
|
156
159
|
}))).join(";\n") + " ";
|
|
157
160
|
return res;
|
|
158
161
|
}
|
|
@@ -172,14 +175,14 @@ class ViewHandler {
|
|
|
172
175
|
this.joinPaths = joinPaths;
|
|
173
176
|
this.tableOrViewInfo = tableOrViewInfo;
|
|
174
177
|
this.name = tableOrViewInfo.name;
|
|
175
|
-
this.escapedName = prostgles_types_1.asName(this.name);
|
|
178
|
+
this.escapedName = (0, prostgles_types_1.asName)(this.name);
|
|
176
179
|
this.columns = tableOrViewInfo.columns;
|
|
177
180
|
/* cols are sorted by name to reduce .d.ts schema rewrites */
|
|
178
181
|
this.columnsForTypes = tableOrViewInfo.columns.slice(0).sort((a, b) => a.name.localeCompare(b.name));
|
|
179
182
|
this.column_names = tableOrViewInfo.columns.map(c => c.name);
|
|
180
183
|
// this.pubSubManager = pubSubManager;
|
|
181
184
|
this.dboBuilder = dboBuilder;
|
|
182
|
-
this.joins = this.dboBuilder.joins;
|
|
185
|
+
this.joins = this.dboBuilder.joins ?? [];
|
|
183
186
|
// fix this
|
|
184
187
|
// and also make hot schema reload over ws
|
|
185
188
|
this.colSet = new ColSet(this.columns, this.name);
|
|
@@ -218,10 +221,10 @@ class ViewHandler {
|
|
|
218
221
|
/* CTID not available in AFTER trigger */
|
|
219
222
|
// .concat(this.is_view? [] : ["ctid"])
|
|
220
223
|
.sort()
|
|
221
|
-
.map(f => (tableAlias ? (prostgles_types_1.asName(tableAlias) + ".") : "") + prostgles_types_1.asName(f))
|
|
224
|
+
.map(f => (tableAlias ? ((0, prostgles_types_1.asName)(tableAlias) + ".") : "") + (0, prostgles_types_1.asName)(f))
|
|
222
225
|
.map(f => `md5(coalesce(${f}::text, 'dd'))`)
|
|
223
226
|
.join(" || ") +
|
|
224
|
-
`)` + (alias ? ` as ${prostgles_types_1.asName(alias)}` : "");
|
|
227
|
+
`)` + (alias ? ` as ${(0, prostgles_types_1.asName)(alias)}` : "");
|
|
225
228
|
}
|
|
226
229
|
async validateViewRules(fields, filterFields, returningFields, forcedFilter, rule) {
|
|
227
230
|
/* Safely test publish rules */
|
|
@@ -276,7 +279,6 @@ class ViewHandler {
|
|
|
276
279
|
return { query, toOne: false };
|
|
277
280
|
}
|
|
278
281
|
getJoins(source, target, path, checkTableConfig) {
|
|
279
|
-
var _a, _b, _e;
|
|
280
282
|
let paths = [];
|
|
281
283
|
if (!this.joinPaths)
|
|
282
284
|
throw `${source} - ${target} Join info missing or dissallowed`;
|
|
@@ -284,7 +286,7 @@ class ViewHandler {
|
|
|
284
286
|
throw `Empty join path ( $path ) specified for ${source} <-> ${target}`;
|
|
285
287
|
/* Find the join path between tables */
|
|
286
288
|
if (checkTableConfig) {
|
|
287
|
-
const tableConfigJoinInfo =
|
|
289
|
+
const tableConfigJoinInfo = this.dboBuilder?.prostgles?.tableConfigurator?.getJoinInfo(source, target);
|
|
288
290
|
if (tableConfigJoinInfo)
|
|
289
291
|
return tableConfigJoinInfo;
|
|
290
292
|
}
|
|
@@ -351,7 +353,6 @@ class ViewHandler {
|
|
|
351
353
|
throw `invalid filter -> ${JSON.stringify(filter)} \nExpecting: undefined | {} | { field_name: "value" } | { field: { $gt: 22 } } ... `;
|
|
352
354
|
}
|
|
353
355
|
async getInfo(param1, param2, param3, tableRules, localParams) {
|
|
354
|
-
var _a, _b, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
355
356
|
const p = this.getValidatedRules(tableRules, localParams);
|
|
356
357
|
if (!p.getInfo)
|
|
357
358
|
throw "Not allowed";
|
|
@@ -360,18 +361,17 @@ class ViewHandler {
|
|
|
360
361
|
* Media is directly related to this table (does not come from a deeply joined table)
|
|
361
362
|
*/
|
|
362
363
|
let has_direct_media = false;
|
|
363
|
-
const mediaTable =
|
|
364
|
+
const mediaTable = this.dboBuilder.prostgles?.opts?.fileTable?.tableName;
|
|
364
365
|
if (!this.is_media && mediaTable) {
|
|
365
|
-
if (
|
|
366
|
-
has_media =
|
|
366
|
+
if (this.dboBuilder.prostgles?.opts?.fileTable?.referencedTables?.[this.name]) {
|
|
367
|
+
has_media = this.dboBuilder.prostgles?.opts?.fileTable?.referencedTables?.[this.name];
|
|
367
368
|
has_direct_media = true;
|
|
368
369
|
}
|
|
369
370
|
else {
|
|
370
371
|
const jp = this.dboBuilder.joinPaths.find(jp => jp.t1 === this.name && jp.t2 === mediaTable);
|
|
371
372
|
if (jp && jp.path.length <= 3) {
|
|
372
373
|
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); });
|
|
374
|
+
const cols = (await this?.dboBuilder?.dbo?.[tableName]?.getColumns?.())?.filter(c => jp.path.includes(c?.references?.ftable));
|
|
375
375
|
if (cols && cols.length && has_media !== "many") {
|
|
376
376
|
if (cols.find(c => !c.is_pkey)) {
|
|
377
377
|
has_media = "many";
|
|
@@ -406,30 +406,39 @@ class ViewHandler {
|
|
|
406
406
|
.filter(c => {
|
|
407
407
|
const { insert, select, update } = p || {};
|
|
408
408
|
return [
|
|
409
|
-
...(
|
|
410
|
-
...(
|
|
411
|
-
...(
|
|
409
|
+
...(insert?.fields || []),
|
|
410
|
+
...(select?.fields || []),
|
|
411
|
+
...(update?.fields || []),
|
|
412
412
|
].includes(c.name);
|
|
413
413
|
})
|
|
414
414
|
.map(_c => {
|
|
415
|
-
|
|
416
|
-
let c = Object.assign({}, _c);
|
|
415
|
+
let c = { ..._c };
|
|
417
416
|
let label = c.comment || capitalizeFirstLetter(c.name, " ");
|
|
418
|
-
const tblConfig =
|
|
417
|
+
const tblConfig = this.dboBuilder.prostgles?.opts?.tableConfig?.[this.name];
|
|
419
418
|
if (tblConfig && "columns" in tblConfig) {
|
|
420
|
-
const lbl =
|
|
419
|
+
const lbl = tblConfig?.columns[c.name]?.label;
|
|
421
420
|
if (["string", "object"].includes(typeof lbl)) {
|
|
422
421
|
if (typeof lbl === "string") {
|
|
423
422
|
label = lbl;
|
|
424
423
|
}
|
|
425
424
|
else if (lang) {
|
|
426
|
-
label = (lbl
|
|
425
|
+
label = (lbl?.[lang]) || lbl?.en || label;
|
|
427
426
|
}
|
|
428
427
|
}
|
|
429
428
|
}
|
|
430
429
|
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
430
|
delete c.privileges;
|
|
432
|
-
return
|
|
431
|
+
return {
|
|
432
|
+
...c,
|
|
433
|
+
label,
|
|
434
|
+
tsDataType: postgresToTsType(c.udt_name),
|
|
435
|
+
insert: insert && Boolean(p.insert && p.insert.fields && p.insert.fields.includes(c.name)),
|
|
436
|
+
select: select && Boolean(p.select && p.select.fields && p.select.fields.includes(c.name)),
|
|
437
|
+
filter: Boolean(p.select && p.select.filterFields && p.select.filterFields.includes(c.name)),
|
|
438
|
+
update: update && Boolean(p.update && p.update.fields && p.update.fields.includes(c.name)),
|
|
439
|
+
delete: _delete && Boolean(p.delete && p.delete.filterFields && p.delete.filterFields.includes(c.name)),
|
|
440
|
+
...(this.dboBuilder?.prostgles?.tableConfigurator?.getColInfo({ table: this.name, col: c.name }) || {})
|
|
441
|
+
};
|
|
433
442
|
}).filter(c => c.select || c.update || c.delete || c.insert);
|
|
434
443
|
//.sort((a, b) => a.ordinal_position - b.ordinal_position);
|
|
435
444
|
// const tblInfo = await this.getInfo();
|
|
@@ -449,15 +458,14 @@ class ViewHandler {
|
|
|
449
458
|
}
|
|
450
459
|
}
|
|
451
460
|
getValidatedRules(tableRules, localParams) {
|
|
452
|
-
|
|
453
|
-
if (utils_1.get(localParams, "socket") && !tableRules) {
|
|
461
|
+
if ((0, utils_1.get)(localParams, "socket") && !tableRules) {
|
|
454
462
|
throw "INTERNAL ERROR: Unexpected case -> localParams && !tableRules";
|
|
455
463
|
}
|
|
456
464
|
/* Computed fields are allowed only if select is allowed */
|
|
457
465
|
const allColumns = this.column_names.slice(0).map(fieldName => ({
|
|
458
466
|
type: "column",
|
|
459
467
|
name: fieldName,
|
|
460
|
-
getQuery: ({ tableAlias }) => QueryBuilder_1.asNameAlias(fieldName, tableAlias),
|
|
468
|
+
getQuery: ({ tableAlias }) => (0, QueryBuilder_1.asNameAlias)(fieldName, tableAlias),
|
|
461
469
|
selected: false
|
|
462
470
|
})).concat(QueryBuilder_1.COMPUTED_FIELDS.map(c => ({
|
|
463
471
|
type: c.type,
|
|
@@ -473,7 +481,7 @@ class ViewHandler {
|
|
|
473
481
|
selected: false
|
|
474
482
|
})));
|
|
475
483
|
if (tableRules) {
|
|
476
|
-
if (prostgles_types_1.isEmpty(tableRules))
|
|
484
|
+
if ((0, prostgles_types_1.isEmpty)(tableRules))
|
|
477
485
|
throw "INTERNAL ERROR: Unexpected case -> Empty table rules for " + this.name;
|
|
478
486
|
const throwFieldsErr = (command, fieldType = "fields") => {
|
|
479
487
|
throw `Invalid publish.${this.name}.${command} rule -> ${fieldType} setting is missing.\nPlease specify allowed ${fieldType} in this format: "*" | { col_name: false } | { col1: true, col2: true }`;
|
|
@@ -483,8 +491,8 @@ class ViewHandler {
|
|
|
483
491
|
};
|
|
484
492
|
let res = {
|
|
485
493
|
allColumns,
|
|
486
|
-
getColumns:
|
|
487
|
-
getInfo:
|
|
494
|
+
getColumns: tableRules?.getColumns ?? true,
|
|
495
|
+
getInfo: tableRules?.getColumns ?? true,
|
|
488
496
|
};
|
|
489
497
|
/* SELECT */
|
|
490
498
|
if (tableRules.select) {
|
|
@@ -499,7 +507,7 @@ class ViewHandler {
|
|
|
499
507
|
}
|
|
500
508
|
res.select = {
|
|
501
509
|
fields: this.parseFieldFilter(tableRules.select.fields),
|
|
502
|
-
forcedFilter:
|
|
510
|
+
forcedFilter: { ...tableRules.select.forcedFilter },
|
|
503
511
|
filterFields: this.parseFieldFilter(tableRules.select.filterFields),
|
|
504
512
|
maxLimit
|
|
505
513
|
};
|
|
@@ -510,9 +518,9 @@ class ViewHandler {
|
|
|
510
518
|
return throwFieldsErr("update");
|
|
511
519
|
res.update = {
|
|
512
520
|
fields: this.parseFieldFilter(tableRules.update.fields),
|
|
513
|
-
forcedData:
|
|
514
|
-
forcedFilter:
|
|
515
|
-
returningFields: getFirstSpecified(
|
|
521
|
+
forcedData: { ...tableRules.update.forcedData },
|
|
522
|
+
forcedFilter: { ...tableRules.update.forcedFilter },
|
|
523
|
+
returningFields: getFirstSpecified(tableRules.update?.returningFields, tableRules?.select?.fields, tableRules.update.fields),
|
|
516
524
|
filterFields: this.parseFieldFilter(tableRules.update.filterFields)
|
|
517
525
|
};
|
|
518
526
|
}
|
|
@@ -522,8 +530,8 @@ class ViewHandler {
|
|
|
522
530
|
return throwFieldsErr("insert");
|
|
523
531
|
res.insert = {
|
|
524
532
|
fields: this.parseFieldFilter(tableRules.insert.fields),
|
|
525
|
-
forcedData:
|
|
526
|
-
returningFields: getFirstSpecified(tableRules.insert.returningFields,
|
|
533
|
+
forcedData: { ...tableRules.insert.forcedData },
|
|
534
|
+
returningFields: getFirstSpecified(tableRules.insert.returningFields, tableRules?.select?.fields, tableRules.insert.fields)
|
|
527
535
|
};
|
|
528
536
|
}
|
|
529
537
|
/* DELETE */
|
|
@@ -531,9 +539,9 @@ class ViewHandler {
|
|
|
531
539
|
if (!tableRules.delete.filterFields)
|
|
532
540
|
return throwFieldsErr("delete", "filterFields");
|
|
533
541
|
res.delete = {
|
|
534
|
-
forcedFilter:
|
|
542
|
+
forcedFilter: { ...tableRules.delete.forcedFilter },
|
|
535
543
|
filterFields: this.parseFieldFilter(tableRules.delete.filterFields),
|
|
536
|
-
returningFields: getFirstSpecified(tableRules.delete.returningFields,
|
|
544
|
+
returningFields: getFirstSpecified(tableRules.delete.returningFields, tableRules?.select?.fields, tableRules.delete.filterFields)
|
|
537
545
|
};
|
|
538
546
|
}
|
|
539
547
|
if (!tableRules.select && !tableRules.update && !tableRules.delete && !tableRules.insert) {
|
|
@@ -576,7 +584,7 @@ class ViewHandler {
|
|
|
576
584
|
};
|
|
577
585
|
}
|
|
578
586
|
}
|
|
579
|
-
async find(filter, selectParams, param3_unused
|
|
587
|
+
async find(filter, selectParams, param3_unused, tableRules, localParams) {
|
|
580
588
|
try {
|
|
581
589
|
filter = filter || {};
|
|
582
590
|
const allowedReturnTypes = ["row", "value", "values"];
|
|
@@ -609,7 +617,7 @@ class ViewHandler {
|
|
|
609
617
|
if (maxLimit && !Number.isInteger(maxLimit))
|
|
610
618
|
throw ` invalid publish.${this.name}.select.maxLimit -> expecting integer but got ` + maxLimit;
|
|
611
619
|
}
|
|
612
|
-
let q = await QueryBuilder_1.getNewQuery(this, filter, selectParams, param3_unused, tableRules, localParams, this.columns), _query = QueryBuilder_1.makeQuery(this, q, undefined, undefined, selectParams);
|
|
620
|
+
let q = await (0, QueryBuilder_1.getNewQuery)(this, filter, selectParams, param3_unused, tableRules, localParams, this.columns), _query = (0, QueryBuilder_1.makeQuery)(this, q, undefined, undefined, selectParams);
|
|
613
621
|
// console.log(_query, JSON.stringify(q, null, 2))
|
|
614
622
|
if (testRule) {
|
|
615
623
|
try {
|
|
@@ -646,14 +654,14 @@ class ViewHandler {
|
|
|
646
654
|
}
|
|
647
655
|
findOne(filter, selectParams, param3_unused, table_rules, localParams) {
|
|
648
656
|
try {
|
|
649
|
-
const { select = "*", orderBy
|
|
657
|
+
const { select = "*", orderBy, offset = 0 } = selectParams || {};
|
|
650
658
|
if (selectParams) {
|
|
651
659
|
const good_params = ["select", "orderBy", "offset"];
|
|
652
660
|
const bad_params = Object.keys(selectParams).filter(k => !good_params.includes(k));
|
|
653
661
|
if (bad_params && bad_params.length)
|
|
654
662
|
throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
|
|
655
663
|
}
|
|
656
|
-
return this.find(filter, { select, orderBy, limit: 1, offset, returnType: "row" },
|
|
664
|
+
return this.find(filter, { select, orderBy, limit: 1, offset, returnType: "row" }, undefined, table_rules, localParams);
|
|
657
665
|
}
|
|
658
666
|
catch (e) {
|
|
659
667
|
if (localParams && localParams.testRule)
|
|
@@ -664,9 +672,9 @@ class ViewHandler {
|
|
|
664
672
|
async count(filter, param2_unused, param3_unused, table_rules, localParams = {}) {
|
|
665
673
|
filter = filter || {};
|
|
666
674
|
try {
|
|
667
|
-
return await this.find(filter, { select: "", limit: 0 },
|
|
675
|
+
return await this.find(filter, { select: "", limit: 0 }, undefined, table_rules, localParams)
|
|
668
676
|
.then(async (allowed) => {
|
|
669
|
-
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {};
|
|
677
|
+
const { filterFields, forcedFilter } = (0, utils_1.get)(table_rules, "select") || {};
|
|
670
678
|
const where = (await this.prepareWhere({ filter, forcedFilter, filterFields, addKeywords: true, localParams, tableRule: table_rules }));
|
|
671
679
|
let query = "SELECT COUNT(*) FROM " + this.escapedName + " " + where;
|
|
672
680
|
return (this.t || this.db).one(query, { _psqlWS_tableName: this.name }).then(({ count }) => +count);
|
|
@@ -681,13 +689,12 @@ class ViewHandler {
|
|
|
681
689
|
async size(filter, selectParams, param3_unused, table_rules, localParams = {}) {
|
|
682
690
|
filter = filter || {};
|
|
683
691
|
try {
|
|
684
|
-
return await this.find(filter,
|
|
692
|
+
return await this.find(filter, { ...selectParams, limit: 2 }, undefined, table_rules, localParams)
|
|
685
693
|
.then(async (_allowed) => {
|
|
686
694
|
// let rules: TableRule = table_rules || {};
|
|
687
695
|
// rules.select.maxLimit = Number.MAX_SAFE_INTEGER;
|
|
688
696
|
// 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 }));
|
|
697
|
+
const q = await this.find(filter, { ...selectParams, limit: selectParams?.limit ?? Number.MAX_SAFE_INTEGER }, undefined, table_rules, { ...localParams, returnQuery: true });
|
|
691
698
|
const query = `
|
|
692
699
|
SELECT sum(pg_column_size((prgl_size_query.*))) as size
|
|
693
700
|
FROM (
|
|
@@ -731,7 +738,7 @@ class ViewHandler {
|
|
|
731
738
|
prepareSelect(selectParams = "*", allowed_cols, allow_empty = true, tableAlias) {
|
|
732
739
|
if (tableAlias) {
|
|
733
740
|
let cs = this.prepareColumnSet(selectParams, allowed_cols, true, false);
|
|
734
|
-
return cs.columns.map(col => `${this.escapedName}.${prostgles_types_1.asName(col.name)}`).join(", ");
|
|
741
|
+
return cs.columns.map(col => `${this.escapedName}.${(0, prostgles_types_1.asName)(col.name)}`).join(", ");
|
|
735
742
|
}
|
|
736
743
|
else {
|
|
737
744
|
return this.prepareColumnSet(selectParams, allowed_cols, true, true);
|
|
@@ -744,7 +751,7 @@ class ViewHandler {
|
|
|
744
751
|
* Parses group or simple filter
|
|
745
752
|
*/
|
|
746
753
|
async prepareWhere(params) {
|
|
747
|
-
const { filter, select, forcedFilter, filterFields: ff, addKeywords = true, tableAlias
|
|
754
|
+
const { filter, select, forcedFilter, filterFields: ff, addKeywords = true, tableAlias, localParams, tableRule } = params;
|
|
748
755
|
const { $and: $and_key, $or: $or_key } = this.dboBuilder.prostgles.keywords;
|
|
749
756
|
let filterFields = ff;
|
|
750
757
|
/* Local update allow all. TODO -> FIX THIS */
|
|
@@ -754,7 +761,7 @@ class ViewHandler {
|
|
|
754
761
|
if (!f)
|
|
755
762
|
throw "Invalid/missing group filter provided";
|
|
756
763
|
let result = "";
|
|
757
|
-
let keys =
|
|
764
|
+
let keys = getKeys(f);
|
|
758
765
|
if (!keys.length)
|
|
759
766
|
return result;
|
|
760
767
|
if ((keys.includes($and_key) || keys.includes($or_key))) {
|
|
@@ -776,7 +783,7 @@ class ViewHandler {
|
|
|
776
783
|
}
|
|
777
784
|
else if (!group) {
|
|
778
785
|
result = await this.getCondition({
|
|
779
|
-
filter:
|
|
786
|
+
filter: { ...f },
|
|
780
787
|
select,
|
|
781
788
|
allowed_colnames: this.parseFieldFilter(filterFields),
|
|
782
789
|
tableAlias,
|
|
@@ -788,7 +795,7 @@ class ViewHandler {
|
|
|
788
795
|
};
|
|
789
796
|
if (!isPlainObject(filter))
|
|
790
797
|
throw "\nInvalid filter\nExpecting an object but got -> " + JSON.stringify(filter);
|
|
791
|
-
let _filter =
|
|
798
|
+
let _filter = { ...filter };
|
|
792
799
|
if (forcedFilter) {
|
|
793
800
|
_filter = {
|
|
794
801
|
[$and_key]: [forcedFilter, _filter].filter(f => f)
|
|
@@ -801,7 +808,7 @@ class ViewHandler {
|
|
|
801
808
|
cond = "WHERE " + cond;
|
|
802
809
|
return cond || "";
|
|
803
810
|
}
|
|
804
|
-
async prepareExistCondition(eConfig, localParams
|
|
811
|
+
async prepareExistCondition(eConfig, localParams) {
|
|
805
812
|
let res = "";
|
|
806
813
|
const thisTable = this.name;
|
|
807
814
|
const isNotExists = ["$notExists", "$notExistsJoined"].includes(eConfig.existType);
|
|
@@ -824,7 +831,7 @@ class ViewHandler {
|
|
|
824
831
|
if (!depth && eConfig.shortestJoin)
|
|
825
832
|
exactPaths = undefined;
|
|
826
833
|
const jinf = this.getJoins(t1, t2, exactPaths, true);
|
|
827
|
-
expectOne = expectOne && jinf.expectOne;
|
|
834
|
+
expectOne = Boolean(expectOne && jinf.expectOne);
|
|
828
835
|
joinPaths = joinPaths.concat(jinf.paths);
|
|
829
836
|
});
|
|
830
837
|
let r = makeJoin({ paths: joinPaths, expectOne }, 0);
|
|
@@ -832,13 +839,13 @@ class ViewHandler {
|
|
|
832
839
|
function makeJoin(joinInfo, ji) {
|
|
833
840
|
const { paths } = joinInfo;
|
|
834
841
|
const jp = paths[ji];
|
|
835
|
-
let prevTable = ji
|
|
842
|
+
// let prevTable = ji? paths[ji - 1].table : jp.source;
|
|
836
843
|
let table = paths[ji].table;
|
|
837
|
-
let tableAlias = prostgles_types_1.asName(ji < paths.length - 1 ? `jd${ji}` : table);
|
|
838
|
-
let prevTableAlias = prostgles_types_1.asName(ji ? `jd${ji - 1}` : thisTable);
|
|
839
|
-
let cond = `${jp.on.map(([c1, c2]) => `${prevTableAlias}.${prostgles_types_1.asName(c1)} = ${tableAlias}.${prostgles_types_1.asName(c2)}`).join("\n AND ")}`;
|
|
844
|
+
let tableAlias = (0, prostgles_types_1.asName)(ji < paths.length - 1 ? `jd${ji}` : table);
|
|
845
|
+
let prevTableAlias = (0, prostgles_types_1.asName)(ji ? `jd${ji - 1}` : thisTable);
|
|
846
|
+
let cond = `${jp.on.map(([c1, c2]) => `${prevTableAlias}.${(0, prostgles_types_1.asName)(c1)} = ${tableAlias}.${(0, prostgles_types_1.asName)(c2)}`).join("\n AND ")}`;
|
|
840
847
|
let j = `SELECT 1 \n` +
|
|
841
|
-
`FROM ${prostgles_types_1.asName(table)} ${tableAlias} \n` +
|
|
848
|
+
`FROM ${(0, prostgles_types_1.asName)(table)} ${tableAlias} \n` +
|
|
842
849
|
`WHERE ${cond} \n`; //
|
|
843
850
|
if (ji === paths.length - 1 &&
|
|
844
851
|
finalFilter) {
|
|
@@ -881,7 +888,7 @@ class ViewHandler {
|
|
|
881
888
|
throw "Issue with preparing $exists query for table " + t2 + "\n->" + JSON.stringify(err);
|
|
882
889
|
}
|
|
883
890
|
if (!isJoined) {
|
|
884
|
-
res = `${isNotExists ? " NOT " : " "} EXISTS (SELECT 1 \nFROM ${prostgles_types_1.asName(t2)} \n${finalWhere ? `WHERE ${finalWhere}` : ""}) `;
|
|
891
|
+
res = `${isNotExists ? " NOT " : " "} EXISTS (SELECT 1 \nFROM ${(0, prostgles_types_1.asName)(t2)} \n${finalWhere ? `WHERE ${finalWhere}` : ""}) `;
|
|
885
892
|
}
|
|
886
893
|
else {
|
|
887
894
|
res = makeTableChain(finalWhere);
|
|
@@ -896,9 +903,9 @@ class ViewHandler {
|
|
|
896
903
|
*/
|
|
897
904
|
async getCondition(params) {
|
|
898
905
|
const { filter, select, allowed_colnames, tableAlias, localParams, tableRules } = params;
|
|
899
|
-
let data =
|
|
906
|
+
let data = { ...filter };
|
|
900
907
|
/* Exists join filter */
|
|
901
|
-
const ERR = "Invalid exists filter. \nExpecting somethibng like: { $exists: { tableName.tableName2: Filter } } | { $exists: { \"**.tableName3\": Filter } }";
|
|
908
|
+
const ERR = "Invalid exists filter. \nExpecting somethibng like: { $exists: { tableName.tableName2: Filter } } | { $exists: { \"**.tableName3\": Filter } }\n";
|
|
902
909
|
const SP_WILDCARD = "**";
|
|
903
910
|
let existsKeys = Object.keys(data)
|
|
904
911
|
.filter(k => exports.EXISTS_KEYS.includes(k) && Object.keys(data[k] || {}).length)
|
|
@@ -945,8 +952,8 @@ class ViewHandler {
|
|
|
945
952
|
funcFilterkeys.map(f => {
|
|
946
953
|
const funcArgs = data[f.name];
|
|
947
954
|
if (!Array.isArray(funcArgs))
|
|
948
|
-
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
|
+
throw `A function filter must contain an array. E.g: { $funcFilterName: ["col1"] } \n but got: ${JSON.stringify((0, PubSubManager_1.filterObj)(data, [f.name]))} `;
|
|
956
|
+
const fields = this.parseFieldFilter(f.getFields(funcArgs), true, allowed_colnames);
|
|
950
957
|
const dissallowedCols = fields.filter(fname => !allowed_colnames.includes(fname));
|
|
951
958
|
if (dissallowedCols.length) {
|
|
952
959
|
throw `Invalid/disallowed columns found in function filter: ${dissallowedCols}`;
|
|
@@ -955,7 +962,7 @@ class ViewHandler {
|
|
|
955
962
|
});
|
|
956
963
|
let existsCond = "";
|
|
957
964
|
if (existsKeys.length) {
|
|
958
|
-
existsCond = (await Promise.all(existsKeys.map(async (k) => await this.prepareExistCondition(k, localParams
|
|
965
|
+
existsCond = (await Promise.all(existsKeys.map(async (k) => await this.prepareExistCondition(k, localParams)))).join(" AND ");
|
|
959
966
|
}
|
|
960
967
|
/* Computed field queries */
|
|
961
968
|
const p = this.getValidatedRules(tableRules, localParams);
|
|
@@ -1002,7 +1009,43 @@ class ViewHandler {
|
|
|
1002
1009
|
selected: false,
|
|
1003
1010
|
getFields: () => [f.name]
|
|
1004
1011
|
})));
|
|
1005
|
-
|
|
1012
|
+
/* Parse complex filters
|
|
1013
|
+
{ $filter: [{ $func: [...] }, "=", value | { $func: [..] }] }
|
|
1014
|
+
*/
|
|
1015
|
+
const complexFilters = [];
|
|
1016
|
+
const complexFilterKey = "$filter";
|
|
1017
|
+
const allowedComparators = [">", "<", "=", "<=", ">=", "<>", "!="];
|
|
1018
|
+
if (complexFilterKey in data) {
|
|
1019
|
+
const getFuncQuery = (funcData) => {
|
|
1020
|
+
const { funcName, args } = (0, QueryBuilder_1.parseFunctionObject)(funcData);
|
|
1021
|
+
const funcDef = (0, QueryBuilder_1.parseFunction)({ func: funcName, args, functions: QueryBuilder_1.FUNCTIONS, allowedFields: allowed_colnames });
|
|
1022
|
+
return funcDef.getQuery({ args, tableAlias, allColumns: this.columns, allowedFields: allowed_colnames });
|
|
1023
|
+
};
|
|
1024
|
+
const complexFilter = data[complexFilterKey];
|
|
1025
|
+
if (!Array.isArray(complexFilter))
|
|
1026
|
+
throw `Invalid $filter. Must contain an array of at least element but got: ${JSON.stringify(complexFilter)} `;
|
|
1027
|
+
const leftFilter = complexFilter[0];
|
|
1028
|
+
const comparator = complexFilter[1];
|
|
1029
|
+
const rightFilterOrValue = complexFilter[2];
|
|
1030
|
+
const leftVal = getFuncQuery(leftFilter);
|
|
1031
|
+
let result = leftVal;
|
|
1032
|
+
if (comparator) {
|
|
1033
|
+
if (!allowedComparators.includes(comparator))
|
|
1034
|
+
throw `Invalid $filter. comparator ${JSON.stringify(comparator)} is not valid. Expecting one of: ${allowedComparators}`;
|
|
1035
|
+
if (!rightFilterOrValue)
|
|
1036
|
+
throw "Invalid $filter. Expecting a value or function after the comparator";
|
|
1037
|
+
const rightVal = (0, utils_1.isObject)(rightFilterOrValue) ? getFuncQuery(rightFilterOrValue) : (0, PubSubManager_1.asValue)(rightFilterOrValue);
|
|
1038
|
+
if (leftVal === rightVal)
|
|
1039
|
+
throw "Invalid $filter. Cannot compare two identical function signatures: " + JSON.stringify(leftFilter);
|
|
1040
|
+
result += ` ${comparator} ${rightVal}`;
|
|
1041
|
+
}
|
|
1042
|
+
complexFilters.push(result);
|
|
1043
|
+
}
|
|
1044
|
+
/* Parse join filters
|
|
1045
|
+
{ $joinFilter: { $ST_DWithin: [table.col, foreignTable.col, distance] }
|
|
1046
|
+
will make an exists filter
|
|
1047
|
+
*/
|
|
1048
|
+
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
1049
|
// if(allowed_colnames){
|
|
1007
1050
|
// const aliasedColumns = (select || []).filter(s =>
|
|
1008
1051
|
// ["function", "computed", "column"].includes(s.type) && allowed_colnames.includes(s.alias) ||
|
|
@@ -1020,8 +1063,8 @@ class ViewHandler {
|
|
|
1020
1063
|
}
|
|
1021
1064
|
/* TODO: Allow filter funcs */
|
|
1022
1065
|
// const singleFuncs = FUNCTIONS.filter(f => f.singleColArg);
|
|
1023
|
-
const f = PubSubManager_1.filterObj(data, filterKeys);
|
|
1024
|
-
const q = Filtering_1.parseFilterItem({
|
|
1066
|
+
const f = (0, PubSubManager_1.filterObj)(data, filterKeys);
|
|
1067
|
+
const q = (0, Filtering_1.parseFilterItem)({
|
|
1025
1068
|
filter: f,
|
|
1026
1069
|
tableAlias,
|
|
1027
1070
|
pgp: exports.pgp,
|
|
@@ -1032,6 +1075,7 @@ class ViewHandler {
|
|
|
1032
1075
|
templates.push(existsCond);
|
|
1033
1076
|
templates = templates.concat(funcConds);
|
|
1034
1077
|
templates = templates.concat(computedColConditions);
|
|
1078
|
+
templates = templates.concat(complexFilters);
|
|
1035
1079
|
return templates.sort() /* sorted to ensure duplicate subscription channels are not created due to different condition order */
|
|
1036
1080
|
.join(" AND \n");
|
|
1037
1081
|
// return templates; //pgp.as.format(template, data);
|
|
@@ -1135,7 +1179,7 @@ class ViewHandler {
|
|
|
1135
1179
|
const orderType = asc ? " ASC " : " DESC ";
|
|
1136
1180
|
const index = selectedAliases.indexOf(key) + 1;
|
|
1137
1181
|
const nullOrder = nulls ? ` NULLS ${nulls === "first" ? " FIRST " : " LAST "}` : "";
|
|
1138
|
-
let colKey = (index > 0 && !nullEmpty) ? index : [tableAlias, key].filter(
|
|
1182
|
+
let colKey = (index > 0 && !nullEmpty) ? index : [tableAlias, key].filter(utils_1.isDefined).map(prostgles_types_1.asName).join(".");
|
|
1139
1183
|
if (nullEmpty) {
|
|
1140
1184
|
colKey = `nullif(trim(${colKey}::text), '')`;
|
|
1141
1185
|
}
|
|
@@ -1203,11 +1247,11 @@ class ViewHandler {
|
|
|
1203
1247
|
if (!column_names || !column_names.length)
|
|
1204
1248
|
throw "table column_names mising";
|
|
1205
1249
|
let _allowed_cols = column_names.slice(0);
|
|
1206
|
-
let _obj =
|
|
1250
|
+
let _obj = { ...obj };
|
|
1207
1251
|
if (allowed_cols) {
|
|
1208
1252
|
_allowed_cols = this.parseFieldFilter(allowed_cols, false);
|
|
1209
1253
|
}
|
|
1210
|
-
let final_filter =
|
|
1254
|
+
let final_filter = { ..._obj }, filter_keys = Object.keys(final_filter);
|
|
1211
1255
|
if (fixIssues && filter_keys.length) {
|
|
1212
1256
|
final_filter = {};
|
|
1213
1257
|
filter_keys
|
|
@@ -1221,7 +1265,7 @@ class ViewHandler {
|
|
|
1221
1265
|
validateObj(final_filter, _allowed_cols);
|
|
1222
1266
|
}
|
|
1223
1267
|
if (forcedData && Object.keys(forcedData).length) {
|
|
1224
|
-
final_filter =
|
|
1268
|
+
final_filter = { ...final_filter, ...forcedData };
|
|
1225
1269
|
}
|
|
1226
1270
|
validateObj(final_filter, column_names.slice(0));
|
|
1227
1271
|
return final_filter;
|
|
@@ -1238,7 +1282,7 @@ class ViewHandler {
|
|
|
1238
1282
|
if (!all_cols)
|
|
1239
1283
|
throw "all_cols missing";
|
|
1240
1284
|
const all_fields = all_cols; // || this.column_names.slice(0);
|
|
1241
|
-
let colNames =
|
|
1285
|
+
let colNames = [], initialParams = JSON.stringify(fieldParams);
|
|
1242
1286
|
if (fieldParams) {
|
|
1243
1287
|
/*
|
|
1244
1288
|
"field1, field2, field4" | "*"
|
|
@@ -1381,7 +1425,7 @@ class TableHandler extends ViewHandler {
|
|
|
1381
1425
|
console.error({ localParams, localFunc });
|
|
1382
1426
|
throw " Cannot have localFunc AND socket ";
|
|
1383
1427
|
}
|
|
1384
|
-
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {}, condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias:
|
|
1428
|
+
const { filterFields, forcedFilter } = (0, utils_1.get)(table_rules, "select") || {}, condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }), throttle = (0, utils_1.get)(params, "throttle") || 0, selectParams = (0, PubSubManager_1.filterObj)(params || {}, [], ["throttle"]);
|
|
1385
1429
|
// const { subOne = false } = localParams || {};
|
|
1386
1430
|
const filterSize = JSON.stringify(filter || {}).length;
|
|
1387
1431
|
if (filterSize * 4 > 2704) {
|
|
@@ -1390,23 +1434,23 @@ class TableHandler extends ViewHandler {
|
|
|
1390
1434
|
if (!localFunc) {
|
|
1391
1435
|
if (!this.dboBuilder.prostgles.isSuperUser)
|
|
1392
1436
|
throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
1393
|
-
return await this.find(filter,
|
|
1437
|
+
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
1394
1438
|
.then(async (isValid) => {
|
|
1395
|
-
const { socket
|
|
1439
|
+
const { socket } = localParams ?? {};
|
|
1396
1440
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
1397
1441
|
return pubSubManager.addSub({
|
|
1398
1442
|
table_info: this.tableOrViewInfo,
|
|
1399
1443
|
socket,
|
|
1400
1444
|
table_rules,
|
|
1401
1445
|
condition: condition,
|
|
1402
|
-
func:
|
|
1403
|
-
filter:
|
|
1404
|
-
params:
|
|
1405
|
-
|
|
1406
|
-
socket_id: socket.id,
|
|
1446
|
+
func: undefined,
|
|
1447
|
+
filter: { ...filter },
|
|
1448
|
+
params: { ...selectParams },
|
|
1449
|
+
socket_id: socket?.id,
|
|
1407
1450
|
table_name: this.name,
|
|
1408
1451
|
throttle,
|
|
1409
1452
|
last_throttled: 0,
|
|
1453
|
+
// subOne
|
|
1410
1454
|
}).then(channelName => ({ channelName }));
|
|
1411
1455
|
});
|
|
1412
1456
|
}
|
|
@@ -1414,17 +1458,17 @@ class TableHandler extends ViewHandler {
|
|
|
1414
1458
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
1415
1459
|
pubSubManager.addSub({
|
|
1416
1460
|
table_info: this.tableOrViewInfo,
|
|
1417
|
-
socket:
|
|
1461
|
+
socket: undefined,
|
|
1418
1462
|
table_rules,
|
|
1419
1463
|
condition,
|
|
1420
1464
|
func: localFunc,
|
|
1421
|
-
filter:
|
|
1422
|
-
params:
|
|
1423
|
-
|
|
1424
|
-
socket_id: null,
|
|
1465
|
+
filter: { ...filter },
|
|
1466
|
+
params: { ...selectParams },
|
|
1467
|
+
socket_id: undefined,
|
|
1425
1468
|
table_name: this.name,
|
|
1426
1469
|
throttle,
|
|
1427
1470
|
last_throttled: 0,
|
|
1471
|
+
// subOne
|
|
1428
1472
|
}).then(channelName => ({ channelName }));
|
|
1429
1473
|
const unsubscribe = async () => {
|
|
1430
1474
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
@@ -1442,11 +1486,11 @@ class TableHandler extends ViewHandler {
|
|
|
1442
1486
|
}
|
|
1443
1487
|
subscribeOne(filter, params = {}, localFunc, table_rules, localParams) {
|
|
1444
1488
|
let func = localParams ? undefined : (rows) => localFunc(rows[0]);
|
|
1445
|
-
return this.subscribe(filter,
|
|
1489
|
+
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
1446
1490
|
}
|
|
1447
|
-
async updateBatch(data, params, tableRules, localParams
|
|
1491
|
+
async updateBatch(data, params, tableRules, localParams) {
|
|
1448
1492
|
try {
|
|
1449
|
-
const queries = await Promise.all(data.map(async ([filter, data]) => await this.update(filter, data,
|
|
1493
|
+
const queries = await Promise.all(data.map(async ([filter, data]) => await this.update(filter, data, { ...(params || {}), returning: undefined }, tableRules, { ...(localParams || {}), returnQuery: true })));
|
|
1450
1494
|
const keys = (data && data.length) ? Object.keys(data[0]) : [];
|
|
1451
1495
|
return this.db.tx(t => {
|
|
1452
1496
|
const _queries = queries.map(q => t.none(q));
|
|
@@ -1459,10 +1503,9 @@ class TableHandler extends ViewHandler {
|
|
|
1459
1503
|
throw { err: parseError(e), msg: `Issue with dbo.${this.name}.update()` };
|
|
1460
1504
|
}
|
|
1461
1505
|
}
|
|
1462
|
-
async update(filter, newData, params, tableRules, localParams
|
|
1463
|
-
var _a;
|
|
1506
|
+
async update(filter, newData, params, tableRules, localParams) {
|
|
1464
1507
|
try {
|
|
1465
|
-
const { testRule = false, returnQuery = false } = localParams
|
|
1508
|
+
const { testRule = false, returnQuery = false } = localParams ?? {};
|
|
1466
1509
|
if (!testRule) {
|
|
1467
1510
|
if (!newData || !Object.keys(newData).length)
|
|
1468
1511
|
throw "no update data provided\nEXPECTING db.table.update(filter, updateData, options)";
|
|
@@ -1474,7 +1517,7 @@ class TableHandler extends ViewHandler {
|
|
|
1474
1517
|
throw "update rules missing for " + this.name;
|
|
1475
1518
|
({ forcedFilter, forcedData, returningFields, fields, filterFields, validate } = tableRules.update);
|
|
1476
1519
|
if (!returningFields)
|
|
1477
|
-
returningFields = utils_1.get(tableRules, "select.fields");
|
|
1520
|
+
returningFields = (0, utils_1.get)(tableRules, "select.fields");
|
|
1478
1521
|
if (!fields)
|
|
1479
1522
|
throw ` Invalid update rule for ${this.name}. fields missing `;
|
|
1480
1523
|
/* Safely test publish rules */
|
|
@@ -1482,7 +1525,7 @@ class TableHandler extends ViewHandler {
|
|
|
1482
1525
|
await this.validateViewRules(fields, filterFields, returningFields, forcedFilter, "update");
|
|
1483
1526
|
if (forcedData) {
|
|
1484
1527
|
try {
|
|
1485
|
-
const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData:
|
|
1528
|
+
const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData: undefined, allowedFields: "*", tableRules, fixIssues: false });
|
|
1486
1529
|
const updateQ = await this.colSet.getUpdateQuery(data, allowedCols, validate); //pgp.helpers.update(data, columnSet)
|
|
1487
1530
|
let query = updateQ + " WHERE FALSE ";
|
|
1488
1531
|
await this.db.any("EXPLAIN " + query);
|
|
@@ -1516,27 +1559,27 @@ class TableHandler extends ViewHandler {
|
|
|
1516
1559
|
const unrecProps = Object.keys(d).filter(k => !["from", "to", "text", "md5"].includes(k));
|
|
1517
1560
|
if (unrecProps.length)
|
|
1518
1561
|
throw "Unrecognised params in textPatch field: " + unrecProps.join(", ");
|
|
1519
|
-
patchedTextData.push(
|
|
1562
|
+
patchedTextData.push({ ...d, fieldName: c.name });
|
|
1520
1563
|
}
|
|
1521
1564
|
});
|
|
1522
1565
|
if (patchedTextData && patchedTextData.length) {
|
|
1523
1566
|
if (tableRules && !tableRules.select)
|
|
1524
1567
|
throw "Select needs to be permitted to patch data";
|
|
1525
|
-
const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => (
|
|
1568
|
+
const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) }, undefined, tableRules);
|
|
1526
1569
|
if (rows.length !== 1) {
|
|
1527
1570
|
throw "Cannot patch data within a filter that affects more/less than 1 row";
|
|
1528
1571
|
}
|
|
1529
1572
|
patchedTextData.map(p => {
|
|
1530
|
-
data[p.fieldName] = prostgles_types_1.unpatchText(rows[0][p.fieldName], p);
|
|
1573
|
+
data[p.fieldName] = (0, prostgles_types_1.unpatchText)(rows[0][p.fieldName], p);
|
|
1531
1574
|
});
|
|
1532
1575
|
// https://w3resource.com/PostgreSQL/overlay-function.p hp
|
|
1533
1576
|
// overlay(coalesce(status, '') placing 'hom' from 2 for 0)
|
|
1534
1577
|
}
|
|
1535
|
-
let nData =
|
|
1578
|
+
let nData = { ...data };
|
|
1536
1579
|
// if(tableRules && tableRules.update && tableRules?.update?.validate){
|
|
1537
1580
|
// nData = await tableRules.update.validate(nData);
|
|
1538
1581
|
// }
|
|
1539
|
-
let query = await this.colSet.getUpdateQuery(nData, allowedCols,
|
|
1582
|
+
let query = await this.colSet.getUpdateQuery(nData, allowedCols, tableRules?.update?.validate); //pgp.helpers.update(nData, columnSet) + " ";
|
|
1540
1583
|
query += (await this.prepareWhere({
|
|
1541
1584
|
filter,
|
|
1542
1585
|
forcedFilter,
|
|
@@ -1554,7 +1597,7 @@ class TableHandler extends ViewHandler {
|
|
|
1554
1597
|
if (returnQuery)
|
|
1555
1598
|
return query;
|
|
1556
1599
|
if (this.t) {
|
|
1557
|
-
return this.t[qType](query).catch(err => makeErr(err, localParams, this, _fields));
|
|
1600
|
+
return this.t[qType](query).catch((err) => makeErr(err, localParams, this, _fields));
|
|
1558
1601
|
}
|
|
1559
1602
|
return this.db.tx(t => t[qType](query)).catch(err => makeErr(err, localParams, this, _fields));
|
|
1560
1603
|
}
|
|
@@ -1566,17 +1609,16 @@ class TableHandler extends ViewHandler {
|
|
|
1566
1609
|
}
|
|
1567
1610
|
;
|
|
1568
1611
|
validateNewData({ row, forcedData, allowedFields, tableRules, fixIssues = false }) {
|
|
1569
|
-
const synced_field = utils_1.get(tableRules
|
|
1612
|
+
const synced_field = (0, utils_1.get)(tableRules ?? {}, "sync.synced_field");
|
|
1570
1613
|
/* Update synced_field if sync is on and missing */
|
|
1571
1614
|
if (synced_field && !row[synced_field]) {
|
|
1572
1615
|
row[synced_field] = Date.now();
|
|
1573
1616
|
}
|
|
1574
1617
|
let data = this.prepareFieldValues(row, forcedData, allowedFields, fixIssues);
|
|
1575
|
-
const dataKeys =
|
|
1618
|
+
const dataKeys = getKeys(data);
|
|
1576
1619
|
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);
|
|
1620
|
+
this.dboBuilder.prostgles?.tableConfigurator?.checkColVal({ table: this.name, col, value: data[col] });
|
|
1621
|
+
const colConfig = this.dboBuilder.prostgles?.tableConfigurator?.getColumnConfig(this.name, col);
|
|
1580
1622
|
if (colConfig && "isText" in colConfig && data[col]) {
|
|
1581
1623
|
if (colConfig.lowerCased) {
|
|
1582
1624
|
data[col] = data[col].toString().toLowerCase();
|
|
@@ -1588,12 +1630,11 @@ class TableHandler extends ViewHandler {
|
|
|
1588
1630
|
});
|
|
1589
1631
|
return { data, allowedCols: this.columns.filter(c => dataKeys.includes(c.name)).map(c => c.name) };
|
|
1590
1632
|
}
|
|
1591
|
-
async insertDataParse(data, param2, param3_unused, tableRules, _localParams
|
|
1592
|
-
var _a, _b;
|
|
1633
|
+
async insertDataParse(data, param2, param3_unused, tableRules, _localParams) {
|
|
1593
1634
|
const localParams = _localParams || {};
|
|
1594
|
-
let dbTX =
|
|
1635
|
+
let dbTX = localParams?.dbTX || this.dbTX;
|
|
1595
1636
|
const isMultiInsert = Array.isArray(data);
|
|
1596
|
-
const getExtraKeys = d => Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
|
|
1637
|
+
const getExtraKeys = (d) => Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
|
|
1597
1638
|
/* Nested insert is not allowed for the file table */
|
|
1598
1639
|
const isNestedInsert = this.is_media ? false : (Array.isArray(data) ? data : [data]).some(d => getExtraKeys(d).length);
|
|
1599
1640
|
/**
|
|
@@ -1601,13 +1642,12 @@ class TableHandler extends ViewHandler {
|
|
|
1601
1642
|
*/
|
|
1602
1643
|
if (isNestedInsert && !dbTX) {
|
|
1603
1644
|
return {
|
|
1604
|
-
insertResult: await this.dboBuilder.getTX((dbTX) => dbTX[this.name].insert(data, param2, param3_unused, tableRules,
|
|
1645
|
+
insertResult: await this.dboBuilder.getTX((dbTX) => dbTX[this.name].insert(data, param2, param3_unused, tableRules, { dbTX, ...localParams }))
|
|
1605
1646
|
};
|
|
1606
1647
|
}
|
|
1607
1648
|
// if(!dbTX && this.t) dbTX = this.d;
|
|
1608
|
-
const preValidate =
|
|
1649
|
+
const preValidate = tableRules?.insert?.preValidate, validate = tableRules?.insert?.validate;
|
|
1609
1650
|
let _data = await Promise.all((Array.isArray(data) ? data : [data]).map(async (row) => {
|
|
1610
|
-
var _a, _b;
|
|
1611
1651
|
if (preValidate) {
|
|
1612
1652
|
row = await preValidate(row);
|
|
1613
1653
|
}
|
|
@@ -1615,7 +1655,7 @@ class TableHandler extends ViewHandler {
|
|
|
1615
1655
|
const extraKeys = getExtraKeys(row);
|
|
1616
1656
|
/* Upload file then continue insert */
|
|
1617
1657
|
if (this.is_media) {
|
|
1618
|
-
if (!
|
|
1658
|
+
if (!this.dboBuilder.prostgles?.fileManager)
|
|
1619
1659
|
throw "fileManager not set up";
|
|
1620
1660
|
const { data, name } = row;
|
|
1621
1661
|
if (dataKeys.length !== 2)
|
|
@@ -1642,35 +1682,43 @@ class TableHandler extends ViewHandler {
|
|
|
1642
1682
|
const _media = await this.dboBuilder.prostgles.fileManager.uploadAsMedia({
|
|
1643
1683
|
item: {
|
|
1644
1684
|
data,
|
|
1645
|
-
name: media.name,
|
|
1685
|
+
name: media.name ?? "????",
|
|
1646
1686
|
content_type: media.content_type
|
|
1647
1687
|
},
|
|
1688
|
+
// imageCompression: {
|
|
1689
|
+
// inside: {
|
|
1690
|
+
// width: 1100,
|
|
1691
|
+
// height: 630
|
|
1692
|
+
// }
|
|
1693
|
+
// }
|
|
1648
1694
|
});
|
|
1649
|
-
return
|
|
1695
|
+
return {
|
|
1696
|
+
...media,
|
|
1697
|
+
..._media,
|
|
1698
|
+
};
|
|
1650
1699
|
/* Potentially a nested join */
|
|
1651
1700
|
}
|
|
1652
1701
|
else if (extraKeys.length) {
|
|
1653
1702
|
/* Ensure we're using the same transaction */
|
|
1654
1703
|
const _this = this.t ? this : dbTX[this.name];
|
|
1655
|
-
let rootData = PubSubManager_1.filterObj(data,
|
|
1704
|
+
let rootData = (0, PubSubManager_1.filterObj)(data, undefined, extraKeys);
|
|
1656
1705
|
let insertedChildren;
|
|
1657
1706
|
let targetTableRules;
|
|
1658
|
-
const fullRootResult = await _this.insert(rootData, { returning: "*" },
|
|
1707
|
+
const fullRootResult = await _this.insert(rootData, { returning: "*" }, undefined, tableRules, localParams);
|
|
1659
1708
|
let returnData;
|
|
1660
|
-
const returning = param2
|
|
1709
|
+
const returning = param2?.returning;
|
|
1661
1710
|
if (returning) {
|
|
1662
1711
|
returnData = {};
|
|
1663
|
-
const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(
|
|
1712
|
+
const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(tableRules?.insert?.returningFields));
|
|
1664
1713
|
returningItems.filter(s => s.selected).map(rs => {
|
|
1665
1714
|
returnData[rs.alias] = fullRootResult[rs.alias];
|
|
1666
1715
|
});
|
|
1667
1716
|
}
|
|
1668
1717
|
await Promise.all(extraKeys.map(async (targetTable) => {
|
|
1669
|
-
var _a;
|
|
1670
1718
|
const childDataItems = Array.isArray(row[targetTable]) ? row[targetTable] : [row[targetTable]];
|
|
1671
1719
|
/* Must be allowed to insert into media table */
|
|
1672
1720
|
const canInsert = async (tbl) => {
|
|
1673
|
-
const childRules = await this.dboBuilder.publishParser
|
|
1721
|
+
const childRules = await this.dboBuilder.publishParser?.getValidatedRequestRuleWusr({ tableName: tbl, command: "insert", localParams });
|
|
1674
1722
|
if (!childRules || !childRules.insert)
|
|
1675
1723
|
throw "Dissallowed nested insert into table " + childRules;
|
|
1676
1724
|
return childRules;
|
|
@@ -1682,7 +1730,7 @@ class TableHandler extends ViewHandler {
|
|
|
1682
1730
|
const thisInfo = await this.getInfo();
|
|
1683
1731
|
const childInsert = async (cdata, tableName) => {
|
|
1684
1732
|
// console.log("childInsert", {data, tableName})
|
|
1685
|
-
if (!cdata || !dbTX[tableName] || !("insert" in dbTX[tableName]))
|
|
1733
|
+
if (!cdata || !dbTX?.[tableName] || !("insert" in dbTX[tableName]))
|
|
1686
1734
|
throw "childInsertErr: Child table handler missing for: " + tableName;
|
|
1687
1735
|
const tableRules = await canInsert(tableName);
|
|
1688
1736
|
if (thisInfo.has_media === "one" && thisInfo.media_table_name === tableName && Array.isArray(cdata) && cdata.length > 1) {
|
|
@@ -1690,7 +1738,7 @@ class TableHandler extends ViewHandler {
|
|
|
1690
1738
|
}
|
|
1691
1739
|
return Promise.all((Array.isArray(cdata) ? cdata : [cdata])
|
|
1692
1740
|
.map(m => dbTX[tableName]
|
|
1693
|
-
.insert(m, { returning: "*" },
|
|
1741
|
+
.insert(m, { returning: "*" }, undefined, tableRules, localParams)
|
|
1694
1742
|
.catch(e => {
|
|
1695
1743
|
console.trace({ childInsertErr: e });
|
|
1696
1744
|
return Promise.reject({ childInsertErr: e });
|
|
@@ -1702,7 +1750,7 @@ class TableHandler extends ViewHandler {
|
|
|
1702
1750
|
const cols2 = this.dboBuilder.dbo[tbl2].columns || [];
|
|
1703
1751
|
if (!this.dboBuilder.dbo[tbl2])
|
|
1704
1752
|
throw "Invalid/disallowed table: " + tbl2;
|
|
1705
|
-
const colsRefT1 = cols2
|
|
1753
|
+
const colsRefT1 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl1);
|
|
1706
1754
|
if (!path.length) {
|
|
1707
1755
|
throw "Nested inserts join path not found for " + [this.name, targetTable];
|
|
1708
1756
|
}
|
|
@@ -1712,8 +1760,8 @@ class TableHandler extends ViewHandler {
|
|
|
1712
1760
|
if (!colsRefT1.length)
|
|
1713
1761
|
throw `Target table ${tbl2} does not reference any columns from the root table ${this.name}. Cannot do nested insert`;
|
|
1714
1762
|
// console.log(childDataItems, JSON.stringify(colsRefT1, null, 2))
|
|
1715
|
-
insertedChildren = await childInsert(childDataItems.map(d => {
|
|
1716
|
-
let result =
|
|
1763
|
+
insertedChildren = await childInsert(childDataItems.map((d) => {
|
|
1764
|
+
let result = { ...d };
|
|
1717
1765
|
colsRefT1.map(col => {
|
|
1718
1766
|
result[col.references.cols[0]] = fullRootResult[col.references.fcols[0]];
|
|
1719
1767
|
});
|
|
@@ -1724,10 +1772,10 @@ class TableHandler extends ViewHandler {
|
|
|
1724
1772
|
else if (path.length === 3) {
|
|
1725
1773
|
if (targetTable !== tbl3)
|
|
1726
1774
|
throw "Did not expect this";
|
|
1727
|
-
const colsRefT3 = cols2
|
|
1775
|
+
const colsRefT3 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl3);
|
|
1728
1776
|
if (!colsRefT1.length || !colsRefT3.length)
|
|
1729
1777
|
throw "Incorrectly referenced or missing columns for nested insert";
|
|
1730
|
-
if (targetTable !== this.dboBuilder.prostgles.fileManager
|
|
1778
|
+
if (targetTable !== this.dboBuilder.prostgles.fileManager?.tableName) {
|
|
1731
1779
|
throw "Only media allowed to have nested inserts more than 2 tables apart";
|
|
1732
1780
|
}
|
|
1733
1781
|
/* We expect tbl2 to have only 2 columns (media_id and foreign_id) */
|
|
@@ -1753,11 +1801,11 @@ class TableHandler extends ViewHandler {
|
|
|
1753
1801
|
throw "Unexpected path for Nested inserts";
|
|
1754
1802
|
}
|
|
1755
1803
|
/* Return also the nested inserted data */
|
|
1756
|
-
if (targetTableRules &&
|
|
1804
|
+
if (targetTableRules && insertedChildren?.length && returning) {
|
|
1757
1805
|
const targetTableHandler = dbTX[targetTable];
|
|
1758
|
-
const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(
|
|
1806
|
+
const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(targetTableRules?.insert?.returningFields));
|
|
1759
1807
|
let clientTargetInserts = insertedChildren.map(d => {
|
|
1760
|
-
let _d =
|
|
1808
|
+
let _d = { ...d };
|
|
1761
1809
|
let res = {};
|
|
1762
1810
|
targetReturning.map(r => {
|
|
1763
1811
|
res[r.alias] = _d[r.alias];
|
|
@@ -1780,8 +1828,7 @@ class TableHandler extends ViewHandler {
|
|
|
1780
1828
|
{ data: result };
|
|
1781
1829
|
return res;
|
|
1782
1830
|
}
|
|
1783
|
-
async insert(rowOrRows, param2, param3_unused, tableRules, _localParams
|
|
1784
|
-
var _a, _b, _e;
|
|
1831
|
+
async insert(rowOrRows, param2, param3_unused, tableRules, _localParams) {
|
|
1785
1832
|
const localParams = _localParams || {};
|
|
1786
1833
|
const { dbTX } = localParams;
|
|
1787
1834
|
try {
|
|
@@ -1796,13 +1843,13 @@ class TableHandler extends ViewHandler {
|
|
|
1796
1843
|
fields = tableRules.insert.fields;
|
|
1797
1844
|
/* If no returning fields specified then take select fields as returning */
|
|
1798
1845
|
if (!returningFields)
|
|
1799
|
-
returningFields = utils_1.get(tableRules, "select.fields") || utils_1.get(tableRules, "insert.fields");
|
|
1846
|
+
returningFields = (0, utils_1.get)(tableRules, "select.fields") || (0, utils_1.get)(tableRules, "insert.fields");
|
|
1800
1847
|
if (!fields)
|
|
1801
1848
|
throw ` invalid insert rule for ${this.name} -> fields missing `;
|
|
1802
1849
|
/* Safely test publish rules */
|
|
1803
1850
|
if (testRule) {
|
|
1804
1851
|
// 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,
|
|
1852
|
+
await this.validateViewRules(fields, undefined, returningFields, undefined, "insert");
|
|
1806
1853
|
if (forcedData) {
|
|
1807
1854
|
const keys = Object.keys(forcedData);
|
|
1808
1855
|
if (keys.length) {
|
|
@@ -1832,19 +1879,18 @@ class TableHandler extends ViewHandler {
|
|
|
1832
1879
|
rowOrRows = {}; //throw "Provide data in param1";
|
|
1833
1880
|
let returningSelect = this.makeReturnQuery(await this.prepareReturning(returning, this.parseFieldFilter(returningFields)));
|
|
1834
1881
|
const makeQuery = async (_row, isOne = false) => {
|
|
1835
|
-
|
|
1836
|
-
let row = Object.assign({}, _row);
|
|
1882
|
+
let row = { ..._row };
|
|
1837
1883
|
if (!isPojoObject(row)) {
|
|
1838
1884
|
console.trace(row);
|
|
1839
1885
|
throw "\ninvalid insert data provided -> " + JSON.stringify(row);
|
|
1840
1886
|
}
|
|
1841
1887
|
const { data, allowedCols } = this.validateNewData({ row, forcedData, allowedFields: fields, tableRules, fixIssues });
|
|
1842
|
-
let _data =
|
|
1888
|
+
let _data = { ...data };
|
|
1843
1889
|
let insertQ = "";
|
|
1844
1890
|
if (!Object.keys(_data).length)
|
|
1845
|
-
insertQ = `INSERT INTO ${prostgles_types_1.asName(this.name)} DEFAULT VALUES `;
|
|
1891
|
+
insertQ = `INSERT INTO ${(0, prostgles_types_1.asName)(this.name)} DEFAULT VALUES `;
|
|
1846
1892
|
else
|
|
1847
|
-
insertQ = await this.colSet.getInsertQuery(_data, allowedCols,
|
|
1893
|
+
insertQ = await this.colSet.getInsertQuery(_data, allowedCols, tableRules?.insert?.validate); // pgp.helpers.insert(_data, columnSet);
|
|
1848
1894
|
return insertQ + conflict_query + returningSelect;
|
|
1849
1895
|
};
|
|
1850
1896
|
let query = "";
|
|
@@ -1877,12 +1923,12 @@ class TableHandler extends ViewHandler {
|
|
|
1877
1923
|
return query;
|
|
1878
1924
|
let result;
|
|
1879
1925
|
if (this.dboBuilder.prostgles.opts.DEBUG_MODE) {
|
|
1880
|
-
console.log(
|
|
1926
|
+
console.log(this.t?.ctx?.start, "insert in " + this.name, data);
|
|
1881
1927
|
}
|
|
1882
|
-
const tx =
|
|
1928
|
+
const tx = dbTX?.[this.name]?.t || this.t;
|
|
1883
1929
|
const allowedFieldKeys = this.parseFieldFilter(fields);
|
|
1884
1930
|
if (tx) {
|
|
1885
|
-
result = tx[queryType](query).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
1931
|
+
result = tx[queryType](query).catch((err) => makeErr(err, localParams, this, allowedFieldKeys));
|
|
1886
1932
|
}
|
|
1887
1933
|
else {
|
|
1888
1934
|
result = this.db.tx(t => t[queryType](query)).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
@@ -1900,11 +1946,11 @@ class TableHandler extends ViewHandler {
|
|
|
1900
1946
|
}
|
|
1901
1947
|
;
|
|
1902
1948
|
makeReturnQuery(items) {
|
|
1903
|
-
if (items
|
|
1904
|
-
return " RETURNING " + items.map(s => s.getQuery() + " AS " + prostgles_types_1.asName(s.alias)).join(", ");
|
|
1949
|
+
if (items?.length)
|
|
1950
|
+
return " RETURNING " + items.map(s => s.getQuery() + " AS " + (0, prostgles_types_1.asName)(s.alias)).join(", ");
|
|
1905
1951
|
return "";
|
|
1906
1952
|
}
|
|
1907
|
-
async delete(filter, params, param3_unused, table_rules, localParams
|
|
1953
|
+
async delete(filter, params, param3_unused, table_rules, localParams) {
|
|
1908
1954
|
try {
|
|
1909
1955
|
const { returning } = params || {};
|
|
1910
1956
|
filter = filter || {};
|
|
@@ -1919,14 +1965,14 @@ class TableHandler extends ViewHandler {
|
|
|
1919
1965
|
filterFields = table_rules.delete.filterFields;
|
|
1920
1966
|
returningFields = table_rules.delete.returningFields;
|
|
1921
1967
|
if (!returningFields)
|
|
1922
|
-
returningFields = utils_1.get(table_rules, "select.fields");
|
|
1968
|
+
returningFields = (0, utils_1.get)(table_rules, "select.fields");
|
|
1923
1969
|
if (!returningFields)
|
|
1924
|
-
returningFields = utils_1.get(table_rules, "delete.filterFields");
|
|
1970
|
+
returningFields = (0, utils_1.get)(table_rules, "delete.filterFields");
|
|
1925
1971
|
if (!filterFields)
|
|
1926
1972
|
throw ` Invalid delete rule for ${this.name}. filterFields missing `;
|
|
1927
1973
|
/* Safely test publish rules */
|
|
1928
1974
|
if (testRule) {
|
|
1929
|
-
await this.validateViewRules(
|
|
1975
|
+
await this.validateViewRules(undefined, filterFields, returningFields, forcedFilter, "delete");
|
|
1930
1976
|
return true;
|
|
1931
1977
|
}
|
|
1932
1978
|
}
|
|
@@ -1954,7 +2000,7 @@ class TableHandler extends ViewHandler {
|
|
|
1954
2000
|
}
|
|
1955
2001
|
if (returnQuery)
|
|
1956
2002
|
return _query;
|
|
1957
|
-
return (this.t || this.db)[queryType](_query).catch(err => makeErr(err, localParams));
|
|
2003
|
+
return (this.t || this.db)[queryType](_query).catch((err) => makeErr(err, localParams));
|
|
1958
2004
|
}
|
|
1959
2005
|
catch (e) {
|
|
1960
2006
|
// console.trace(e)
|
|
@@ -1964,10 +2010,10 @@ class TableHandler extends ViewHandler {
|
|
|
1964
2010
|
}
|
|
1965
2011
|
}
|
|
1966
2012
|
;
|
|
1967
|
-
remove(filter, params, param3_unused, tableRules, localParams
|
|
2013
|
+
remove(filter, params, param3_unused, tableRules, localParams) {
|
|
1968
2014
|
return this.delete(filter, params, param3_unused, tableRules, localParams);
|
|
1969
2015
|
}
|
|
1970
|
-
async upsert(filter, newData, params, table_rules, localParams
|
|
2016
|
+
async upsert(filter, newData, params, table_rules, localParams) {
|
|
1971
2017
|
try {
|
|
1972
2018
|
/* Do it within a transaction to ensure consisency */
|
|
1973
2019
|
if (!this.t) {
|
|
@@ -1977,13 +2023,13 @@ class TableHandler extends ViewHandler {
|
|
|
1977
2023
|
return _upsert(this);
|
|
1978
2024
|
}
|
|
1979
2025
|
async function _upsert(tblH) {
|
|
1980
|
-
return tblH.find(filter, { select: "", limit: 1 },
|
|
2026
|
+
return tblH.find(filter, { select: "", limit: 1 }, undefined, table_rules, localParams)
|
|
1981
2027
|
.then(exists => {
|
|
1982
2028
|
if (exists && exists.length) {
|
|
1983
2029
|
return tblH.update(filter, newData, params, table_rules, localParams);
|
|
1984
2030
|
}
|
|
1985
2031
|
else {
|
|
1986
|
-
return tblH.insert(
|
|
2032
|
+
return tblH.insert({ ...newData, ...filter }, params, undefined, table_rules, localParams);
|
|
1987
2033
|
}
|
|
1988
2034
|
});
|
|
1989
2035
|
}
|
|
@@ -2019,11 +2065,11 @@ class TableHandler extends ViewHandler {
|
|
|
2019
2065
|
throw err;
|
|
2020
2066
|
}
|
|
2021
2067
|
id_fields = this.parseFieldFilter(id_fields, false);
|
|
2022
|
-
let allowedSelect = this.parseFieldFilter(utils_1.get(table_rules, "select.fields"), false);
|
|
2068
|
+
let allowedSelect = this.parseFieldFilter((0, utils_1.get)(table_rules, "select.fields"), false);
|
|
2023
2069
|
if (syncFields.find(f => !allowedSelect.includes(f))) {
|
|
2024
2070
|
throw `INTERNAL ERROR: sync field missing from publish.${this.name}.select.fields`;
|
|
2025
2071
|
}
|
|
2026
|
-
let select = this.getAllowedSelectFields(utils_1.get(params || {}, "select") || "*", allowedSelect, false);
|
|
2072
|
+
let select = this.getAllowedSelectFields((0, utils_1.get)(params || {}, "select") || "*", allowedSelect, false);
|
|
2027
2073
|
if (!select.length)
|
|
2028
2074
|
throw "Empty select not allowed";
|
|
2029
2075
|
/* Add sync fields if missing */
|
|
@@ -2032,19 +2078,20 @@ class TableHandler extends ViewHandler {
|
|
|
2032
2078
|
select.push(sf);
|
|
2033
2079
|
});
|
|
2034
2080
|
/* Step 1: parse command and params */
|
|
2035
|
-
return this.find(filter, { select, limit: 0 },
|
|
2081
|
+
return this.find(filter, { select, limit: 0 }, undefined, table_rules, localParams)
|
|
2036
2082
|
.then(async (isValid) => {
|
|
2037
|
-
const { filterFields, forcedFilter } = utils_1.get(table_rules, "select") || {};
|
|
2083
|
+
const { filterFields, forcedFilter } = (0, utils_1.get)(table_rules, "select") || {};
|
|
2038
2084
|
const condition = await this.prepareWhere({ filter, forcedFilter, filterFields, addKeywords: false, localParams, tableRule: table_rules });
|
|
2039
2085
|
// let final_filter = getFindFilter(filter, table_rules);
|
|
2040
2086
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
2041
2087
|
return pubSubManager.addSync({
|
|
2042
2088
|
table_info: this.tableOrViewInfo,
|
|
2043
2089
|
condition,
|
|
2044
|
-
id_fields, synced_field,
|
|
2090
|
+
id_fields, synced_field,
|
|
2091
|
+
allow_delete,
|
|
2045
2092
|
socket,
|
|
2046
2093
|
table_rules,
|
|
2047
|
-
filter:
|
|
2094
|
+
filter: { ...filter },
|
|
2048
2095
|
params: { select }
|
|
2049
2096
|
}).then(channelName => ({ channelName, id_fields, synced_field }));
|
|
2050
2097
|
});
|
|
@@ -2082,7 +2129,7 @@ class TableHandler extends ViewHandler {
|
|
|
2082
2129
|
}
|
|
2083
2130
|
}
|
|
2084
2131
|
exports.TableHandler = TableHandler;
|
|
2085
|
-
const
|
|
2132
|
+
const Prostgles_1 = require("./Prostgles");
|
|
2086
2133
|
class DboBuilder {
|
|
2087
2134
|
constructor(prostgles) {
|
|
2088
2135
|
this.schema = "public";
|
|
@@ -2111,8 +2158,11 @@ class DboBuilder {
|
|
|
2111
2158
|
console.warn(`subscribe and sync cannot be used because db user is not a superuser `);
|
|
2112
2159
|
}
|
|
2113
2160
|
}
|
|
2161
|
+
if (!this._pubSubManager)
|
|
2162
|
+
throw "Could not create this._pubSubManager";
|
|
2114
2163
|
return this._pubSubManager;
|
|
2115
2164
|
};
|
|
2165
|
+
this.joinPaths = [];
|
|
2116
2166
|
this.init = async () => {
|
|
2117
2167
|
/* If watchSchema then PubSubManager must be created */
|
|
2118
2168
|
await this.build();
|
|
@@ -2124,7 +2174,7 @@ class DboBuilder {
|
|
|
2124
2174
|
this.getTX = (cb) => {
|
|
2125
2175
|
return this.db.tx((t) => {
|
|
2126
2176
|
let dbTX = {};
|
|
2127
|
-
this.tablesOrViews
|
|
2177
|
+
this.tablesOrViews?.map(tov => {
|
|
2128
2178
|
if (tov.is_view) {
|
|
2129
2179
|
dbTX[tov.name] = new ViewHandler(this.db, tov, this, t, dbTX, this.joinPaths);
|
|
2130
2180
|
}
|
|
@@ -2145,14 +2195,15 @@ class DboBuilder {
|
|
|
2145
2195
|
});
|
|
2146
2196
|
};
|
|
2147
2197
|
this.prostgles = prostgles;
|
|
2198
|
+
if (!this.prostgles.db)
|
|
2199
|
+
throw "db missing";
|
|
2148
2200
|
this.db = this.prostgles.db;
|
|
2149
2201
|
this.schema = this.prostgles.opts.schema || "public";
|
|
2150
2202
|
this.dbo = {};
|
|
2151
2203
|
// this.joins = this.prostgles.joins;
|
|
2152
2204
|
}
|
|
2153
2205
|
destroy() {
|
|
2154
|
-
|
|
2155
|
-
(_a = this._pubSubManager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
2206
|
+
this._pubSubManager?.destroy();
|
|
2156
2207
|
}
|
|
2157
2208
|
getJoins() {
|
|
2158
2209
|
return this.joins;
|
|
@@ -2185,7 +2236,7 @@ class DboBuilder {
|
|
|
2185
2236
|
}
|
|
2186
2237
|
const tovNames = this.tablesOrViews.map(t => t.name);
|
|
2187
2238
|
// 2 find incorrect tables
|
|
2188
|
-
const missing =
|
|
2239
|
+
const missing = joins.flatMap(j => j.tables).find(t => !tovNames.includes(t));
|
|
2189
2240
|
if (missing) {
|
|
2190
2241
|
throw "Table not found: " + missing;
|
|
2191
2242
|
}
|
|
@@ -2204,11 +2255,11 @@ class DboBuilder {
|
|
|
2204
2255
|
});
|
|
2205
2256
|
});
|
|
2206
2257
|
// 4 find incorrect/missing join types
|
|
2207
|
-
const expected_types = " \n\n-> Expecting: " +
|
|
2258
|
+
const expected_types = " \n\n-> Expecting: " + Prostgles_1.JOIN_TYPES.map(t => JSON.stringify(t)).join(` | `);
|
|
2208
2259
|
const mt = joins.find(j => !j.type);
|
|
2209
2260
|
if (mt)
|
|
2210
2261
|
throw "Join type missing for: " + JSON.stringify(mt, null, 2) + expected_types;
|
|
2211
|
-
const it = joins.find(j => !
|
|
2262
|
+
const it = joins.find(j => !Prostgles_1.JOIN_TYPES.includes(j.type));
|
|
2212
2263
|
if (it)
|
|
2213
2264
|
throw "Incorrect join type for: " + JSON.stringify(it, null, 2) + expected_types;
|
|
2214
2265
|
}
|
|
@@ -2224,11 +2275,11 @@ class DboBuilder {
|
|
|
2224
2275
|
this.joinGraph[t2] = this.joinGraph[t2] || {};
|
|
2225
2276
|
this.joinGraph[t2][t1] = 1;
|
|
2226
2277
|
});
|
|
2227
|
-
const tables =
|
|
2278
|
+
const tables = this.joins.flatMap(t => t.tables);
|
|
2228
2279
|
this.joinPaths = [];
|
|
2229
2280
|
tables.map(t1 => {
|
|
2230
2281
|
tables.map(t2 => {
|
|
2231
|
-
const spath = shortestPath_1.findShortestPath(this.joinGraph, t1, t2);
|
|
2282
|
+
const spath = (0, shortestPath_1.findShortestPath)(this.joinGraph, t1, t2);
|
|
2232
2283
|
if (spath && spath.distance < Infinity) {
|
|
2233
2284
|
const existing1 = this.joinPaths.find(j => j.t1 === t1 && j.t2 === t2);
|
|
2234
2285
|
if (!existing1) {
|
|
@@ -2283,11 +2334,11 @@ export type TxCB = {
|
|
|
2283
2334
|
const TSTableDataName = snakify(tov.name, true);
|
|
2284
2335
|
const TSTableHandlerName = JSON.stringify(tov.name);
|
|
2285
2336
|
if (tov.is_view) {
|
|
2286
|
-
this.dbo[tov.name] = new ViewHandler(this.db, tov, this,
|
|
2337
|
+
this.dbo[tov.name] = new ViewHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
|
|
2287
2338
|
this.dboDefinition += ` ${TSTableHandlerName}: ViewHandler<${TSTableDataName}> \n`;
|
|
2288
2339
|
}
|
|
2289
2340
|
else {
|
|
2290
|
-
this.dbo[tov.name] = new TableHandler(this.db, tov, this,
|
|
2341
|
+
this.dbo[tov.name] = new TableHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
|
|
2291
2342
|
this.dboDefinition += ` ${TSTableHandlerName}: TableHandler<${TSTableDataName}> \n`;
|
|
2292
2343
|
}
|
|
2293
2344
|
allDataDefs += `export type ${TSTableDataName} = { \n` +
|
|
@@ -2297,6 +2348,14 @@ export type TxCB = {
|
|
|
2297
2348
|
if (this.joinPaths && this.joinPaths.find(jp => [jp.t1, jp.t2].includes(tov.name))) {
|
|
2298
2349
|
let table = tov.name;
|
|
2299
2350
|
joinTableNames.push(table);
|
|
2351
|
+
const makeJoin = (isLeft = true, filter, select, options) => {
|
|
2352
|
+
return {
|
|
2353
|
+
[isLeft ? "$leftJoin" : "$innerJoin"]: table,
|
|
2354
|
+
filter,
|
|
2355
|
+
select,
|
|
2356
|
+
...options
|
|
2357
|
+
};
|
|
2358
|
+
};
|
|
2300
2359
|
this.dbo.innerJoin = this.dbo.innerJoin || {};
|
|
2301
2360
|
this.dbo.leftJoin = this.dbo.leftJoin || {};
|
|
2302
2361
|
this.dbo.innerJoinOne = this.dbo.innerJoinOne || {};
|
|
@@ -2308,15 +2367,11 @@ export type TxCB = {
|
|
|
2308
2367
|
return makeJoin(false, filter, select, options);
|
|
2309
2368
|
};
|
|
2310
2369
|
this.dbo.leftJoinOne[table] = (filter, select, options = {}) => {
|
|
2311
|
-
return makeJoin(true, filter, select,
|
|
2370
|
+
return makeJoin(true, filter, select, { ...options, limit: 1 });
|
|
2312
2371
|
};
|
|
2313
2372
|
this.dbo.innerJoinOne[table] = (filter, select, options = {}) => {
|
|
2314
|
-
return makeJoin(false, filter, select,
|
|
2373
|
+
return makeJoin(false, filter, select, { ...options, limit: 1 });
|
|
2315
2374
|
};
|
|
2316
|
-
function makeJoin(isLeft = true, filter, select, options) {
|
|
2317
|
-
return Object.assign({ [isLeft ? "$leftJoin" : "$innerJoin"]: table, filter,
|
|
2318
|
-
select }, options);
|
|
2319
|
-
}
|
|
2320
2375
|
}
|
|
2321
2376
|
});
|
|
2322
2377
|
i18nDef += " }> \n";
|
|
@@ -2344,13 +2399,12 @@ export type TxCB = {
|
|
|
2344
2399
|
let DATA_TYPES = !needType ? [] : await this.db.any("SELECT oid, typname FROM pg_type");
|
|
2345
2400
|
let USER_TABLES = !needType ? [] : await this.db.any("SELECT relid, relname FROM pg_catalog.pg_statio_user_tables");
|
|
2346
2401
|
this.dbo.sql = async (query, params, options, localParams) => {
|
|
2347
|
-
var _a, _b;
|
|
2348
2402
|
const canRunSQL = async (localParams) => {
|
|
2349
2403
|
if (!localParams)
|
|
2350
2404
|
return true;
|
|
2351
2405
|
const { socket } = localParams;
|
|
2352
2406
|
const publishParams = await this.prostgles.publishParser.getPublishParams({ socket });
|
|
2353
|
-
let res = await this.prostgles.opts.publishRawSQL(publishParams);
|
|
2407
|
+
let res = await this.prostgles.opts.publishRawSQL?.(publishParams);
|
|
2354
2408
|
return Boolean(res && typeof res === "boolean" || res === "*");
|
|
2355
2409
|
};
|
|
2356
2410
|
if (!(await canRunSQL(localParams)))
|
|
@@ -2360,7 +2414,7 @@ export type TxCB = {
|
|
|
2360
2414
|
if (returnType === "noticeSubscription") {
|
|
2361
2415
|
if (!socket)
|
|
2362
2416
|
throw "Only allowed with client socket";
|
|
2363
|
-
return await this.prostgles.dbEventsManager
|
|
2417
|
+
return await this.prostgles.dbEventsManager?.addNotice(socket);
|
|
2364
2418
|
}
|
|
2365
2419
|
else if (returnType === "statement") {
|
|
2366
2420
|
try {
|
|
@@ -2375,12 +2429,12 @@ export type TxCB = {
|
|
|
2375
2429
|
if (returnType === "arrayMode") {
|
|
2376
2430
|
finalQuery = new PQ({ text: exports.pgp.as.format(query, params), rowMode: "array" });
|
|
2377
2431
|
}
|
|
2378
|
-
let
|
|
2379
|
-
const {
|
|
2432
|
+
let _qres = await this.db.result(finalQuery, params);
|
|
2433
|
+
const { fields, rows, command } = _qres;
|
|
2380
2434
|
/**
|
|
2381
2435
|
* Fallback for watchSchema in case not superuser and cannot add db event listener
|
|
2382
2436
|
*/
|
|
2383
|
-
const { watchSchema, watchSchemaType } =
|
|
2437
|
+
const { watchSchema, watchSchemaType } = this.prostgles?.opts || {};
|
|
2384
2438
|
if (watchSchema &&
|
|
2385
2439
|
(!this.prostgles.isSuperUser || watchSchemaType === "queries") &&
|
|
2386
2440
|
(["CREATE", "ALTER", "DROP"].includes(command) ||
|
|
@@ -2391,7 +2445,7 @@ export type TxCB = {
|
|
|
2391
2445
|
if (command === "LISTEN") {
|
|
2392
2446
|
if (!socket)
|
|
2393
2447
|
throw "Only allowed with client socket";
|
|
2394
|
-
return await this.prostgles.dbEventsManager
|
|
2448
|
+
return await this.prostgles.dbEventsManager?.addNotify(query, socket);
|
|
2395
2449
|
}
|
|
2396
2450
|
else if (returnType === "rows") {
|
|
2397
2451
|
return rows;
|
|
@@ -2400,18 +2454,26 @@ export type TxCB = {
|
|
|
2400
2454
|
return rows[0];
|
|
2401
2455
|
}
|
|
2402
2456
|
else if (returnType === "value") {
|
|
2403
|
-
return
|
|
2457
|
+
return Object.values(rows?.[0] || {})?.[0];
|
|
2404
2458
|
}
|
|
2405
2459
|
else if (returnType === "values") {
|
|
2406
2460
|
return rows.map(r => Object.values(r[0]));
|
|
2407
2461
|
}
|
|
2408
2462
|
else {
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2463
|
+
let qres = {
|
|
2464
|
+
duration: 0,
|
|
2465
|
+
..._qres,
|
|
2466
|
+
fields: fields?.map(f => {
|
|
2467
|
+
const dataType = DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID)?.typname ?? "text", tableName = USER_TABLES.find(t => +t.relid === +f.tableID), tsDataType = postgresToTsType(dataType);
|
|
2468
|
+
return {
|
|
2469
|
+
...f,
|
|
2470
|
+
tsDataType,
|
|
2471
|
+
dataType,
|
|
2472
|
+
udt_name: dataType,
|
|
2473
|
+
tableName: tableName?.relname
|
|
2474
|
+
};
|
|
2475
|
+
}) ?? []
|
|
2476
|
+
};
|
|
2415
2477
|
return qres;
|
|
2416
2478
|
}
|
|
2417
2479
|
}
|
|
@@ -2437,6 +2499,7 @@ export type TxCB = {
|
|
|
2437
2499
|
}
|
|
2438
2500
|
}
|
|
2439
2501
|
exports.DboBuilder = DboBuilder;
|
|
2502
|
+
_a = DboBuilder;
|
|
2440
2503
|
DboBuilder.create = async (prostgles) => {
|
|
2441
2504
|
let res = new DboBuilder(prostgles);
|
|
2442
2505
|
return await res.init();
|
|
@@ -2449,7 +2512,7 @@ async function getConstraints(db, schema = "public") {
|
|
|
2449
2512
|
ON rel.oid = con.conrelid
|
|
2450
2513
|
INNER JOIN pg_catalog.pg_namespace nsp
|
|
2451
2514
|
ON nsp.oid = connamespace
|
|
2452
|
-
WHERE nsp.nspname = ${PubSubManager_1.asValue(schema)}
|
|
2515
|
+
WHERE nsp.nspname = ${(0, PubSubManager_1.asValue)(schema)}
|
|
2453
2516
|
`);
|
|
2454
2517
|
}
|
|
2455
2518
|
async function getTablesForSchemaPostgresSQL(db, schema = "public") {
|
|
@@ -2563,7 +2626,7 @@ async function getTablesForSchemaPostgresSQL(db, schema = "public") {
|
|
|
2563
2626
|
GROUP BY cl_r.relname
|
|
2564
2627
|
) vr
|
|
2565
2628
|
ON t.table_name = vr.view_name
|
|
2566
|
-
WHERE t.table_schema = ${PubSubManager_1.asValue(schema)}
|
|
2629
|
+
WHERE t.table_schema = ${(0, PubSubManager_1.asValue)(schema)}
|
|
2567
2630
|
GROUP BY t.table_schema, t.table_name, t.table_type, vr.table_names , cc.table_oid
|
|
2568
2631
|
ORDER BY schema, name
|
|
2569
2632
|
`;
|
|
@@ -2608,8 +2671,13 @@ function isPlainObject(o) {
|
|
|
2608
2671
|
return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
|
|
2609
2672
|
}
|
|
2610
2673
|
exports.isPlainObject = isPlainObject;
|
|
2674
|
+
function getKeys(o) {
|
|
2675
|
+
return Object.keys(o);
|
|
2676
|
+
}
|
|
2677
|
+
exports.getKeys = getKeys;
|
|
2611
2678
|
function postgresToTsType(udt_data_type) {
|
|
2612
|
-
return
|
|
2679
|
+
return getKeys(prostgles_types_1.TS_PG_Types).find(k => {
|
|
2680
|
+
// @ts-ignore
|
|
2613
2681
|
return prostgles_types_1.TS_PG_Types[k].includes(udt_data_type) || !prostgles_types_1.TS_PG_Types[k].length;
|
|
2614
2682
|
});
|
|
2615
2683
|
}
|
|
@@ -2857,6 +2925,7 @@ function sqlErrCodeToMsg(code) {
|
|
|
2857
2925
|
"XX001": "data_corrupted",
|
|
2858
2926
|
"XX002": "index_corrupted"
|
|
2859
2927
|
}, 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" };
|
|
2928
|
+
//@ts-ignore
|
|
2860
2929
|
return c2[code] || errs[code] || code;
|
|
2861
2930
|
/*
|
|
2862
2931
|
https://www.postgresql.org/docs/13/errcodes-appendix.html
|
|
@@ -2891,10 +2960,10 @@ async function getInferredJoins(db, schema = "public") {
|
|
|
2891
2960
|
let existing = joins[eIdx];
|
|
2892
2961
|
if (existing) {
|
|
2893
2962
|
if (existing.tables[0] === d.table_name) {
|
|
2894
|
-
existing.on =
|
|
2963
|
+
existing.on = { ...existing.on, [d.column_name]: d.foreign_column_name };
|
|
2895
2964
|
}
|
|
2896
2965
|
else {
|
|
2897
|
-
existing.on =
|
|
2966
|
+
existing.on = { ...existing.on, [d.foreign_column_name]: d.column_name };
|
|
2898
2967
|
}
|
|
2899
2968
|
joins[eIdx] = existing;
|
|
2900
2969
|
}
|