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/lib/DboBuilder.ts
CHANGED
|
@@ -11,7 +11,8 @@ import * as pgPromise from 'pg-promise';
|
|
|
11
11
|
const {ParameterizedQuery: PQ} = require('pg-promise');
|
|
12
12
|
import pg = require('pg-promise/typescript/pg-subset');
|
|
13
13
|
import {
|
|
14
|
-
ColumnInfo, ValidatedColumnInfo, FieldFilter, SelectParams, SubscribeParams,
|
|
14
|
+
ColumnInfo, ValidatedColumnInfo, FieldFilter, SelectParams, SubscribeParams,
|
|
15
|
+
OrderBy, InsertParams, UpdateParams, DeleteParams, SQLOptions,
|
|
15
16
|
DbJoinMaker,
|
|
16
17
|
unpatchText,
|
|
17
18
|
isEmpty,
|
|
@@ -21,6 +22,9 @@ import {
|
|
|
21
22
|
TableInfo as TInfo,
|
|
22
23
|
SQLHandler,
|
|
23
24
|
AnyObject,
|
|
25
|
+
SQLResult,
|
|
26
|
+
Select,
|
|
27
|
+
JoinMaker,
|
|
24
28
|
} from "prostgles-types";
|
|
25
29
|
|
|
26
30
|
export type Media = {
|
|
@@ -69,10 +73,10 @@ export type DbHandler = {
|
|
|
69
73
|
// [key: string]: TX
|
|
70
74
|
// }>
|
|
71
75
|
|
|
72
|
-
import { get } from "./utils";
|
|
73
|
-
import { getNewQuery, makeQuery, COMPUTED_FIELDS, SelectItem, FieldSpec, asNameAlias, SelectItemBuilder, FUNCTIONS } from "./QueryBuilder";
|
|
76
|
+
import { get, isDefined, isObject } from "./utils";
|
|
77
|
+
import { getNewQuery, makeQuery, COMPUTED_FIELDS, SelectItem, FieldSpec, asNameAlias, SelectItemBuilder, FUNCTIONS, parseFunction, parseFunctionObject } from "./QueryBuilder";
|
|
74
78
|
import {
|
|
75
|
-
DB, TableRule, SelectRule, InsertRule, UpdateRule, DeleteRule, SyncRule, Joins, Join, Prostgles, PublishParser,
|
|
79
|
+
DB, TableRule, SelectRule, InsertRule, UpdateRule, DeleteRule, SyncRule, Joins, Join, Prostgles, PublishParser, ValidateRow
|
|
76
80
|
} from "./Prostgles";
|
|
77
81
|
import { PubSubManager, filterObj, asValue, BasicCallback } from "./PubSubManager";
|
|
78
82
|
|
|
@@ -108,8 +112,16 @@ export type PRGLIOSocket = {
|
|
|
108
112
|
headers?: { cookie?: string; } // e.g.: "some_arg=dwdaw; otherarg=23232"
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
readonly on: (channel: string, params: any, cb?: (err: any, res?: any) => void) => Promise<void>;
|
|
116
|
+
|
|
111
117
|
readonly emit: (channel: string, message: any, cb?: BasicCallback) => any;
|
|
112
118
|
|
|
119
|
+
readonly once: (channel: string, cb: (_data: any, cb: BasicCallback) => void) => void;
|
|
120
|
+
|
|
121
|
+
readonly removeAllListeners: (channel: string) => void;
|
|
122
|
+
|
|
123
|
+
readonly disconnect: () => void;
|
|
124
|
+
|
|
113
125
|
/** Used for session caching */
|
|
114
126
|
__prglCache?: {
|
|
115
127
|
session: BasicSession;
|
|
@@ -117,6 +129,8 @@ export type PRGLIOSocket = {
|
|
|
117
129
|
clientUser: AnyObject;
|
|
118
130
|
}
|
|
119
131
|
|
|
132
|
+
_user?: AnyObject
|
|
133
|
+
|
|
120
134
|
/** Used for publish error caching */
|
|
121
135
|
prostgles?: AnyObject;
|
|
122
136
|
};
|
|
@@ -361,7 +375,7 @@ class ColSet {
|
|
|
361
375
|
this.opts = { columns, tableName, colNames: columns.map(c => c.name) }
|
|
362
376
|
}
|
|
363
377
|
|
|
364
|
-
private async getRow(data: any, allowedCols: string[], validate
|
|
378
|
+
private async getRow(data: any, allowedCols: string[], validate?: ValidateRow): Promise<{ escapedCol: string; escapedVal: string }[]> {
|
|
365
379
|
const badCol = allowedCols.find(c => !this.opts.colNames.includes(c))
|
|
366
380
|
if(!allowedCols || badCol){
|
|
367
381
|
throw "Missing or unexpected columns: " + badCol;
|
|
@@ -387,7 +401,7 @@ class ColSet {
|
|
|
387
401
|
let escapedVal: string;
|
|
388
402
|
if(["geometry", "geography"].includes(col.udt_name) && row[key] && isPlainObject(row[key])){
|
|
389
403
|
|
|
390
|
-
const basicFunc = (args) => {
|
|
404
|
+
const basicFunc = (args: any[]) => {
|
|
391
405
|
return args.map(arg => asValue(arg)).join(", ")
|
|
392
406
|
}
|
|
393
407
|
const basicFuncNames = ["ST_GeomFromText", "ST_Point", "ST_MakePoint", "ST_MakePointM", "ST_PointFromText", "ST_GeomFromEWKT", "ST_GeomFromGeoJSON"]
|
|
@@ -413,7 +427,7 @@ class ColSet {
|
|
|
413
427
|
|
|
414
428
|
}
|
|
415
429
|
|
|
416
|
-
async getInsertQuery(data: any[], allowedCols: string[], validate: ValidateRow): Promise<string> {
|
|
430
|
+
async getInsertQuery(data: any[], allowedCols: string[], validate: ValidateRow | undefined): Promise<string> {
|
|
417
431
|
const res = (await Promise.all((Array.isArray(data)? data : [data]).map(async d => {
|
|
418
432
|
const rowParts = await this.getRow(d, allowedCols, validate);
|
|
419
433
|
const select = rowParts.map(r => r.escapedCol).join(", "),
|
|
@@ -423,7 +437,7 @@ class ColSet {
|
|
|
423
437
|
}))).join(";\n") + " ";
|
|
424
438
|
return res;
|
|
425
439
|
}
|
|
426
|
-
async getUpdateQuery(data: any[], allowedCols: string[], validate: ValidateRow): Promise<string> {
|
|
440
|
+
async getUpdateQuery(data: any[], allowedCols: string[], validate: ValidateRow | undefined): Promise<string> {
|
|
427
441
|
const res = (await Promise.all((Array.isArray(data)? data : [data]).map(async d => {
|
|
428
442
|
const rowParts = await this.getRow(d, allowedCols, validate);
|
|
429
443
|
return `UPDATE ${asName(this.opts.tableName)} SET ` + rowParts.map(r => `${r.escapedCol} = ${r.escapedVal} `).join(",\n")
|
|
@@ -483,7 +497,7 @@ export class ViewHandler {
|
|
|
483
497
|
|
|
484
498
|
// this.pubSubManager = pubSubManager;
|
|
485
499
|
this.dboBuilder = dboBuilder;
|
|
486
|
-
this.joins = this.dboBuilder.joins;
|
|
500
|
+
this.joins = this.dboBuilder.joins ?? [];
|
|
487
501
|
|
|
488
502
|
// fix this
|
|
489
503
|
// and also make hot schema reload over ws
|
|
@@ -533,7 +547,7 @@ export class ViewHandler {
|
|
|
533
547
|
`)` + (alias? ` as ${asName(alias)}` : "");
|
|
534
548
|
}
|
|
535
549
|
|
|
536
|
-
async validateViewRules(fields: FieldFilter, filterFields: FieldFilter, returningFields: FieldFilter, forcedFilter:
|
|
550
|
+
async validateViewRules(fields: FieldFilter | undefined, filterFields: FieldFilter | undefined, returningFields: FieldFilter | undefined, forcedFilter: AnyObject | undefined, rule: "update" | "select" | "insert" | "delete"){
|
|
537
551
|
|
|
538
552
|
/* Safely test publish rules */
|
|
539
553
|
if(fields) {
|
|
@@ -932,7 +946,7 @@ export class ViewHandler {
|
|
|
932
946
|
|
|
933
947
|
}
|
|
934
948
|
|
|
935
|
-
async find(filter?: Filter, selectParams?: SelectParams , param3_unused
|
|
949
|
+
async find(filter?: Filter, selectParams?: SelectParams , param3_unused?: never, tableRules?: TableRule, localParams?: LocalParams): Promise<any[]>{
|
|
936
950
|
try {
|
|
937
951
|
filter = filter || {};
|
|
938
952
|
const allowedReturnTypes: Array<SelectParams["returnType"]> = ["row", "value", "values"]
|
|
@@ -954,9 +968,9 @@ export class ViewHandler {
|
|
|
954
968
|
if(tableRules){
|
|
955
969
|
|
|
956
970
|
let fields: FieldFilter,
|
|
957
|
-
filterFields: FieldFilter,
|
|
958
|
-
forcedFilter:
|
|
959
|
-
maxLimit: number;
|
|
971
|
+
filterFields: FieldFilter | undefined,
|
|
972
|
+
forcedFilter: AnyObject | undefined,
|
|
973
|
+
maxLimit: number | undefined | null;
|
|
960
974
|
|
|
961
975
|
if(!tableRules.select) throw "select rules missing for " + this.name;
|
|
962
976
|
fields = tableRules.select.fields;
|
|
@@ -983,7 +997,7 @@ export class ViewHandler {
|
|
|
983
997
|
}
|
|
984
998
|
|
|
985
999
|
if(returnQuery) return (_query as unknown as any[]);
|
|
986
|
-
if(["row", "value"].includes(returnType)) {
|
|
1000
|
+
if(["row", "value"].includes(returnType!)) {
|
|
987
1001
|
return (this.t || this.db).oneOrNone(_query).then(data => {
|
|
988
1002
|
return (data && returnType === "value")? Object.values(data)[0] : data;
|
|
989
1003
|
}).catch(err => makeErr(err, localParams, this));
|
|
@@ -1003,26 +1017,26 @@ export class ViewHandler {
|
|
|
1003
1017
|
}
|
|
1004
1018
|
}
|
|
1005
1019
|
|
|
1006
|
-
findOne(filter?: Filter, selectParams?: SelectParams, param3_unused
|
|
1020
|
+
findOne(filter?: Filter, selectParams?: SelectParams, param3_unused?: never, table_rules?: TableRule, localParams?: LocalParams): Promise<any>{
|
|
1007
1021
|
|
|
1008
1022
|
try {
|
|
1009
|
-
const { select = "*", orderBy
|
|
1023
|
+
const { select = "*", orderBy, offset = 0 } = selectParams || {};
|
|
1010
1024
|
if(selectParams){
|
|
1011
1025
|
const good_params = ["select", "orderBy", "offset"];
|
|
1012
1026
|
const bad_params = Object.keys(selectParams).filter(k => !good_params.includes(k));
|
|
1013
1027
|
if(bad_params && bad_params.length) throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
|
|
1014
1028
|
}
|
|
1015
|
-
return this.find(filter, { select, orderBy, limit: 1, offset, returnType: "row" },
|
|
1029
|
+
return this.find(filter, { select, orderBy, limit: 1, offset, returnType: "row" }, undefined, table_rules, localParams);
|
|
1016
1030
|
} catch(e){
|
|
1017
1031
|
if(localParams && localParams.testRule) throw e;
|
|
1018
1032
|
throw { err: parseError(e), msg: `Issue with dbo.${this.name}.findOne()` };
|
|
1019
1033
|
}
|
|
1020
1034
|
}
|
|
1021
1035
|
|
|
1022
|
-
async count(filter?: Filter, param2_unused
|
|
1036
|
+
async count(filter?: Filter, param2_unused?: never, param3_unused?: never, table_rules?: TableRule, localParams: any = {}): Promise<number>{
|
|
1023
1037
|
filter = filter || {};
|
|
1024
1038
|
try {
|
|
1025
|
-
return await this.find(filter, { select: "", limit: 0 },
|
|
1039
|
+
return await this.find(filter, { select: "", limit: 0 }, undefined, table_rules, localParams)
|
|
1026
1040
|
.then(async allowed => {
|
|
1027
1041
|
const { filterFields, forcedFilter } = get(table_rules, "select") || {};
|
|
1028
1042
|
const where = (await this.prepareWhere({ filter, forcedFilter, filterFields, addKeywords: true, localParams, tableRule: table_rules }));
|
|
@@ -1035,10 +1049,10 @@ export class ViewHandler {
|
|
|
1035
1049
|
}
|
|
1036
1050
|
}
|
|
1037
1051
|
|
|
1038
|
-
async size(filter?: Filter, selectParams?: SelectParams, param3_unused
|
|
1052
|
+
async size(filter?: Filter, selectParams?: SelectParams, param3_unused?: never, table_rules?: TableRule, localParams: any = {}): Promise<string>{
|
|
1039
1053
|
filter = filter || {};
|
|
1040
1054
|
try {
|
|
1041
|
-
return await this.find(filter, { ...selectParams, limit: 2 },
|
|
1055
|
+
return await this.find(filter, { ...selectParams, limit: 2 }, undefined, table_rules, localParams)
|
|
1042
1056
|
.then(async _allowed => {
|
|
1043
1057
|
// let rules: TableRule = table_rules || {};
|
|
1044
1058
|
// rules.select.maxLimit = Number.MAX_SAFE_INTEGER;
|
|
@@ -1046,7 +1060,7 @@ export class ViewHandler {
|
|
|
1046
1060
|
|
|
1047
1061
|
const q: string = await this.find(
|
|
1048
1062
|
filter, { ...selectParams, limit: selectParams?.limit ?? Number.MAX_SAFE_INTEGER },
|
|
1049
|
-
|
|
1063
|
+
undefined,
|
|
1050
1064
|
table_rules,
|
|
1051
1065
|
{ ...localParams, returnQuery: true }
|
|
1052
1066
|
) as any;
|
|
@@ -1068,7 +1082,7 @@ export class ViewHandler {
|
|
|
1068
1082
|
getAllowedSelectFields(selectParams: FieldFilter = "*", allowed_cols: FieldFilter, allow_empty: boolean = true): string[] {
|
|
1069
1083
|
let all_columns = this.column_names.slice(0),
|
|
1070
1084
|
allowedFields = all_columns.slice(0),
|
|
1071
|
-
resultFields = [];
|
|
1085
|
+
resultFields: string[] = [];
|
|
1072
1086
|
|
|
1073
1087
|
if(selectParams){
|
|
1074
1088
|
resultFields = this.parseFieldFilter(selectParams, allow_empty);
|
|
@@ -1121,27 +1135,27 @@ export class ViewHandler {
|
|
|
1121
1135
|
* Parses group or simple filter
|
|
1122
1136
|
*/
|
|
1123
1137
|
async prepareWhere(params: {
|
|
1124
|
-
filter
|
|
1138
|
+
filter?: Filter;
|
|
1125
1139
|
select?: SelectItem[];
|
|
1126
|
-
forcedFilter
|
|
1127
|
-
filterFields
|
|
1140
|
+
forcedFilter?: AnyObject;
|
|
1141
|
+
filterFields?: FieldFilter;
|
|
1128
1142
|
addKeywords?: boolean;
|
|
1129
1143
|
tableAlias?: string,
|
|
1130
|
-
localParams: LocalParams,
|
|
1131
|
-
tableRule: TableRule
|
|
1144
|
+
localParams: LocalParams | undefined,
|
|
1145
|
+
tableRule: TableRule | undefined
|
|
1132
1146
|
}): Promise<string>
|
|
1133
1147
|
{
|
|
1134
|
-
const { filter, select, forcedFilter, filterFields: ff, addKeywords = true, tableAlias
|
|
1148
|
+
const { filter, select, forcedFilter, filterFields: ff, addKeywords = true, tableAlias, localParams, tableRule } = params;
|
|
1135
1149
|
const { $and: $and_key, $or: $or_key } = this.dboBuilder.prostgles.keywords;
|
|
1136
1150
|
|
|
1137
1151
|
let filterFields = ff;
|
|
1138
1152
|
/* Local update allow all. TODO -> FIX THIS */
|
|
1139
1153
|
if(!ff && !tableRule) filterFields = "*";
|
|
1140
1154
|
|
|
1141
|
-
const parseFullFilter = async (f: any, parentFilter: any = null) => {
|
|
1155
|
+
const parseFullFilter = async (f: any, parentFilter: any = null): Promise<string> => {
|
|
1142
1156
|
if(!f) throw "Invalid/missing group filter provided";
|
|
1143
1157
|
let result = "";
|
|
1144
|
-
let keys =
|
|
1158
|
+
let keys = getKeys(f);
|
|
1145
1159
|
if(!keys.length) return result;
|
|
1146
1160
|
if((keys.includes($and_key) || keys.includes($or_key))){
|
|
1147
1161
|
if(keys.length > 1) throw `\ngroup filter must contain only one array property. e.g.: { ${$and_key}: [...] } OR { ${$or_key}: [...] } `;
|
|
@@ -1149,7 +1163,7 @@ export class ViewHandler {
|
|
|
1149
1163
|
}
|
|
1150
1164
|
|
|
1151
1165
|
const { [$and_key]: $and, [$or_key]: $or } = f,
|
|
1152
|
-
group = $and || $or;
|
|
1166
|
+
group: AnyObject[] = $and || $or;
|
|
1153
1167
|
|
|
1154
1168
|
if(group && group.length){
|
|
1155
1169
|
const operand = $and? " AND " : " OR ";
|
|
@@ -1175,7 +1189,7 @@ export class ViewHandler {
|
|
|
1175
1189
|
if(!isPlainObject(filter)) throw "\nInvalid filter\nExpecting an object but got -> " + JSON.stringify(filter);
|
|
1176
1190
|
|
|
1177
1191
|
|
|
1178
|
-
let _filter = { ...
|
|
1192
|
+
let _filter = { ...filter };
|
|
1179
1193
|
if(forcedFilter){
|
|
1180
1194
|
_filter = {
|
|
1181
1195
|
[$and_key]: [forcedFilter, _filter].filter(f => f)
|
|
@@ -1190,7 +1204,7 @@ export class ViewHandler {
|
|
|
1190
1204
|
return cond || "";
|
|
1191
1205
|
}
|
|
1192
1206
|
|
|
1193
|
-
async prepareExistCondition(eConfig: ExistsFilterConfig, localParams: LocalParams
|
|
1207
|
+
async prepareExistCondition(eConfig: ExistsFilterConfig, localParams: LocalParams | undefined): Promise<string> {
|
|
1194
1208
|
let res = "";
|
|
1195
1209
|
const thisTable = this.name;
|
|
1196
1210
|
const isNotExists = ["$notExists", "$notExistsJoined"].includes(eConfig.existType);
|
|
@@ -1214,11 +1228,11 @@ export class ViewHandler {
|
|
|
1214
1228
|
let expectOne = true;
|
|
1215
1229
|
tables.map((t2, depth) => {
|
|
1216
1230
|
let t1 = depth? tables[depth - 1] : thisTable;
|
|
1217
|
-
let exactPaths = [t1, t2];
|
|
1231
|
+
let exactPaths: string[] | undefined = [t1, t2];
|
|
1218
1232
|
|
|
1219
1233
|
if(!depth && eConfig.shortestJoin) exactPaths = undefined;
|
|
1220
1234
|
const jinf= this.getJoins(t1, t2, exactPaths, true);
|
|
1221
|
-
expectOne = expectOne && jinf.expectOne
|
|
1235
|
+
expectOne = Boolean(expectOne && jinf.expectOne)
|
|
1222
1236
|
joinPaths = joinPaths.concat(jinf.paths);
|
|
1223
1237
|
});
|
|
1224
1238
|
|
|
@@ -1229,7 +1243,7 @@ export class ViewHandler {
|
|
|
1229
1243
|
const { paths } = joinInfo;
|
|
1230
1244
|
const jp = paths[ji];
|
|
1231
1245
|
|
|
1232
|
-
let prevTable = ji? paths[ji - 1].table : jp.source;
|
|
1246
|
+
// let prevTable = ji? paths[ji - 1].table : jp.source;
|
|
1233
1247
|
let table = paths[ji].table;
|
|
1234
1248
|
let tableAlias = asName(ji < paths.length - 1? `jd${ji}` : table);
|
|
1235
1249
|
let prevTableAlias = asName(ji? `jd${ji - 1}` : thisTable);
|
|
@@ -1248,7 +1262,7 @@ export class ViewHandler {
|
|
|
1248
1262
|
j += `AND ${finalFilter} \n`;
|
|
1249
1263
|
}
|
|
1250
1264
|
|
|
1251
|
-
const indent = (a, b) => a;
|
|
1265
|
+
const indent = (a: any, b: any) => a;
|
|
1252
1266
|
|
|
1253
1267
|
if(ji < paths.length - 1){
|
|
1254
1268
|
j += `AND ${makeJoin(joinInfo, ji + 1)} \n`
|
|
@@ -1264,9 +1278,9 @@ export class ViewHandler {
|
|
|
1264
1278
|
|
|
1265
1279
|
}
|
|
1266
1280
|
|
|
1267
|
-
let t2Rules: TableRule = undefined,
|
|
1268
|
-
forcedFilter,
|
|
1269
|
-
filterFields,
|
|
1281
|
+
let t2Rules: TableRule | undefined = undefined,
|
|
1282
|
+
forcedFilter: AnyObject | undefined,
|
|
1283
|
+
filterFields: FieldFilter | undefined,
|
|
1270
1284
|
tableAlias;
|
|
1271
1285
|
|
|
1272
1286
|
/* Check if allowed to view data */
|
|
@@ -1314,7 +1328,7 @@ export class ViewHandler {
|
|
|
1314
1328
|
let data = { ... (filter as any) } as any ;
|
|
1315
1329
|
|
|
1316
1330
|
/* Exists join filter */
|
|
1317
|
-
const ERR = "Invalid exists filter. \nExpecting somethibng like: { $exists: { tableName.tableName2: Filter } } | { $exists: { \"**.tableName3\": Filter } }"
|
|
1331
|
+
const ERR = "Invalid exists filter. \nExpecting somethibng like: { $exists: { tableName.tableName2: Filter } } | { $exists: { \"**.tableName3\": Filter } }\n"
|
|
1318
1332
|
const SP_WILDCARD = "**";
|
|
1319
1333
|
let existsKeys: ExistsFilterConfig[] = Object.keys(data)
|
|
1320
1334
|
.filter(k => EXISTS_KEYS.includes(k as EXISTS_KEY) && Object.keys(data[k] || {}).length)
|
|
@@ -1366,7 +1380,7 @@ export class ViewHandler {
|
|
|
1366
1380
|
funcFilterkeys.map(f => {
|
|
1367
1381
|
const funcArgs = data[f.name];
|
|
1368
1382
|
if(!Array.isArray(funcArgs)) throw `A function filter must contain an array. E.g: { $funcFilterName: ["col1"] } \n but got: ${JSON.stringify(filterObj(data, [f.name]))} `;
|
|
1369
|
-
const fields = this.parseFieldFilter(f.getFields(funcArgs
|
|
1383
|
+
const fields = this.parseFieldFilter(f.getFields(funcArgs), true, allowed_colnames);
|
|
1370
1384
|
|
|
1371
1385
|
const dissallowedCols = fields.filter(fname => !allowed_colnames.includes(fname))
|
|
1372
1386
|
if(dissallowedCols.length){
|
|
@@ -1378,11 +1392,10 @@ export class ViewHandler {
|
|
|
1378
1392
|
|
|
1379
1393
|
let existsCond = "";
|
|
1380
1394
|
if(existsKeys.length){
|
|
1381
|
-
existsCond = (await Promise.all(existsKeys.map(async k => await this.prepareExistCondition(k,
|
|
1395
|
+
existsCond = (await Promise.all(existsKeys.map(async k => await this.prepareExistCondition(k, localParams)))).join(" AND ");
|
|
1382
1396
|
}
|
|
1383
1397
|
|
|
1384
1398
|
/* Computed field queries */
|
|
1385
|
-
|
|
1386
1399
|
const p = this.getValidatedRules(tableRules, localParams);
|
|
1387
1400
|
const computedFields = p.allColumns.filter(c => c.type === "computed" );
|
|
1388
1401
|
let computedColConditions: string[] = [];
|
|
@@ -1438,7 +1451,43 @@ export class ViewHandler {
|
|
|
1438
1451
|
}))
|
|
1439
1452
|
);
|
|
1440
1453
|
|
|
1441
|
-
|
|
1454
|
+
/* Parse complex filters
|
|
1455
|
+
{ $filter: [{ $func: [...] }, "=", value | { $func: [..] }] }
|
|
1456
|
+
*/
|
|
1457
|
+
const complexFilters: string[] = [];
|
|
1458
|
+
const complexFilterKey = "$filter";
|
|
1459
|
+
const allowedComparators = [">", "<", "=", "<=", ">=", "<>", "!="]
|
|
1460
|
+
if(complexFilterKey in data){
|
|
1461
|
+
const getFuncQuery = (funcData: any): string => {
|
|
1462
|
+
const { funcName, args } = parseFunctionObject(funcData);
|
|
1463
|
+
const funcDef = parseFunction({ func: funcName, args, functions: FUNCTIONS, allowedFields: allowed_colnames });
|
|
1464
|
+
return funcDef.getQuery({ args, tableAlias, allColumns: this.columns, allowedFields: allowed_colnames });
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
const complexFilter = data[complexFilterKey];
|
|
1468
|
+
if(!Array.isArray(complexFilter)) throw `Invalid $filter. Must contain an array of at least element but got: ${JSON.stringify(complexFilter)} `
|
|
1469
|
+
const leftFilter = complexFilter[0];
|
|
1470
|
+
const comparator = complexFilter[1];
|
|
1471
|
+
const rightFilterOrValue = complexFilter[2];
|
|
1472
|
+
const leftVal = getFuncQuery(leftFilter);
|
|
1473
|
+
let result = leftVal;
|
|
1474
|
+
if(comparator){
|
|
1475
|
+
if(!allowedComparators.includes(comparator)) throw `Invalid $filter. comparator ${JSON.stringify(comparator)} is not valid. Expecting one of: ${allowedComparators}`
|
|
1476
|
+
if(!rightFilterOrValue) throw "Invalid $filter. Expecting a value or function after the comparator";
|
|
1477
|
+
const rightVal = isObject(rightFilterOrValue)? getFuncQuery(rightFilterOrValue) : asValue(rightFilterOrValue);
|
|
1478
|
+
if(leftVal === rightVal) throw "Invalid $filter. Cannot compare two identical function signatures: " + JSON.stringify(leftFilter);
|
|
1479
|
+
result += ` ${comparator} ${rightVal}`;
|
|
1480
|
+
}
|
|
1481
|
+
complexFilters.push(result);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
|
|
1485
|
+
/* Parse join filters
|
|
1486
|
+
{ $joinFilter: { $ST_DWithin: [table.col, foreignTable.col, distance] }
|
|
1487
|
+
will make an exists filter
|
|
1488
|
+
*/
|
|
1489
|
+
|
|
1490
|
+
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));
|
|
1442
1491
|
// if(allowed_colnames){
|
|
1443
1492
|
// const aliasedColumns = (select || []).filter(s =>
|
|
1444
1493
|
// ["function", "computed", "column"].includes(s.type) && allowed_colnames.includes(s.alias) ||
|
|
@@ -1480,6 +1529,7 @@ export class ViewHandler {
|
|
|
1480
1529
|
if(existsCond) templates.push(existsCond);
|
|
1481
1530
|
templates = templates.concat(funcConds);
|
|
1482
1531
|
templates = templates.concat(computedColConditions);
|
|
1532
|
+
templates = templates.concat(complexFilters);
|
|
1483
1533
|
|
|
1484
1534
|
return templates.sort() /* sorted to ensure duplicate subscription channels are not created due to different condition order */
|
|
1485
1535
|
.join(" AND \n");
|
|
@@ -1493,7 +1543,7 @@ export class ViewHandler {
|
|
|
1493
1543
|
}
|
|
1494
1544
|
|
|
1495
1545
|
/* This relates only to SELECT */
|
|
1496
|
-
prepareSort(orderBy: OrderBy, allowed_cols, tableAlias: string, excludeOrder: boolean = false, select: SelectItem[]): string {
|
|
1546
|
+
prepareSort(orderBy: OrderBy | undefined, allowed_cols: FieldFilter, tableAlias: string | undefined, excludeOrder: boolean = false, select: SelectItem[]): string {
|
|
1497
1547
|
let column_names = this.column_names.slice(0);
|
|
1498
1548
|
|
|
1499
1549
|
const throwErr = () => {
|
|
@@ -1504,7 +1554,7 @@ export class ViewHandler {
|
|
|
1504
1554
|
[{ key1: true }, { key2: false }] \
|
|
1505
1555
|
[{ key: 'colName', asc: true, nulls: 'first', nullEmpty: true }]"
|
|
1506
1556
|
},
|
|
1507
|
-
parseOrderObj = (orderBy, expectOne = false): { key: string, asc: boolean, nulls?: "first" | "last", nullEmpty?: boolean }[] => {
|
|
1557
|
+
parseOrderObj = (orderBy: any, expectOne = false): { key: string, asc: boolean, nulls?: "first" | "last", nullEmpty?: boolean }[] => {
|
|
1508
1558
|
if(!isPlainObject(orderBy)) return throwErr();
|
|
1509
1559
|
|
|
1510
1560
|
const keys = Object.keys(orderBy);
|
|
@@ -1542,7 +1592,7 @@ export class ViewHandler {
|
|
|
1542
1592
|
|
|
1543
1593
|
if(!orderBy) return "";
|
|
1544
1594
|
|
|
1545
|
-
let allowedFields = [];
|
|
1595
|
+
let allowedFields: string[] = [];
|
|
1546
1596
|
if(allowed_cols){
|
|
1547
1597
|
allowedFields = this.parseFieldFilter(allowed_cols);
|
|
1548
1598
|
}
|
|
@@ -1594,7 +1644,7 @@ export class ViewHandler {
|
|
|
1594
1644
|
const orderType = asc? " ASC " : " DESC ";
|
|
1595
1645
|
const index = selectedAliases.indexOf(key) + 1;
|
|
1596
1646
|
const nullOrder = nulls? ` NULLS ${nulls === "first"? " FIRST " : " LAST "}` : "";
|
|
1597
|
-
let colKey = (index > 0 && !nullEmpty)? index : [tableAlias, key].filter(
|
|
1647
|
+
let colKey = (index > 0 && !nullEmpty)? index : [tableAlias, key].filter(isDefined).map(asName).join(".");
|
|
1598
1648
|
if(nullEmpty){
|
|
1599
1649
|
colKey = `nullif(trim(${colKey}::text), '')`
|
|
1600
1650
|
}
|
|
@@ -1627,7 +1677,7 @@ export class ViewHandler {
|
|
|
1627
1677
|
} else {
|
|
1628
1678
|
|
|
1629
1679
|
/* If a limit higher than maxLimit specified throw error */
|
|
1630
|
-
if(Number.isInteger(p.select.maxLimit) && _limit > p.select.maxLimit){
|
|
1680
|
+
if(Number.isInteger(p.select.maxLimit) && _limit > p.select.maxLimit!){
|
|
1631
1681
|
throw `Unexpected LIMIT ${_limit}. Must be less than the published maxLimit: ` + p.select.maxLimit;
|
|
1632
1682
|
}
|
|
1633
1683
|
}
|
|
@@ -1637,9 +1687,9 @@ export class ViewHandler {
|
|
|
1637
1687
|
}
|
|
1638
1688
|
|
|
1639
1689
|
/* This relates only to SELECT */
|
|
1640
|
-
prepareOffsetQuery(offset
|
|
1690
|
+
prepareOffsetQuery(offset?: number): number{
|
|
1641
1691
|
if(Number.isInteger(offset)){
|
|
1642
|
-
return offset
|
|
1692
|
+
return offset!;
|
|
1643
1693
|
}
|
|
1644
1694
|
|
|
1645
1695
|
return 0;
|
|
@@ -1647,7 +1697,7 @@ export class ViewHandler {
|
|
|
1647
1697
|
|
|
1648
1698
|
|
|
1649
1699
|
intersectColumns(allowedFields: FieldFilter, dissallowedFields: FieldFilter, fixIssues: boolean = false): string[] {
|
|
1650
|
-
let result = [];
|
|
1700
|
+
let result: string[] = [];
|
|
1651
1701
|
if(allowedFields){
|
|
1652
1702
|
result = this.parseFieldFilter(allowedFields);
|
|
1653
1703
|
}
|
|
@@ -1673,7 +1723,7 @@ export class ViewHandler {
|
|
|
1673
1723
|
* @param {Object} forcedData - set/override property
|
|
1674
1724
|
* @param {string[]} allowed_cols - allowed columns (excluding forcedData) from table rules
|
|
1675
1725
|
*/
|
|
1676
|
-
prepareFieldValues(obj:
|
|
1726
|
+
prepareFieldValues(obj: Record<string, any> = {}, forcedData: object = {}, allowed_cols: FieldFilter | undefined, fixIssues = false): AnyObject {
|
|
1677
1727
|
let column_names = this.column_names.slice(0);
|
|
1678
1728
|
if(!column_names || !column_names.length) throw "table column_names mising";
|
|
1679
1729
|
let _allowed_cols = column_names.slice(0);
|
|
@@ -1683,7 +1733,7 @@ export class ViewHandler {
|
|
|
1683
1733
|
_allowed_cols = this.parseFieldFilter(allowed_cols, false);
|
|
1684
1734
|
}
|
|
1685
1735
|
let final_filter = { ..._obj },
|
|
1686
|
-
filter_keys = Object.keys(final_filter);
|
|
1736
|
+
filter_keys: Array<keyof typeof final_filter> = Object.keys(final_filter);
|
|
1687
1737
|
|
|
1688
1738
|
if(fixIssues && filter_keys.length){
|
|
1689
1739
|
final_filter = {};
|
|
@@ -1720,7 +1770,7 @@ export class ViewHandler {
|
|
|
1720
1770
|
static _parseFieldFilter(fieldParams: FieldFilter = "*", allow_empty: boolean = true, all_cols: string[]): string[] {
|
|
1721
1771
|
if(!all_cols) throw "all_cols missing"
|
|
1722
1772
|
const all_fields = all_cols;// || this.column_names.slice(0);
|
|
1723
|
-
let colNames =
|
|
1773
|
+
let colNames: string[] = [],
|
|
1724
1774
|
initialParams = JSON.stringify(fieldParams);
|
|
1725
1775
|
|
|
1726
1776
|
if(fieldParams){
|
|
@@ -1763,7 +1813,9 @@ export class ViewHandler {
|
|
|
1763
1813
|
} else if(isPlainObject(fieldParams)){
|
|
1764
1814
|
|
|
1765
1815
|
if(Object.keys(fieldParams).length){
|
|
1766
|
-
let keys = Object.keys(fieldParams
|
|
1816
|
+
let keys = Object.keys(fieldParams as {
|
|
1817
|
+
[key: string]: boolean | 0 | 1;
|
|
1818
|
+
});
|
|
1767
1819
|
if(keys[0] === ""){
|
|
1768
1820
|
if(allow_empty){
|
|
1769
1821
|
return [""];
|
|
@@ -1776,11 +1828,11 @@ export class ViewHandler {
|
|
|
1776
1828
|
|
|
1777
1829
|
keys.forEach(key => {
|
|
1778
1830
|
const allowedVals = [true, false, 0, 1];
|
|
1779
|
-
if(!allowedVals.includes(fieldParams[key])) throw `Invalid field selection value for: { ${key}: ${fieldParams[key]} }. \n Allowed values: ${allowedVals.join(" OR ")}`
|
|
1831
|
+
if(!allowedVals.includes((fieldParams as any)[key])) throw `Invalid field selection value for: { ${key}: ${(fieldParams as any)[key]} }. \n Allowed values: ${allowedVals.join(" OR ")}`
|
|
1780
1832
|
})
|
|
1781
1833
|
|
|
1782
|
-
let allowed = keys.filter(key => fieldParams[key]),
|
|
1783
|
-
disallowed = keys.filter(key => !fieldParams[key]);
|
|
1834
|
+
let allowed = keys.filter(key => (fieldParams as any)[key]),
|
|
1835
|
+
disallowed = keys.filter(key => !(fieldParams as any)[key]);
|
|
1784
1836
|
|
|
1785
1837
|
|
|
1786
1838
|
if(disallowed && disallowed.length){
|
|
@@ -1808,7 +1860,7 @@ export class ViewHandler {
|
|
|
1808
1860
|
}
|
|
1809
1861
|
}
|
|
1810
1862
|
|
|
1811
|
-
function isPojoObject(obj):
|
|
1863
|
+
function isPojoObject<T>(obj: T): obj is Record<string, any> {
|
|
1812
1864
|
if(obj && (typeof obj !== "object" || Array.isArray(obj) || obj instanceof Date)){
|
|
1813
1865
|
return false;
|
|
1814
1866
|
}
|
|
@@ -1817,10 +1869,10 @@ function isPojoObject(obj): boolean {
|
|
|
1817
1869
|
|
|
1818
1870
|
|
|
1819
1871
|
type ValidatedParams = {
|
|
1820
|
-
row:
|
|
1821
|
-
forcedData
|
|
1822
|
-
allowedFields
|
|
1823
|
-
tableRules
|
|
1872
|
+
row: AnyObject;
|
|
1873
|
+
forcedData?: AnyObject;
|
|
1874
|
+
allowedFields?: FieldFilter;
|
|
1875
|
+
tableRules?: TableRule;
|
|
1824
1876
|
fixIssues: boolean;
|
|
1825
1877
|
}
|
|
1826
1878
|
|
|
@@ -1829,7 +1881,7 @@ export class TableHandler extends ViewHandler {
|
|
|
1829
1881
|
throttle_queries_per_sec: number;
|
|
1830
1882
|
since: number,
|
|
1831
1883
|
queries: number,
|
|
1832
|
-
batching: string[]
|
|
1884
|
+
batching: string[] | null
|
|
1833
1885
|
}
|
|
1834
1886
|
|
|
1835
1887
|
constructor(db: DB, tableOrViewInfo: TableSchema, dboBuilder: DboBuilder, t?: pgPromise.ITask<{}>, dbTX?: TxHandler, joinPaths?: JoinPaths){
|
|
@@ -1864,8 +1916,8 @@ export class TableHandler extends ViewHandler {
|
|
|
1864
1916
|
}
|
|
1865
1917
|
|
|
1866
1918
|
async subscribe(filter: Filter, params: SubscribeParams, localFunc: (items: AnyObject[]) => any): Promise<{ unsubscribe: () => any }>
|
|
1867
|
-
async subscribe(filter: Filter, params: SubscribeParams, localFunc
|
|
1868
|
-
async subscribe(filter: Filter, params: SubscribeParams = {}, localFunc
|
|
1919
|
+
async subscribe(filter: Filter, params: SubscribeParams, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>
|
|
1920
|
+
async subscribe(filter: Filter, params: SubscribeParams = {}, localFunc?: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams):
|
|
1869
1921
|
Promise<string | { unsubscribe: () => any }>
|
|
1870
1922
|
{
|
|
1871
1923
|
try {
|
|
@@ -1878,7 +1930,7 @@ export class TableHandler extends ViewHandler {
|
|
|
1878
1930
|
}
|
|
1879
1931
|
|
|
1880
1932
|
const { filterFields, forcedFilter } = get(table_rules, "select") || {},
|
|
1881
|
-
condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias:
|
|
1933
|
+
condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }),
|
|
1882
1934
|
throttle = get(params, "throttle") || 0,
|
|
1883
1935
|
selectParams = filterObj(params || {}, [], ["throttle"]);
|
|
1884
1936
|
|
|
@@ -1890,21 +1942,20 @@ export class TableHandler extends ViewHandler {
|
|
|
1890
1942
|
|
|
1891
1943
|
if(!localFunc) {
|
|
1892
1944
|
if(!this.dboBuilder.prostgles.isSuperUser) throw "Subscribe not possible. Must be superuser to add triggers 1856";
|
|
1893
|
-
return await this.find(filter, { ...selectParams, limit: 0 },
|
|
1945
|
+
return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
|
|
1894
1946
|
.then(async isValid => {
|
|
1895
1947
|
|
|
1896
|
-
const { socket
|
|
1948
|
+
const { socket } = localParams ?? {};
|
|
1897
1949
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
1898
1950
|
return pubSubManager.addSub({
|
|
1899
1951
|
table_info: this.tableOrViewInfo,
|
|
1900
1952
|
socket,
|
|
1901
1953
|
table_rules,
|
|
1902
1954
|
condition: condition,
|
|
1903
|
-
func:
|
|
1955
|
+
func: undefined,
|
|
1904
1956
|
filter: { ...filter },
|
|
1905
1957
|
params: { ...selectParams },
|
|
1906
|
-
|
|
1907
|
-
socket_id: socket.id,
|
|
1958
|
+
socket_id: socket?.id,
|
|
1908
1959
|
table_name: this.name,
|
|
1909
1960
|
throttle,
|
|
1910
1961
|
last_throttled: 0,
|
|
@@ -1915,14 +1966,13 @@ export class TableHandler extends ViewHandler {
|
|
|
1915
1966
|
const pubSubManager = await this.dboBuilder.getPubSubManager();
|
|
1916
1967
|
pubSubManager.addSub({
|
|
1917
1968
|
table_info: this.tableOrViewInfo,
|
|
1918
|
-
socket:
|
|
1969
|
+
socket: undefined,
|
|
1919
1970
|
table_rules,
|
|
1920
1971
|
condition,
|
|
1921
1972
|
func: localFunc,
|
|
1922
1973
|
filter: { ...filter },
|
|
1923
1974
|
params: { ...selectParams },
|
|
1924
|
-
|
|
1925
|
-
socket_id: null,
|
|
1975
|
+
socket_id: undefined,
|
|
1926
1976
|
table_name: this.name,
|
|
1927
1977
|
throttle,
|
|
1928
1978
|
last_throttled: 0,
|
|
@@ -1947,12 +1997,12 @@ export class TableHandler extends ViewHandler {
|
|
|
1947
1997
|
subscribeOne(filter: Filter, params: SubscribeParams = {}, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams):
|
|
1948
1998
|
Promise<string | { unsubscribe: () => any }>
|
|
1949
1999
|
{
|
|
1950
|
-
let func = localParams? undefined : (rows) => localFunc(rows[0]);
|
|
2000
|
+
let func = localParams? undefined : (rows: AnyObject[]) => localFunc(rows[0]);
|
|
1951
2001
|
return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
|
|
1952
2002
|
}
|
|
1953
2003
|
|
|
1954
2004
|
|
|
1955
|
-
async updateBatch(data: [Filter, AnyObject][], params?: UpdateParams, tableRules?: TableRule, localParams
|
|
2005
|
+
async updateBatch(data: [Filter, AnyObject][], params?: UpdateParams, tableRules?: TableRule, localParams?: LocalParams): Promise<any>{
|
|
1956
2006
|
try {
|
|
1957
2007
|
const queries = await Promise.all(
|
|
1958
2008
|
data.map(async ([filter, data]) =>
|
|
@@ -1976,20 +2026,20 @@ export class TableHandler extends ViewHandler {
|
|
|
1976
2026
|
}
|
|
1977
2027
|
}
|
|
1978
2028
|
|
|
1979
|
-
async update(filter: Filter, newData:
|
|
2029
|
+
async update(filter: Filter, newData: AnyObject, params?: UpdateParams, tableRules?: TableRule, localParams?: LocalParams): Promise<AnyObject | void>{
|
|
1980
2030
|
try {
|
|
1981
2031
|
|
|
1982
|
-
const { testRule = false, returnQuery = false } = localParams
|
|
2032
|
+
const { testRule = false, returnQuery = false } = localParams ?? {};
|
|
1983
2033
|
if(!testRule){
|
|
1984
2034
|
if(!newData || !Object.keys(newData).length) throw "no update data provided\nEXPECTING db.table.update(filter, updateData, options)";
|
|
1985
2035
|
this.checkFilter(filter);
|
|
1986
2036
|
}
|
|
1987
2037
|
|
|
1988
|
-
let forcedFilter:
|
|
1989
|
-
forcedData:
|
|
1990
|
-
validate: ValidateRow,
|
|
1991
|
-
returningFields: FieldFilter = "*",
|
|
1992
|
-
filterFields: FieldFilter = "*",
|
|
2038
|
+
let forcedFilter: AnyObject | undefined = {},
|
|
2039
|
+
forcedData: AnyObject | undefined = {},
|
|
2040
|
+
validate: ValidateRow | undefined,
|
|
2041
|
+
returningFields: FieldFilter | undefined = "*",
|
|
2042
|
+
filterFields: FieldFilter | undefined = "*",
|
|
1993
2043
|
fields: FieldFilter = "*";
|
|
1994
2044
|
|
|
1995
2045
|
if(tableRules){
|
|
@@ -2004,7 +2054,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2004
2054
|
await this.validateViewRules(fields, filterFields, returningFields, forcedFilter, "update");
|
|
2005
2055
|
if(forcedData) {
|
|
2006
2056
|
try {
|
|
2007
|
-
const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData:
|
|
2057
|
+
const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData: undefined, allowedFields: "*", tableRules, fixIssues: false });
|
|
2008
2058
|
const updateQ = await this.colSet.getUpdateQuery(data, allowedCols, validate) //pgp.helpers.update(data, columnSet)
|
|
2009
2059
|
let query = updateQ + " WHERE FALSE ";
|
|
2010
2060
|
await this.db.any("EXPLAIN " + query);
|
|
@@ -2049,13 +2099,13 @@ export class TableHandler extends ViewHandler {
|
|
|
2049
2099
|
if(c.data_type === "text" && d && isPlainObject(d) && !["from", "to"].find(key => typeof d[key] !== "number")){
|
|
2050
2100
|
const unrecProps = Object.keys(d).filter(k => !["from", "to", "text", "md5"].includes(k));
|
|
2051
2101
|
if(unrecProps.length) throw "Unrecognised params in textPatch field: " + unrecProps.join(", ");
|
|
2052
|
-
patchedTextData.push({ ...d, fieldName: c.name });
|
|
2102
|
+
patchedTextData.push({ ...d, fieldName: c.name } as (typeof patchedTextData)[number]);
|
|
2053
2103
|
}
|
|
2054
2104
|
});
|
|
2055
2105
|
|
|
2056
2106
|
if(patchedTextData && patchedTextData.length){
|
|
2057
2107
|
if(tableRules && !tableRules.select) throw "Select needs to be permitted to patch data";
|
|
2058
|
-
const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) },
|
|
2108
|
+
const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) }, undefined, tableRules);
|
|
2059
2109
|
|
|
2060
2110
|
if(rows.length !== 1) {
|
|
2061
2111
|
throw "Cannot patch data within a filter that affects more/less than 1 row";
|
|
@@ -2091,9 +2141,9 @@ export class TableHandler extends ViewHandler {
|
|
|
2091
2141
|
if(returnQuery) return query as unknown as void;
|
|
2092
2142
|
|
|
2093
2143
|
if(this.t){
|
|
2094
|
-
return this.t[qType](query).catch(err => makeErr(err, localParams, this, _fields));
|
|
2144
|
+
return (this.t as any)[qType](query).catch((err: any) => makeErr(err, localParams, this, _fields));
|
|
2095
2145
|
}
|
|
2096
|
-
return this.db.tx(t => t[qType](query)).catch(err => makeErr(err, localParams, this, _fields));
|
|
2146
|
+
return this.db.tx(t => (t as any)[qType](query)).catch(err => makeErr(err, localParams, this, _fields));
|
|
2097
2147
|
} catch(e){
|
|
2098
2148
|
if(localParams && localParams.testRule) throw e;
|
|
2099
2149
|
throw { err: parseError(e), msg: `Issue with dbo.${this.name}.update(${JSON.stringify(filter || {}, null, 2)}, ${JSON.stringify(newData || {}, null, 2)}, ${JSON.stringify(params || {}, null, 2)})` };
|
|
@@ -2101,7 +2151,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2101
2151
|
};
|
|
2102
2152
|
|
|
2103
2153
|
validateNewData({ row, forcedData, allowedFields, tableRules, fixIssues = false }: ValidatedParams): { data: any; allowedCols: string[] } {
|
|
2104
|
-
const synced_field = get(tableRules
|
|
2154
|
+
const synced_field = get(tableRules ?? {}, "sync.synced_field");
|
|
2105
2155
|
|
|
2106
2156
|
/* Update synced_field if sync is on and missing */
|
|
2107
2157
|
if(synced_field && !row[synced_field]){
|
|
@@ -2109,7 +2159,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2109
2159
|
}
|
|
2110
2160
|
|
|
2111
2161
|
let data = this.prepareFieldValues(row, forcedData, allowedFields, fixIssues);
|
|
2112
|
-
const dataKeys =
|
|
2162
|
+
const dataKeys = getKeys(data);
|
|
2113
2163
|
|
|
2114
2164
|
dataKeys.map(col => {
|
|
2115
2165
|
this.dboBuilder.prostgles?.tableConfigurator?.checkColVal({ table: this.name, col, value: data[col] });
|
|
@@ -2128,7 +2178,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2128
2178
|
}
|
|
2129
2179
|
|
|
2130
2180
|
|
|
2131
|
-
private async insertDataParse(data: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused
|
|
2181
|
+
private async insertDataParse(data: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused?: never, tableRules?: TableRule, _localParams?: LocalParams): Promise<{
|
|
2132
2182
|
data?: AnyObject | AnyObject[];
|
|
2133
2183
|
insertResult?: AnyObject | AnyObject[];
|
|
2134
2184
|
}>{
|
|
@@ -2136,7 +2186,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2136
2186
|
let dbTX = localParams?.dbTX || this.dbTX;
|
|
2137
2187
|
|
|
2138
2188
|
const isMultiInsert = Array.isArray(data);
|
|
2139
|
-
const getExtraKeys = d => Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
|
|
2189
|
+
const getExtraKeys = (d: AnyObject)=> Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
|
|
2140
2190
|
|
|
2141
2191
|
/* Nested insert is not allowed for the file table */
|
|
2142
2192
|
const isNestedInsert = this.is_media? false : (Array.isArray(data)? data : [data]).some(d => getExtraKeys(d).length);
|
|
@@ -2201,7 +2251,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2201
2251
|
const _media: Media = await this.dboBuilder.prostgles.fileManager.uploadAsMedia({
|
|
2202
2252
|
item: {
|
|
2203
2253
|
data,
|
|
2204
|
-
name: media.name,
|
|
2254
|
+
name: media.name ?? "????",
|
|
2205
2255
|
content_type: media.content_type as any
|
|
2206
2256
|
},
|
|
2207
2257
|
// imageCompression: {
|
|
@@ -2221,21 +2271,21 @@ export class TableHandler extends ViewHandler {
|
|
|
2221
2271
|
} else if(extraKeys.length){
|
|
2222
2272
|
|
|
2223
2273
|
/* Ensure we're using the same transaction */
|
|
2224
|
-
const _this = this.t? this : dbTX[this.name] as TableHandler;
|
|
2274
|
+
const _this = this.t? this : dbTX![this.name] as TableHandler;
|
|
2225
2275
|
|
|
2226
|
-
let rootData = filterObj(data,
|
|
2276
|
+
let rootData = filterObj(data, undefined, extraKeys);
|
|
2227
2277
|
|
|
2228
2278
|
let insertedChildren: AnyObject[];
|
|
2229
2279
|
let targetTableRules: TableRule;
|
|
2230
2280
|
|
|
2231
|
-
const fullRootResult = await _this.insert(rootData, { returning: "*" },
|
|
2232
|
-
let returnData: AnyObject;
|
|
2281
|
+
const fullRootResult = await _this.insert(rootData, { returning: "*" }, undefined, tableRules, localParams);
|
|
2282
|
+
let returnData: AnyObject | undefined;
|
|
2233
2283
|
const returning = param2?.returning;
|
|
2234
2284
|
if(returning){
|
|
2235
2285
|
returnData = {}
|
|
2236
2286
|
const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(tableRules?.insert?.returningFields));
|
|
2237
2287
|
returningItems.filter(s => s.selected).map(rs => {
|
|
2238
|
-
returnData[rs.alias] = fullRootResult[rs.alias];
|
|
2288
|
+
returnData![rs.alias] = fullRootResult[rs.alias];
|
|
2239
2289
|
})
|
|
2240
2290
|
}
|
|
2241
2291
|
|
|
@@ -2244,7 +2294,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2244
2294
|
|
|
2245
2295
|
/* Must be allowed to insert into media table */
|
|
2246
2296
|
const canInsert = async (tbl: string) => {
|
|
2247
|
-
const childRules = await this.dboBuilder.publishParser
|
|
2297
|
+
const childRules = await this.dboBuilder.publishParser?.getValidatedRequestRuleWusr({ tableName: tbl, command: "insert", localParams });
|
|
2248
2298
|
if(!childRules || !childRules.insert) throw "Dissallowed nested insert into table " + childRules;
|
|
2249
2299
|
return childRules;
|
|
2250
2300
|
}
|
|
@@ -2254,9 +2304,9 @@ export class TableHandler extends ViewHandler {
|
|
|
2254
2304
|
if(!jp) throw `Could not find a valid table for the nested data { ${targetTable} } `;
|
|
2255
2305
|
|
|
2256
2306
|
const thisInfo = await this.getInfo();
|
|
2257
|
-
const childInsert = async (cdata, tableName) => {
|
|
2307
|
+
const childInsert = async (cdata: AnyObject | AnyObject[], tableName: string) => {
|
|
2258
2308
|
// console.log("childInsert", {data, tableName})
|
|
2259
|
-
if(!cdata || !dbTX[tableName] || !("insert" in dbTX[tableName])) throw "childInsertErr: Child table handler missing for: " + tableName;
|
|
2309
|
+
if(!cdata || !dbTX?.[tableName] || !("insert" in dbTX[tableName])) throw "childInsertErr: Child table handler missing for: " + tableName;
|
|
2260
2310
|
|
|
2261
2311
|
const tableRules = await canInsert(tableName);
|
|
2262
2312
|
|
|
@@ -2265,8 +2315,8 @@ export class TableHandler extends ViewHandler {
|
|
|
2265
2315
|
}
|
|
2266
2316
|
return Promise.all(
|
|
2267
2317
|
(Array.isArray(cdata)? cdata : [cdata])
|
|
2268
|
-
.map(m => (dbTX[tableName] as TableHandler)
|
|
2269
|
-
.insert(m, { returning: "*" },
|
|
2318
|
+
.map(m => (dbTX![tableName] as TableHandler)
|
|
2319
|
+
.insert(m, { returning: "*" }, undefined, tableRules, localParams)
|
|
2270
2320
|
.catch(e => {
|
|
2271
2321
|
console.trace({ childInsertErr: e })
|
|
2272
2322
|
return Promise.reject({ childInsertErr: e });
|
|
@@ -2293,10 +2343,10 @@ export class TableHandler extends ViewHandler {
|
|
|
2293
2343
|
|
|
2294
2344
|
// console.log(childDataItems, JSON.stringify(colsRefT1, null, 2))
|
|
2295
2345
|
insertedChildren = await childInsert(
|
|
2296
|
-
childDataItems.map(d => {
|
|
2346
|
+
childDataItems.map((d: AnyObject) => {
|
|
2297
2347
|
let result = {...d};
|
|
2298
2348
|
colsRefT1.map(col => {
|
|
2299
|
-
result[col.references
|
|
2349
|
+
result[col.references!.cols[0]] = fullRootResult[col.references!.fcols[0]]
|
|
2300
2350
|
})
|
|
2301
2351
|
return result;
|
|
2302
2352
|
}),
|
|
@@ -2309,7 +2359,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2309
2359
|
const colsRefT3 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl3);
|
|
2310
2360
|
if(!colsRefT1.length || !colsRefT3.length) throw "Incorrectly referenced or missing columns for nested insert";
|
|
2311
2361
|
|
|
2312
|
-
if(targetTable !== this.dboBuilder.prostgles.fileManager
|
|
2362
|
+
if(targetTable !== this.dboBuilder.prostgles.fileManager?.tableName){
|
|
2313
2363
|
throw "Only media allowed to have nested inserts more than 2 tables apart"
|
|
2314
2364
|
}
|
|
2315
2365
|
|
|
@@ -2322,13 +2372,13 @@ export class TableHandler extends ViewHandler {
|
|
|
2322
2372
|
|
|
2323
2373
|
/* Insert in key_lookup table */
|
|
2324
2374
|
await Promise.all(insertedChildren.map(async t3Child => {
|
|
2325
|
-
let tbl2Row = {};
|
|
2375
|
+
let tbl2Row: AnyObject = {};
|
|
2326
2376
|
|
|
2327
2377
|
colsRefT3.map(col => {
|
|
2328
|
-
tbl2Row[col.name] = t3Child[col.references
|
|
2378
|
+
tbl2Row[col.name] = t3Child[col.references!.fcols[0]];
|
|
2329
2379
|
})
|
|
2330
2380
|
colsRefT1.map(col => {
|
|
2331
|
-
tbl2Row[col.name] = fullRootResult[col.references
|
|
2381
|
+
tbl2Row[col.name] = fullRootResult[col.references!.fcols[0]];
|
|
2332
2382
|
})
|
|
2333
2383
|
// console.log({ rootResult, tbl2Row, t3Child, colsRefT3, colsRefT1, t: this.t?.ctx?.start });
|
|
2334
2384
|
|
|
@@ -2342,18 +2392,18 @@ export class TableHandler extends ViewHandler {
|
|
|
2342
2392
|
|
|
2343
2393
|
/* Return also the nested inserted data */
|
|
2344
2394
|
if(targetTableRules && insertedChildren?.length && returning){
|
|
2345
|
-
const targetTableHandler = dbTX[targetTable] as TableHandler;
|
|
2395
|
+
const targetTableHandler = dbTX![targetTable] as TableHandler;
|
|
2346
2396
|
const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(targetTableRules?.insert?.returningFields));
|
|
2347
2397
|
let clientTargetInserts = insertedChildren.map(d => {
|
|
2348
2398
|
let _d = { ...d };
|
|
2349
|
-
let res = {};
|
|
2399
|
+
let res: AnyObject = {};
|
|
2350
2400
|
targetReturning.map(r => {
|
|
2351
2401
|
res[r.alias] = _d[r.alias]
|
|
2352
2402
|
});
|
|
2353
2403
|
return res;
|
|
2354
2404
|
});
|
|
2355
2405
|
|
|
2356
|
-
returnData[targetTable] = clientTargetInserts.length === 1? clientTargetInserts[0] : clientTargetInserts;
|
|
2406
|
+
returnData![targetTable] = clientTargetInserts.length === 1? clientTargetInserts[0] : clientTargetInserts;
|
|
2357
2407
|
}
|
|
2358
2408
|
}));
|
|
2359
2409
|
|
|
@@ -2374,7 +2424,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2374
2424
|
return res;
|
|
2375
2425
|
}
|
|
2376
2426
|
|
|
2377
|
-
async insert(rowOrRows: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused
|
|
2427
|
+
async insert(rowOrRows: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused?: never, tableRules?: TableRule, _localParams?: LocalParams): Promise<any | any[] | boolean>{
|
|
2378
2428
|
const localParams = _localParams || {};
|
|
2379
2429
|
const {dbTX} = localParams
|
|
2380
2430
|
try {
|
|
@@ -2382,9 +2432,9 @@ export class TableHandler extends ViewHandler {
|
|
|
2382
2432
|
const { returning, onConflictDoNothing, fixIssues = false } = param2 || {};
|
|
2383
2433
|
const { testRule = false, returnQuery = false } = localParams || {};
|
|
2384
2434
|
|
|
2385
|
-
let returningFields: FieldFilter,
|
|
2386
|
-
forcedData:
|
|
2387
|
-
fields: FieldFilter;
|
|
2435
|
+
let returningFields: FieldFilter | undefined,
|
|
2436
|
+
forcedData: AnyObject | undefined,
|
|
2437
|
+
fields: FieldFilter | undefined;
|
|
2388
2438
|
|
|
2389
2439
|
if(tableRules){
|
|
2390
2440
|
if(!tableRules.insert) throw "insert rules missing for " + this.name;
|
|
@@ -2400,7 +2450,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2400
2450
|
/* Safely test publish rules */
|
|
2401
2451
|
if(testRule){
|
|
2402
2452
|
// if(this.is_media && tableRules.insert.preValidate) throw "Media table cannot have a preValidate. It already is used internally by prostgles for file upload";
|
|
2403
|
-
await this.validateViewRules(fields,
|
|
2453
|
+
await this.validateViewRules(fields, undefined, returningFields, undefined, "insert");
|
|
2404
2454
|
if(forcedData) {
|
|
2405
2455
|
const keys = Object.keys(forcedData);
|
|
2406
2456
|
if(keys.length){
|
|
@@ -2432,7 +2482,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2432
2482
|
|
|
2433
2483
|
if(!rowOrRows) rowOrRows = {}; //throw "Provide data in param1";
|
|
2434
2484
|
let returningSelect = this.makeReturnQuery(await this.prepareReturning(returning, this.parseFieldFilter(returningFields)));
|
|
2435
|
-
const makeQuery = async (_row, isOne = false) => {
|
|
2485
|
+
const makeQuery = async (_row: AnyObject | undefined, isOne = false) => {
|
|
2436
2486
|
let row = { ..._row };
|
|
2437
2487
|
|
|
2438
2488
|
if(!isPojoObject(row)) {
|
|
@@ -2450,7 +2500,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2450
2500
|
};
|
|
2451
2501
|
|
|
2452
2502
|
let query = "";
|
|
2453
|
-
let queryType = "none";
|
|
2503
|
+
let queryType: keyof pgPromise.ITask<{}> = "none";
|
|
2454
2504
|
|
|
2455
2505
|
/**
|
|
2456
2506
|
* If media it will: upload file and continue insert
|
|
@@ -2487,9 +2537,9 @@ export class TableHandler extends ViewHandler {
|
|
|
2487
2537
|
|
|
2488
2538
|
const allowedFieldKeys = this.parseFieldFilter(fields);
|
|
2489
2539
|
if(tx) {
|
|
2490
|
-
result = tx[queryType](query).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
2540
|
+
result = (tx as any)[queryType](query).catch((err: any) => makeErr(err, localParams, this, allowedFieldKeys));
|
|
2491
2541
|
} else {
|
|
2492
|
-
result = this.db.tx(t => t[queryType](query)).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
2542
|
+
result = this.db.tx(t => (t as any)[queryType](query)).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
|
|
2493
2543
|
}
|
|
2494
2544
|
|
|
2495
2545
|
return result;
|
|
@@ -2502,7 +2552,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2502
2552
|
}
|
|
2503
2553
|
};
|
|
2504
2554
|
|
|
2505
|
-
prepareReturning = async (returning:
|
|
2555
|
+
prepareReturning = async (returning: Select<AnyObject>, allowedFields: string[]): Promise<SelectItem[]> => {
|
|
2506
2556
|
let result: SelectItem[] = [];
|
|
2507
2557
|
if(returning){
|
|
2508
2558
|
let sBuilder = new SelectItemBuilder({
|
|
@@ -2526,7 +2576,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2526
2576
|
return "";
|
|
2527
2577
|
}
|
|
2528
2578
|
|
|
2529
|
-
async delete(filter?: Filter, params?: DeleteParams, param3_unused
|
|
2579
|
+
async delete(filter?: Filter, params?: DeleteParams, param3_unused?: never, table_rules?: TableRule, localParams?: LocalParams): Promise<any> { //{ socket, func, has_rules = false, socketDb } = {}
|
|
2530
2580
|
try {
|
|
2531
2581
|
const { returning } = params || {};
|
|
2532
2582
|
filter = filter || {};
|
|
@@ -2534,9 +2584,9 @@ export class TableHandler extends ViewHandler {
|
|
|
2534
2584
|
|
|
2535
2585
|
// table_rules = table_rules || {};
|
|
2536
2586
|
|
|
2537
|
-
let forcedFilter:
|
|
2538
|
-
filterFields: FieldFilter = "*",
|
|
2539
|
-
returningFields: FieldFilter = "*";
|
|
2587
|
+
let forcedFilter: AnyObject | undefined = {},
|
|
2588
|
+
filterFields: FieldFilter | undefined = "*",
|
|
2589
|
+
returningFields: FieldFilter | undefined = "*";
|
|
2540
2590
|
|
|
2541
2591
|
const { testRule = false, returnQuery = false } = localParams || {};
|
|
2542
2592
|
if(table_rules){
|
|
@@ -2552,7 +2602,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2552
2602
|
|
|
2553
2603
|
/* Safely test publish rules */
|
|
2554
2604
|
if(testRule){
|
|
2555
|
-
await this.validateViewRules(
|
|
2605
|
+
await this.validateViewRules(undefined, filterFields, returningFields, forcedFilter, "delete");
|
|
2556
2606
|
return true;
|
|
2557
2607
|
}
|
|
2558
2608
|
}
|
|
@@ -2564,7 +2614,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2564
2614
|
if(bad_params && bad_params.length) throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
|
|
2565
2615
|
}
|
|
2566
2616
|
|
|
2567
|
-
let queryType = 'none';
|
|
2617
|
+
let queryType: keyof pgPromise.ITask<{}> = 'none';
|
|
2568
2618
|
let _query = "DELETE FROM " + this.escapedName;
|
|
2569
2619
|
|
|
2570
2620
|
_query += (await this.prepareWhere({
|
|
@@ -2584,7 +2634,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2584
2634
|
}
|
|
2585
2635
|
|
|
2586
2636
|
if(returnQuery) return _query;
|
|
2587
|
-
return (this.t || this.db)[queryType](_query).catch(err => makeErr(err, localParams));
|
|
2637
|
+
return (this.t || this.db as any)[queryType](_query).catch((err: any) => makeErr(err, localParams));
|
|
2588
2638
|
} catch(e){
|
|
2589
2639
|
// console.trace(e)
|
|
2590
2640
|
if(localParams && localParams.testRule) throw e;
|
|
@@ -2592,11 +2642,11 @@ export class TableHandler extends ViewHandler {
|
|
|
2592
2642
|
}
|
|
2593
2643
|
};
|
|
2594
2644
|
|
|
2595
|
-
remove(filter: Filter, params?: UpdateParams, param3_unused?:
|
|
2645
|
+
remove(filter: Filter, params?: UpdateParams, param3_unused?: never, tableRules?: TableRule, localParams?: LocalParams){
|
|
2596
2646
|
return this.delete(filter, params, param3_unused , tableRules, localParams);
|
|
2597
2647
|
}
|
|
2598
2648
|
|
|
2599
|
-
async upsert(filter: Filter, newData
|
|
2649
|
+
async upsert(filter: Filter, newData: AnyObject, params?: UpdateParams, table_rules?: TableRule, localParams?: LocalParams): Promise<any> {
|
|
2600
2650
|
try {
|
|
2601
2651
|
/* Do it within a transaction to ensure consisency */
|
|
2602
2652
|
if(!this.t){
|
|
@@ -2606,12 +2656,12 @@ export class TableHandler extends ViewHandler {
|
|
|
2606
2656
|
}
|
|
2607
2657
|
|
|
2608
2658
|
async function _upsert(tblH: TableHandler){
|
|
2609
|
-
return tblH.find(filter, { select: "", limit: 1 },
|
|
2659
|
+
return tblH.find(filter, { select: "", limit: 1 }, undefined, table_rules, localParams)
|
|
2610
2660
|
.then(exists => {
|
|
2611
2661
|
if(exists && exists.length){
|
|
2612
2662
|
return tblH.update(filter, newData, params, table_rules, localParams);
|
|
2613
2663
|
} else {
|
|
2614
|
-
return tblH.insert({ ...newData, ...filter }, params,
|
|
2664
|
+
return tblH.insert({ ...newData, ...filter }, params, undefined, table_rules, localParams);
|
|
2615
2665
|
}
|
|
2616
2666
|
});
|
|
2617
2667
|
}
|
|
@@ -2622,7 +2672,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2622
2672
|
};
|
|
2623
2673
|
|
|
2624
2674
|
/* External request. Cannot sync from server */
|
|
2625
|
-
async sync(filter: Filter, params: SelectParams, param3_unused, table_rules: TableRule, localParams: LocalParams){
|
|
2675
|
+
async sync(filter: Filter, params: SelectParams, param3_unused: never, table_rules: TableRule, localParams: LocalParams){
|
|
2626
2676
|
if(!localParams) throw "Sync not allowed within the same server code";
|
|
2627
2677
|
const { socket } = localParams;
|
|
2628
2678
|
if(!socket) throw "INTERNAL ERROR: socket missing";
|
|
@@ -2667,7 +2717,7 @@ export class TableHandler extends ViewHandler {
|
|
|
2667
2717
|
});
|
|
2668
2718
|
|
|
2669
2719
|
/* Step 1: parse command and params */
|
|
2670
|
-
return this.find(filter, { select, limit: 0 },
|
|
2720
|
+
return this.find(filter, { select, limit: 0 }, undefined, table_rules, localParams)
|
|
2671
2721
|
.then(async isValid => {
|
|
2672
2722
|
|
|
2673
2723
|
const { filterFields, forcedFilter } = get(table_rules, "select") || {};
|
|
@@ -2678,7 +2728,8 @@ export class TableHandler extends ViewHandler {
|
|
|
2678
2728
|
return pubSubManager.addSync({
|
|
2679
2729
|
table_info: this.tableOrViewInfo,
|
|
2680
2730
|
condition,
|
|
2681
|
-
id_fields, synced_field,
|
|
2731
|
+
id_fields, synced_field,
|
|
2732
|
+
allow_delete,
|
|
2682
2733
|
socket,
|
|
2683
2734
|
table_rules,
|
|
2684
2735
|
filter: { ...filter },
|
|
@@ -2725,18 +2776,18 @@ import { JOIN_TYPES } from "./Prostgles";
|
|
|
2725
2776
|
import { BasicSession } from "./AuthHandler";
|
|
2726
2777
|
|
|
2727
2778
|
export class DboBuilder {
|
|
2728
|
-
tablesOrViews
|
|
2779
|
+
tablesOrViews?: TableSchema[]; //TableSchema TableOrViewInfo
|
|
2729
2780
|
/**
|
|
2730
2781
|
* Used in obtaining column names for error messages
|
|
2731
2782
|
*/
|
|
2732
|
-
constraints
|
|
2783
|
+
constraints?: PGConstraint[];
|
|
2733
2784
|
|
|
2734
2785
|
db: DB;
|
|
2735
2786
|
schema: string = "public";
|
|
2736
2787
|
|
|
2737
2788
|
// dbo: DbHandler | DbHandlerTX;
|
|
2738
2789
|
dbo: DbHandler;
|
|
2739
|
-
_pubSubManager
|
|
2790
|
+
_pubSubManager?: PubSubManager;
|
|
2740
2791
|
|
|
2741
2792
|
getPubSubManager = async () : Promise<PubSubManager> => {
|
|
2742
2793
|
if(!this._pubSubManager){
|
|
@@ -2763,26 +2814,27 @@ export class DboBuilder {
|
|
|
2763
2814
|
console.warn(`subscribe and sync cannot be used because db user is not a superuser `)
|
|
2764
2815
|
}
|
|
2765
2816
|
}
|
|
2766
|
-
|
|
2817
|
+
if(!this._pubSubManager) throw "Could not create this._pubSubManager";
|
|
2767
2818
|
return this._pubSubManager;
|
|
2768
2819
|
}
|
|
2769
2820
|
|
|
2770
|
-
pojoDefinitions
|
|
2771
|
-
dboDefinition
|
|
2821
|
+
pojoDefinitions?: string[];
|
|
2822
|
+
dboDefinition?: string;
|
|
2772
2823
|
|
|
2773
|
-
tsTypesDefinition
|
|
2824
|
+
tsTypesDefinition?: string;
|
|
2774
2825
|
|
|
2775
|
-
joins
|
|
2776
|
-
joinGraph
|
|
2777
|
-
joinPaths: JoinPaths;
|
|
2826
|
+
joins?: Join[];
|
|
2827
|
+
joinGraph?: Graph;
|
|
2828
|
+
joinPaths: JoinPaths = [];
|
|
2778
2829
|
|
|
2779
2830
|
prostgles: Prostgles;
|
|
2780
|
-
publishParser
|
|
2831
|
+
publishParser?: PublishParser;
|
|
2781
2832
|
|
|
2782
|
-
onSchemaChange
|
|
2833
|
+
onSchemaChange?: (event: { command: string; query: string }) => void;
|
|
2783
2834
|
|
|
2784
2835
|
private constructor(prostgles: Prostgles){
|
|
2785
2836
|
this.prostgles = prostgles;
|
|
2837
|
+
if(!this.prostgles.db) throw "db missing"
|
|
2786
2838
|
this.db = this.prostgles.db;
|
|
2787
2839
|
this.schema = this.prostgles.opts.schema || "public";
|
|
2788
2840
|
this.dbo = { } as unknown as DbHandler;
|
|
@@ -2844,10 +2896,10 @@ export class DboBuilder {
|
|
|
2844
2896
|
if(dup){
|
|
2845
2897
|
throw "Duplicate join declaration for table: " + dup.tables[0];
|
|
2846
2898
|
}
|
|
2847
|
-
const tovNames = this.tablesOrViews
|
|
2899
|
+
const tovNames = this.tablesOrViews!.map(t => t.name);
|
|
2848
2900
|
|
|
2849
2901
|
// 2 find incorrect tables
|
|
2850
|
-
const missing =
|
|
2902
|
+
const missing = joins.flatMap(j => j.tables).find(t => !tovNames.includes(t));
|
|
2851
2903
|
if(missing){
|
|
2852
2904
|
throw "Table not found: " + missing;
|
|
2853
2905
|
}
|
|
@@ -2862,9 +2914,9 @@ export class DboBuilder {
|
|
|
2862
2914
|
var t = <string>v[0],
|
|
2863
2915
|
f = <string[]>v[1];
|
|
2864
2916
|
|
|
2865
|
-
let tov = this.tablesOrViews
|
|
2917
|
+
let tov = this.tablesOrViews!.find(_t => _t.name === t);
|
|
2866
2918
|
if(!tov) throw "Table not found: " + t;
|
|
2867
|
-
const m1 = f.filter(k => !tov
|
|
2919
|
+
const m1 = f.filter(k => !tov!.columns.map(c => c.name).includes(k))
|
|
2868
2920
|
if(m1 && m1.length){
|
|
2869
2921
|
throw `Table ${t}(${tov.columns.map(c => c.name).join()}) has no fields named: ${m1.join()}`;
|
|
2870
2922
|
}
|
|
@@ -2889,17 +2941,17 @@ export class DboBuilder {
|
|
|
2889
2941
|
let _t = tables.slice().sort(),
|
|
2890
2942
|
t1 = _t[0],
|
|
2891
2943
|
t2 = _t[1];
|
|
2892
|
-
this.joinGraph[t1] = this.joinGraph[t1] || {};
|
|
2893
|
-
this.joinGraph[t1][t2] = 1;
|
|
2944
|
+
this.joinGraph![t1] = this.joinGraph![t1] || {};
|
|
2945
|
+
this.joinGraph![t1][t2] = 1;
|
|
2894
2946
|
|
|
2895
|
-
this.joinGraph[t2] = this.joinGraph[t2] || {};
|
|
2896
|
-
this.joinGraph[t2][t1] = 1;
|
|
2947
|
+
this.joinGraph![t2] = this.joinGraph![t2] || {};
|
|
2948
|
+
this.joinGraph![t2][t1] = 1;
|
|
2897
2949
|
});
|
|
2898
|
-
const tables =
|
|
2950
|
+
const tables = this.joins.flatMap(t => t.tables);
|
|
2899
2951
|
this.joinPaths = [];
|
|
2900
2952
|
tables.map(t1 => {
|
|
2901
2953
|
tables.map(t2 => {
|
|
2902
|
-
const spath = findShortestPath(this.joinGraph
|
|
2954
|
+
const spath = findShortestPath(this.joinGraph!, t1, t2);
|
|
2903
2955
|
if(spath && spath.distance < Infinity){
|
|
2904
2956
|
|
|
2905
2957
|
const existing1 = this.joinPaths.find(j => j.t1 === t1 && j.t2 === t2)
|
|
@@ -2946,7 +2998,7 @@ export type TxCB = {
|
|
|
2946
2998
|
|
|
2947
2999
|
await this.parseJoins();
|
|
2948
3000
|
|
|
2949
|
-
let joinTableNames = [];
|
|
3001
|
+
let joinTableNames: string[] = [];
|
|
2950
3002
|
|
|
2951
3003
|
let allDataDefs = "";
|
|
2952
3004
|
let i18nDef = "type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]>; }; \n"
|
|
@@ -2974,10 +3026,10 @@ export type TxCB = {
|
|
|
2974
3026
|
const TSTableDataName = snakify(tov.name, true);
|
|
2975
3027
|
const TSTableHandlerName = JSON.stringify(tov.name)
|
|
2976
3028
|
if(tov.is_view){
|
|
2977
|
-
this.dbo[tov.name] = new ViewHandler(this.db, tov, this,
|
|
3029
|
+
this.dbo[tov.name] = new ViewHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
|
|
2978
3030
|
this.dboDefinition += ` ${TSTableHandlerName}: ViewHandler<${TSTableDataName}> \n`;
|
|
2979
3031
|
} else {
|
|
2980
|
-
this.dbo[tov.name] = new TableHandler(this.db, tov, this,
|
|
3032
|
+
this.dbo[tov.name] = new TableHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
|
|
2981
3033
|
this.dboDefinition += ` ${TSTableHandlerName}: TableHandler<${TSTableDataName}> \n`;
|
|
2982
3034
|
}
|
|
2983
3035
|
allDataDefs += `export type ${TSTableDataName} = { \n` +
|
|
@@ -2991,6 +3043,19 @@ export type TxCB = {
|
|
|
2991
3043
|
let table = tov.name;
|
|
2992
3044
|
joinTableNames.push(table);
|
|
2993
3045
|
|
|
3046
|
+
const makeJoin = (
|
|
3047
|
+
isLeft = true,
|
|
3048
|
+
filter: Parameters<JoinMaker<AnyObject>>[0],
|
|
3049
|
+
select: Parameters<JoinMaker<AnyObject>>[1],
|
|
3050
|
+
options: Parameters<JoinMaker<AnyObject>>[2]
|
|
3051
|
+
): ReturnType<JoinMaker<AnyObject>> => {
|
|
3052
|
+
return {
|
|
3053
|
+
[isLeft? "$leftJoin" : "$innerJoin"]: table,
|
|
3054
|
+
filter,
|
|
3055
|
+
select,
|
|
3056
|
+
...options
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
2994
3059
|
this.dbo.innerJoin = this.dbo.innerJoin || {};
|
|
2995
3060
|
this.dbo.leftJoin = this.dbo.leftJoin || {};
|
|
2996
3061
|
this.dbo.innerJoinOne = this.dbo.innerJoinOne || {};
|
|
@@ -3007,14 +3072,6 @@ export type TxCB = {
|
|
|
3007
3072
|
this.dbo.innerJoinOne[table] = (filter, select, options = {}) => {
|
|
3008
3073
|
return makeJoin(false, filter, select, {...options, limit: 1});
|
|
3009
3074
|
}
|
|
3010
|
-
function makeJoin(isLeft = true, filter, select, options){
|
|
3011
|
-
return {
|
|
3012
|
-
[isLeft? "$leftJoin" : "$innerJoin"]: table,
|
|
3013
|
-
filter,
|
|
3014
|
-
select,
|
|
3015
|
-
...options
|
|
3016
|
-
}
|
|
3017
|
-
}
|
|
3018
3075
|
}
|
|
3019
3076
|
});
|
|
3020
3077
|
i18nDef += " }> \n";
|
|
@@ -3044,17 +3101,17 @@ export type TxCB = {
|
|
|
3044
3101
|
if(!this.dbo.sql){
|
|
3045
3102
|
|
|
3046
3103
|
let needType = true;// this.publishRawSQL && typeof this.publishRawSQL === "function";
|
|
3047
|
-
let DATA_TYPES = !needType? [] : await this.db.any("SELECT oid, typname FROM pg_type");
|
|
3048
|
-
let USER_TABLES = !needType? [] : await this.db.any("SELECT relid, relname FROM pg_catalog.pg_statio_user_tables");
|
|
3104
|
+
let DATA_TYPES: {oid: string, typname: PG_COLUMN_UDT_DATA_TYPE }[] = !needType? [] : await this.db.any("SELECT oid, typname FROM pg_type");
|
|
3105
|
+
let USER_TABLES: { relid: string; relname: string; }[] = !needType? [] : await this.db.any("SELECT relid, relname FROM pg_catalog.pg_statio_user_tables");
|
|
3049
3106
|
|
|
3050
|
-
this.dbo.sql = async (query: string, params: any, options: SQLOptions, localParams?: LocalParams) => {
|
|
3107
|
+
this.dbo.sql = async (query: string, params: any, options: SQLOptions | undefined, localParams?: LocalParams) => {
|
|
3051
3108
|
|
|
3052
|
-
const canRunSQL = async (localParams
|
|
3109
|
+
const canRunSQL = async (localParams?: LocalParams) => {
|
|
3053
3110
|
if(!localParams) return true;
|
|
3054
3111
|
|
|
3055
3112
|
const { socket } = localParams;
|
|
3056
|
-
const publishParams = await this.prostgles.publishParser
|
|
3057
|
-
let res = await this.prostgles.opts.publishRawSQL(publishParams);
|
|
3113
|
+
const publishParams = await this.prostgles.publishParser!.getPublishParams({ socket });
|
|
3114
|
+
let res = await this.prostgles.opts.publishRawSQL?.(publishParams);
|
|
3058
3115
|
return Boolean(res && typeof res === "boolean" || res === "*");
|
|
3059
3116
|
}
|
|
3060
3117
|
|
|
@@ -3065,12 +3122,12 @@ export type TxCB = {
|
|
|
3065
3122
|
|
|
3066
3123
|
if(returnType === "noticeSubscription"){
|
|
3067
3124
|
if(!socket) throw "Only allowed with client socket"
|
|
3068
|
-
return await this.prostgles.dbEventsManager
|
|
3125
|
+
return await this.prostgles.dbEventsManager?.addNotice(socket);
|
|
3069
3126
|
} else if(returnType === "statement"){
|
|
3070
3127
|
try {
|
|
3071
3128
|
return pgp.as.format(query, params);
|
|
3072
3129
|
} catch (err){
|
|
3073
|
-
throw err.toString();
|
|
3130
|
+
throw (err as any).toString();
|
|
3074
3131
|
}
|
|
3075
3132
|
} else if(this.db) {
|
|
3076
3133
|
|
|
@@ -3079,8 +3136,8 @@ export type TxCB = {
|
|
|
3079
3136
|
finalQuery = new PQ({ text: pgp.as.format(query, params), rowMode: "array" });
|
|
3080
3137
|
}
|
|
3081
3138
|
|
|
3082
|
-
let
|
|
3083
|
-
const {
|
|
3139
|
+
let _qres = await this.db.result(finalQuery, params)
|
|
3140
|
+
const { fields, rows, command } = _qres;
|
|
3084
3141
|
|
|
3085
3142
|
/**
|
|
3086
3143
|
* Fallback for watchSchema in case not superuser and cannot add db event listener
|
|
@@ -3102,7 +3159,7 @@ export type TxCB = {
|
|
|
3102
3159
|
|
|
3103
3160
|
if(command === "LISTEN"){
|
|
3104
3161
|
if(!socket) throw "Only allowed with client socket"
|
|
3105
|
-
return await this.prostgles.dbEventsManager
|
|
3162
|
+
return await this.prostgles.dbEventsManager?.addNotify(query, socket);
|
|
3106
3163
|
|
|
3107
3164
|
} else if(returnType === "rows") {
|
|
3108
3165
|
return rows;
|
|
@@ -3117,22 +3174,27 @@ export type TxCB = {
|
|
|
3117
3174
|
return rows.map(r => Object.values(r[0]));
|
|
3118
3175
|
|
|
3119
3176
|
} else {
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3177
|
+
|
|
3178
|
+
let qres: SQLResult = {
|
|
3179
|
+
duration: 0,
|
|
3180
|
+
..._qres,
|
|
3181
|
+
fields: fields?.map(f => {
|
|
3182
|
+
const dataType = DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID)?.typname ?? "text",
|
|
3123
3183
|
tableName = USER_TABLES.find(t => +t.relid === +f.tableID),
|
|
3124
|
-
|
|
3184
|
+
tsDataType = postgresToTsType(dataType);
|
|
3125
3185
|
|
|
3126
3186
|
return {
|
|
3127
3187
|
...f,
|
|
3128
|
-
|
|
3129
|
-
|
|
3188
|
+
tsDataType,
|
|
3189
|
+
dataType,
|
|
3190
|
+
udt_name: dataType,
|
|
3191
|
+
tableName: tableName?.relname
|
|
3130
3192
|
}
|
|
3131
|
-
})
|
|
3132
|
-
}
|
|
3193
|
+
}) ?? []
|
|
3194
|
+
};
|
|
3133
3195
|
return qres;
|
|
3134
3196
|
}
|
|
3135
|
-
|
|
3197
|
+
|
|
3136
3198
|
} else console.error("db missing");
|
|
3137
3199
|
}
|
|
3138
3200
|
} else {
|
|
@@ -3159,7 +3221,7 @@ export type TxCB = {
|
|
|
3159
3221
|
getTX = (cb: TxCB) => {
|
|
3160
3222
|
return this.db.tx((t) => {
|
|
3161
3223
|
let dbTX: TxHandler = {};
|
|
3162
|
-
this.tablesOrViews
|
|
3224
|
+
this.tablesOrViews?.map(tov => {
|
|
3163
3225
|
if(tov.is_view){
|
|
3164
3226
|
|
|
3165
3227
|
dbTX[tov.name] = new ViewHandler(this.db, tov, this, t, dbTX, this.joinPaths);
|
|
@@ -3416,17 +3478,20 @@ function validateObj(obj: object, allowedKeys: string[]): object{
|
|
|
3416
3478
|
}
|
|
3417
3479
|
|
|
3418
3480
|
|
|
3419
|
-
export function isPlainObject(o) {
|
|
3481
|
+
export function isPlainObject<T>(o: T): o is T | Record<string, any> {
|
|
3420
3482
|
return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
|
|
3421
3483
|
}
|
|
3422
|
-
|
|
3484
|
+
export function getKeys<T>(o: T): Array<keyof T>{
|
|
3485
|
+
return Object.keys(o) as any
|
|
3486
|
+
}
|
|
3423
3487
|
export function postgresToTsType(udt_data_type: PG_COLUMN_UDT_DATA_TYPE): keyof typeof TS_PG_Types {
|
|
3424
|
-
return
|
|
3488
|
+
return getKeys(TS_PG_Types).find(k => {
|
|
3489
|
+
// @ts-ignore
|
|
3425
3490
|
return TS_PG_Types[k].includes(udt_data_type) || !TS_PG_Types[k].length;
|
|
3426
3491
|
}) as keyof typeof TS_PG_Types;
|
|
3427
3492
|
}
|
|
3428
3493
|
|
|
3429
|
-
function sqlErrCodeToMsg(code){
|
|
3494
|
+
function sqlErrCodeToMsg(code: string){
|
|
3430
3495
|
const errs = {
|
|
3431
3496
|
"00000": "successful_completion",
|
|
3432
3497
|
"01000": "warning",
|
|
@@ -3671,6 +3736,7 @@ function sqlErrCodeToMsg(code){
|
|
|
3671
3736
|
},
|
|
3672
3737
|
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"}
|
|
3673
3738
|
|
|
3739
|
+
//@ts-ignore
|
|
3674
3740
|
return c2[code] || errs[code] || code;
|
|
3675
3741
|
|
|
3676
3742
|
/*
|