prostgles-server 3.0.78 → 3.0.79
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/DboBuilder/QueryBuilder/Functions.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions.js +18 -0
- package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
- package/dist/DboBuilder/TableHandler.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler.js +1 -1
- package/dist/DboBuilder/TableHandler.js.map +1 -1
- package/dist/DboBuilder/ViewHandler.d.ts +6 -12
- package/dist/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler.js +5 -207
- package/dist/DboBuilder/ViewHandler.js.map +1 -1
- package/dist/DboBuilder/delete.d.ts.map +1 -1
- package/dist/DboBuilder/delete.js +1 -1
- package/dist/DboBuilder/delete.js.map +1 -1
- package/dist/DboBuilder/getCondition.d.ts +19 -0
- package/dist/DboBuilder/getCondition.d.ts.map +1 -0
- package/dist/DboBuilder/getCondition.js +236 -0
- package/dist/DboBuilder/getCondition.js.map +1 -0
- package/dist/DboBuilder/insert.d.ts.map +1 -1
- package/dist/DboBuilder/insert.js +2 -2
- package/dist/DboBuilder/insert.js.map +1 -1
- package/dist/DboBuilder/subscribe.d.ts.map +1 -1
- package/dist/DboBuilder/subscribe.js +1 -1
- package/dist/DboBuilder/subscribe.js.map +1 -1
- package/dist/DboBuilder/update.d.ts.map +1 -1
- package/dist/DboBuilder/update.js +2 -2
- package/dist/DboBuilder/update.js.map +1 -1
- package/dist/DboBuilder.d.ts +2 -4
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +3 -4
- package/dist/DboBuilder.js.map +1 -1
- package/dist/Filtering.d.ts.map +1 -1
- package/dist/Filtering.js +94 -73
- package/dist/Filtering.js.map +1 -1
- package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/initPubSubManager.js +10 -2
- package/dist/PubSubManager/initPubSubManager.js.map +1 -1
- package/lib/DboBuilder/QueryBuilder/Functions.d.ts.map +1 -1
- package/lib/DboBuilder/QueryBuilder/Functions.js +18 -0
- package/lib/DboBuilder/QueryBuilder/Functions.ts +23 -0
- package/lib/DboBuilder/TableHandler.d.ts.map +1 -1
- package/lib/DboBuilder/TableHandler.js +1 -1
- package/lib/DboBuilder/TableHandler.ts +2 -2
- package/lib/DboBuilder/ViewHandler.d.ts +1 -14
- package/lib/DboBuilder/ViewHandler.d.ts.map +1 -1
- package/lib/DboBuilder/ViewHandler.js +5 -207
- package/lib/DboBuilder/ViewHandler.ts +9 -248
- package/lib/DboBuilder/delete.d.ts.map +1 -1
- package/lib/DboBuilder/delete.js +1 -1
- package/lib/DboBuilder/delete.ts +2 -2
- package/lib/DboBuilder/getCondition.d.ts +19 -0
- package/lib/DboBuilder/getCondition.d.ts.map +1 -0
- package/lib/DboBuilder/getCondition.js +235 -0
- package/lib/DboBuilder/getCondition.ts +279 -0
- package/lib/DboBuilder/insert.d.ts.map +1 -1
- package/lib/DboBuilder/insert.js +2 -2
- package/lib/DboBuilder/insert.ts +3 -3
- package/lib/DboBuilder/subscribe.d.ts.map +1 -1
- package/lib/DboBuilder/subscribe.js +1 -1
- package/lib/DboBuilder/subscribe.ts +2 -2
- package/lib/DboBuilder/update.d.ts.map +1 -1
- package/lib/DboBuilder/update.js +2 -2
- package/lib/DboBuilder/update.ts +3 -3
- package/lib/DboBuilder.d.ts +2 -4
- package/lib/DboBuilder.d.ts.map +1 -1
- package/lib/DboBuilder.js +3 -4
- package/lib/DboBuilder.ts +5 -13
- package/lib/Filtering.d.ts.map +1 -1
- package/lib/Filtering.js +94 -73
- package/lib/Filtering.ts +104 -79
- package/lib/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/lib/PubSubManager/initPubSubManager.js +10 -2
- package/lib/PubSubManager/initPubSubManager.ts +11 -2
- package/package.json +4 -4
- package/tests/client/PID.txt +1 -1
- package/tests/server/package-lock.json +7 -7
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCondition = void 0;
|
|
4
|
+
const prostgles_types_1 = require("prostgles-types");
|
|
5
|
+
const DboBuilder_1 = require("../DboBuilder");
|
|
6
|
+
const PubSubManager_1 = require("../PubSubManager/PubSubManager");
|
|
7
|
+
const Functions_1 = require("./QueryBuilder/Functions");
|
|
8
|
+
const QueryBuilder_1 = require("./QueryBuilder/QueryBuilder");
|
|
9
|
+
const Filtering_1 = require("../Filtering");
|
|
10
|
+
const FILTER_FUNCS = Functions_1.FUNCTIONS.filter(f => f.canBeUsedForFilter);
|
|
11
|
+
/**
|
|
12
|
+
* parses a single filter
|
|
13
|
+
* @example
|
|
14
|
+
* { fff: 2 } => "fff" = 2
|
|
15
|
+
* { fff: { $ilike: 'abc' } } => "fff" ilike 'abc'
|
|
16
|
+
*/
|
|
17
|
+
async function getCondition(params) {
|
|
18
|
+
const { filter, select, allowed_colnames, tableAlias, localParams, tableRules } = params;
|
|
19
|
+
let data = { ...filter };
|
|
20
|
+
/* Exists join filter */
|
|
21
|
+
const ERR = "Invalid exists filter. \nExpecting somethibng like: \n | { $exists: { tableName.tableName2: Filter } } \n | { $exists: { \"**.tableName3\": Filter } }\n | { path: string[]; filter: AnyObject }";
|
|
22
|
+
const SP_WILDCARD = "**";
|
|
23
|
+
let existsKeys = (0, prostgles_types_1.getKeys)(data)
|
|
24
|
+
.filter(k => prostgles_types_1.EXISTS_KEYS.includes(k) && Object.keys(data[k] ?? {}).length)
|
|
25
|
+
.map(key => {
|
|
26
|
+
const isJoined = key.toLowerCase().includes("join");
|
|
27
|
+
const filterValue = data[key];
|
|
28
|
+
/**
|
|
29
|
+
* type ExistsJoined =
|
|
30
|
+
* | { "table1.table2": { column: filterValue } }
|
|
31
|
+
* | { path: string[]; filter: AnyObject }
|
|
32
|
+
*/
|
|
33
|
+
const dataKeys = Object.keys(filterValue);
|
|
34
|
+
const isDetailed = dataKeys.length === 2 && dataKeys.every(key => ["path", "filter"].includes(key));
|
|
35
|
+
const firstKey = dataKeys[0];
|
|
36
|
+
/**
|
|
37
|
+
* Prevent some errors with table names that contain "."
|
|
38
|
+
*/
|
|
39
|
+
const firstKeyIsATable = !!this.dboBuilder.dbo[firstKey];
|
|
40
|
+
let tables = isDetailed ? filterValue.path : (firstKeyIsATable ? [firstKey] : firstKey.split("."));
|
|
41
|
+
let f2 = isDetailed ? filterValue.filter : filterValue[firstKey];
|
|
42
|
+
let shortestJoin = false;
|
|
43
|
+
if (!isJoined) {
|
|
44
|
+
if (tables.length !== 1)
|
|
45
|
+
throw "Expecting single table in exists filter. Example: { $exists: { tableName: Filter } }";
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
/* First part can be the ** param meaning shortest join. Will be overriden by anything in tableConfig */
|
|
49
|
+
if (!tables.length) {
|
|
50
|
+
throw ERR + "\nBut got: " + filterValue;
|
|
51
|
+
}
|
|
52
|
+
if (tables[0] === SP_WILDCARD) {
|
|
53
|
+
tables = tables.slice(1);
|
|
54
|
+
shortestJoin = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
key,
|
|
59
|
+
existType: key,
|
|
60
|
+
isJoined,
|
|
61
|
+
shortestJoin,
|
|
62
|
+
f2,
|
|
63
|
+
tables
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
/* Exists with exact path */
|
|
67
|
+
// Object.keys(data).map(k => {
|
|
68
|
+
// let isthis = isPlainObject(data[k]) && !this.column_names.includes(k) && !k.split(".").find(kt => !this.dboBuilder.dbo[kt]);
|
|
69
|
+
// if(isthis) {
|
|
70
|
+
// existsKeys.push({
|
|
71
|
+
// key: k,
|
|
72
|
+
// notJoined: false,
|
|
73
|
+
// exactPaths: k.split(".")
|
|
74
|
+
// });
|
|
75
|
+
// }
|
|
76
|
+
// });
|
|
77
|
+
let funcConds = [];
|
|
78
|
+
const funcFilterkeys = FILTER_FUNCS.filter(f => {
|
|
79
|
+
return f.name in data;
|
|
80
|
+
});
|
|
81
|
+
funcFilterkeys.map(f => {
|
|
82
|
+
const funcArgs = data[f.name];
|
|
83
|
+
if (!Array.isArray(funcArgs))
|
|
84
|
+
throw `A function filter must contain an array. E.g: { $funcFilterName: ["col1"] } \n but got: ${JSON.stringify((0, prostgles_types_1.pickKeys)(data, [f.name]))} `;
|
|
85
|
+
const fields = this.parseFieldFilter(f.getFields(funcArgs), true, allowed_colnames);
|
|
86
|
+
const dissallowedCols = fields.filter(fname => !allowed_colnames.includes(fname));
|
|
87
|
+
if (dissallowedCols.length) {
|
|
88
|
+
throw `Invalid/disallowed columns found in function filter: ${dissallowedCols}`;
|
|
89
|
+
}
|
|
90
|
+
funcConds.push(f.getQuery({ args: funcArgs, allColumns: this.columns, allowedFields: allowed_colnames, tableAlias }));
|
|
91
|
+
});
|
|
92
|
+
let existsCond = "";
|
|
93
|
+
if (existsKeys.length) {
|
|
94
|
+
existsCond = (await Promise.all(existsKeys.map(async (k) => await this.prepareExistCondition(k, localParams)))).join(" AND ");
|
|
95
|
+
}
|
|
96
|
+
/* Computed field queries */
|
|
97
|
+
const p = this.getValidatedRules(tableRules, localParams);
|
|
98
|
+
const computedFields = p.allColumns.filter(c => c.type === "computed");
|
|
99
|
+
let computedColConditions = [];
|
|
100
|
+
Object.keys(data || {}).map(key => {
|
|
101
|
+
const compCol = computedFields.find(cf => cf.name === key);
|
|
102
|
+
if (compCol) {
|
|
103
|
+
computedColConditions.push(compCol.getQuery({
|
|
104
|
+
tableAlias,
|
|
105
|
+
allowedFields: p.select.fields,
|
|
106
|
+
allColumns: this.columns,
|
|
107
|
+
/* CTID not available in AFTER trigger */
|
|
108
|
+
// ctidField: this.is_view? undefined : "ctid"
|
|
109
|
+
ctidField: undefined,
|
|
110
|
+
}) + ` = ${DboBuilder_1.pgp.as.format("$1", [data[key]])}`);
|
|
111
|
+
delete data[key];
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
let allowedSelect = [];
|
|
115
|
+
/* Select aliases take precedence over col names. This is to ensure filters work correctly and even on computed cols*/
|
|
116
|
+
if (select) {
|
|
117
|
+
/* Allow filtering by selected fields/funcs */
|
|
118
|
+
allowedSelect = select.filter(s => {
|
|
119
|
+
/* */
|
|
120
|
+
if (["function", "computed", "column"].includes(s.type)) {
|
|
121
|
+
if (s.type !== "column" || allowed_colnames.includes(s.alias)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/* Add remaining allowed fields */
|
|
129
|
+
allowedSelect = allowedSelect.concat(p.allColumns.filter(c => allowed_colnames.includes(c.name) &&
|
|
130
|
+
!allowedSelect.find(s => s.alias === c.name)).map(f => ({
|
|
131
|
+
type: f.type,
|
|
132
|
+
alias: f.name,
|
|
133
|
+
getQuery: (tableAlias) => f.getQuery({
|
|
134
|
+
tableAlias,
|
|
135
|
+
allColumns: this.columns,
|
|
136
|
+
allowedFields: allowed_colnames
|
|
137
|
+
}),
|
|
138
|
+
selected: false,
|
|
139
|
+
getFields: () => [f.name],
|
|
140
|
+
column_udt_type: f.type === "column" ? this.columns.find(c => c.name === f.name)?.udt_name : undefined
|
|
141
|
+
})));
|
|
142
|
+
/* Parse complex filters
|
|
143
|
+
{
|
|
144
|
+
$filter: [
|
|
145
|
+
{ $func: [...] },
|
|
146
|
+
"=",
|
|
147
|
+
value | { $func: [..] }
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
*/
|
|
151
|
+
const complexFilters = [];
|
|
152
|
+
const complexFilterKey = "$filter";
|
|
153
|
+
const allowedComparators = [">", "<", "=", "<=", ">=", "<>", "!="];
|
|
154
|
+
if (complexFilterKey in data) {
|
|
155
|
+
/**
|
|
156
|
+
* { $funcName: [arg1, arg2] }
|
|
157
|
+
* { $column: "column_name" }
|
|
158
|
+
*/
|
|
159
|
+
const getFuncQuery = (funcData) => {
|
|
160
|
+
if ((0, prostgles_types_1.isObject)(funcData) && "$column" in funcData) {
|
|
161
|
+
const column = funcData["$column"];
|
|
162
|
+
if (typeof column !== "string") {
|
|
163
|
+
throw `expecting: \n { $column: "column_name" } received:\n ${JSON.stringify(funcData)}`;
|
|
164
|
+
}
|
|
165
|
+
if (!allowed_colnames.includes(column)) {
|
|
166
|
+
throw `Dissallowed or Invalid column ${column}. Allowed columns: ${allowed_colnames}`;
|
|
167
|
+
}
|
|
168
|
+
return (0, QueryBuilder_1.asNameAlias)(column, tableAlias);
|
|
169
|
+
}
|
|
170
|
+
const { funcName, args } = (0, QueryBuilder_1.parseFunctionObject)(funcData);
|
|
171
|
+
const funcDef = (0, Functions_1.parseFunction)({ func: funcName, args, functions: Functions_1.FUNCTIONS, allowedFields: allowed_colnames });
|
|
172
|
+
return funcDef.getQuery({ args, tableAlias, allColumns: this.columns, allowedFields: allowed_colnames });
|
|
173
|
+
};
|
|
174
|
+
const complexFilter = data[complexFilterKey];
|
|
175
|
+
if (!Array.isArray(complexFilter)) {
|
|
176
|
+
throw `Invalid $filter. Must contain an array of at least element but got: ${JSON.stringify(complexFilter)} `;
|
|
177
|
+
}
|
|
178
|
+
const [leftFilter, comparator, rightFilterOrValue] = complexFilter;
|
|
179
|
+
const leftVal = getFuncQuery(leftFilter);
|
|
180
|
+
let result = leftVal;
|
|
181
|
+
if (comparator) {
|
|
182
|
+
if (!allowedComparators.includes(comparator)) {
|
|
183
|
+
throw `Invalid $filter. comparator ${JSON.stringify(comparator)} is not valid. Expecting one of: ${allowedComparators}`;
|
|
184
|
+
}
|
|
185
|
+
if (!rightFilterOrValue) {
|
|
186
|
+
throw "Invalid $filter. Expecting a value or function after the comparator";
|
|
187
|
+
}
|
|
188
|
+
const rightVal = (0, prostgles_types_1.isObject)(rightFilterOrValue) ? getFuncQuery(rightFilterOrValue) : (0, PubSubManager_1.asValue)(rightFilterOrValue);
|
|
189
|
+
if (leftVal === rightVal) {
|
|
190
|
+
throw "Invalid $filter. Cannot compare two identical function signatures: " + JSON.stringify(leftFilter);
|
|
191
|
+
}
|
|
192
|
+
result += ` ${comparator} ${rightVal}`;
|
|
193
|
+
}
|
|
194
|
+
complexFilters.push(result);
|
|
195
|
+
}
|
|
196
|
+
/* Parse join filters
|
|
197
|
+
{ $joinFilter: { $ST_DWithin: [table.col, foreignTable.col, distance] }
|
|
198
|
+
will make an exists filter
|
|
199
|
+
*/
|
|
200
|
+
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));
|
|
201
|
+
// if(allowed_colnames){
|
|
202
|
+
// const aliasedColumns = (select || []).filter(s =>
|
|
203
|
+
// ["function", "computed", "column"].includes(s.type) && allowed_colnames.includes(s.alias) ||
|
|
204
|
+
// s.getFields().find(f => allowed_colnames.includes(f))
|
|
205
|
+
// ).map(s => s.alias);
|
|
206
|
+
// const validCols = [...allowed_colnames, ...aliasedColumns];
|
|
207
|
+
// }
|
|
208
|
+
const validFieldNames = allowedSelect.map(s => s.alias);
|
|
209
|
+
const invalidColumn = filterKeys
|
|
210
|
+
.find(fName => !validFieldNames.find(c => c === fName ||
|
|
211
|
+
(fName.startsWith(c) && (fName.slice(c.length).includes("->") ||
|
|
212
|
+
fName.slice(c.length).includes(".")))));
|
|
213
|
+
if (invalidColumn) {
|
|
214
|
+
throw `Table: ${this.name} -> disallowed/inexistent columns in filter: ${invalidColumn} \n Expecting one of: ${allowedSelect.map(s => s.type === "column" ? s.getQuery() : s.alias).join(", ")}`;
|
|
215
|
+
}
|
|
216
|
+
/* TODO: Allow filter funcs */
|
|
217
|
+
// const singleFuncs = FUNCTIONS.filter(f => f.singleColArg);
|
|
218
|
+
const f = (0, prostgles_types_1.pickKeys)(data, filterKeys);
|
|
219
|
+
const q = (0, Filtering_1.parseFilterItem)({
|
|
220
|
+
filter: f,
|
|
221
|
+
tableAlias,
|
|
222
|
+
pgp: DboBuilder_1.pgp,
|
|
223
|
+
select: allowedSelect
|
|
224
|
+
});
|
|
225
|
+
let templates = [q].filter(q => q);
|
|
226
|
+
if (existsCond)
|
|
227
|
+
templates.push(existsCond);
|
|
228
|
+
templates = templates.concat(funcConds);
|
|
229
|
+
templates = templates.concat(computedColConditions);
|
|
230
|
+
templates = templates.concat(complexFilters);
|
|
231
|
+
/* sorted to ensure duplicate subscription channels are not created due to different condition order */
|
|
232
|
+
return templates.sort()
|
|
233
|
+
.join(" AND \n");
|
|
234
|
+
}
|
|
235
|
+
exports.getCondition = getCondition;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { AnyObject, EXISTS_KEY, EXISTS_KEYS, getKeys, isObject, pickKeys } from "prostgles-types";
|
|
2
|
+
import { ExistsFilterConfig, LocalParams, makeErrorFromPGError, pgp } from "../DboBuilder";
|
|
3
|
+
import { TableRule } from "../PublishParser";
|
|
4
|
+
import { asValue } from "../PubSubManager/PubSubManager";
|
|
5
|
+
import { FUNCTIONS, parseFunction } from "./QueryBuilder/Functions";
|
|
6
|
+
import { asNameAlias, parseFunctionObject, SelectItem } from "./QueryBuilder/QueryBuilder";
|
|
7
|
+
import { ViewHandler } from "./ViewHandler";
|
|
8
|
+
import { parseFilterItem } from "../Filtering";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const FILTER_FUNCS = FUNCTIONS.filter(f => f.canBeUsedForFilter);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* parses a single filter
|
|
15
|
+
* @example
|
|
16
|
+
* { fff: 2 } => "fff" = 2
|
|
17
|
+
* { fff: { $ilike: 'abc' } } => "fff" ilike 'abc'
|
|
18
|
+
*/
|
|
19
|
+
export async function getCondition(this: ViewHandler, params: { filter: any, select?: SelectItem[], allowed_colnames: string[], tableAlias?: string, localParams?: LocalParams, tableRules?: TableRule }) {
|
|
20
|
+
const { filter, select, allowed_colnames, tableAlias, localParams, tableRules } = params;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
let data = { ... (filter as any) } as any;
|
|
24
|
+
|
|
25
|
+
/* Exists join filter */
|
|
26
|
+
const ERR = "Invalid exists filter. \nExpecting somethibng like: \n | { $exists: { tableName.tableName2: Filter } } \n | { $exists: { \"**.tableName3\": Filter } }\n | { path: string[]; filter: AnyObject }"
|
|
27
|
+
const SP_WILDCARD = "**";
|
|
28
|
+
let existsKeys: ExistsFilterConfig[] = getKeys(data)
|
|
29
|
+
.filter(k => EXISTS_KEYS.includes(k as EXISTS_KEY) && Object.keys(data[k] ?? {}).length)
|
|
30
|
+
.map(key => {
|
|
31
|
+
|
|
32
|
+
const isJoined = key.toLowerCase().includes("join");
|
|
33
|
+
|
|
34
|
+
const filterValue = data[key];
|
|
35
|
+
/**
|
|
36
|
+
* type ExistsJoined =
|
|
37
|
+
* | { "table1.table2": { column: filterValue } }
|
|
38
|
+
* | { path: string[]; filter: AnyObject }
|
|
39
|
+
*/
|
|
40
|
+
const dataKeys = Object.keys(filterValue);
|
|
41
|
+
const isDetailed = dataKeys.length === 2 && dataKeys.every(key => ["path", "filter"].includes(key));
|
|
42
|
+
|
|
43
|
+
const firstKey = dataKeys[0];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Prevent some errors with table names that contain "."
|
|
47
|
+
*/
|
|
48
|
+
const firstKeyIsATable = !!this.dboBuilder.dbo[firstKey];
|
|
49
|
+
let tables = isDetailed? filterValue.path : (firstKeyIsATable? [firstKey] : firstKey.split("."));
|
|
50
|
+
let f2 = isDetailed? filterValue.filter : filterValue[firstKey];
|
|
51
|
+
let shortestJoin = false;
|
|
52
|
+
|
|
53
|
+
if (!isJoined) {
|
|
54
|
+
if (tables.length !== 1) throw "Expecting single table in exists filter. Example: { $exists: { tableName: Filter } }"
|
|
55
|
+
} else {
|
|
56
|
+
/* First part can be the ** param meaning shortest join. Will be overriden by anything in tableConfig */
|
|
57
|
+
|
|
58
|
+
if (!tables.length) {
|
|
59
|
+
throw ERR + "\nBut got: " + filterValue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (tables[0] === SP_WILDCARD) {
|
|
63
|
+
tables = tables.slice(1);
|
|
64
|
+
shortestJoin = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
key,
|
|
70
|
+
existType: key as EXISTS_KEY,
|
|
71
|
+
isJoined,
|
|
72
|
+
shortestJoin,
|
|
73
|
+
f2,
|
|
74
|
+
tables
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
/* Exists with exact path */
|
|
78
|
+
// Object.keys(data).map(k => {
|
|
79
|
+
// let isthis = isPlainObject(data[k]) && !this.column_names.includes(k) && !k.split(".").find(kt => !this.dboBuilder.dbo[kt]);
|
|
80
|
+
// if(isthis) {
|
|
81
|
+
// existsKeys.push({
|
|
82
|
+
// key: k,
|
|
83
|
+
// notJoined: false,
|
|
84
|
+
// exactPaths: k.split(".")
|
|
85
|
+
// });
|
|
86
|
+
// }
|
|
87
|
+
// });
|
|
88
|
+
let funcConds: string[] = [];
|
|
89
|
+
const funcFilterkeys = FILTER_FUNCS.filter(f => {
|
|
90
|
+
return f.name in data;
|
|
91
|
+
});
|
|
92
|
+
funcFilterkeys.map(f => {
|
|
93
|
+
const funcArgs = data[f.name];
|
|
94
|
+
if (!Array.isArray(funcArgs)) throw `A function filter must contain an array. E.g: { $funcFilterName: ["col1"] } \n but got: ${JSON.stringify(pickKeys(data, [f.name]))} `;
|
|
95
|
+
const fields = this.parseFieldFilter(f.getFields(funcArgs), true, allowed_colnames);
|
|
96
|
+
|
|
97
|
+
const dissallowedCols = fields.filter(fname => !allowed_colnames.includes(fname))
|
|
98
|
+
if (dissallowedCols.length) {
|
|
99
|
+
throw `Invalid/disallowed columns found in function filter: ${dissallowedCols}`
|
|
100
|
+
}
|
|
101
|
+
funcConds.push(f.getQuery({ args: funcArgs, allColumns: this.columns, allowedFields: allowed_colnames, tableAlias }));
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
let existsCond = "";
|
|
106
|
+
if (existsKeys.length) {
|
|
107
|
+
existsCond = (await Promise.all(existsKeys.map(async k => await this.prepareExistCondition(k, localParams)))).join(" AND ");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Computed field queries */
|
|
111
|
+
const p = this.getValidatedRules(tableRules, localParams);
|
|
112
|
+
const computedFields = p.allColumns.filter(c => c.type === "computed");
|
|
113
|
+
let computedColConditions: string[] = [];
|
|
114
|
+
Object.keys(data || {}).map(key => {
|
|
115
|
+
const compCol = computedFields.find(cf => cf.name === key);
|
|
116
|
+
if (compCol) {
|
|
117
|
+
computedColConditions.push(
|
|
118
|
+
compCol.getQuery({
|
|
119
|
+
tableAlias,
|
|
120
|
+
allowedFields: p.select.fields,
|
|
121
|
+
allColumns: this.columns,
|
|
122
|
+
|
|
123
|
+
/* CTID not available in AFTER trigger */
|
|
124
|
+
// ctidField: this.is_view? undefined : "ctid"
|
|
125
|
+
|
|
126
|
+
ctidField: undefined,
|
|
127
|
+
}) + ` = ${pgp.as.format("$1", [(data as any)[key]])}`
|
|
128
|
+
);
|
|
129
|
+
delete (data as any)[key];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
let allowedSelect: SelectItem[] = [];
|
|
134
|
+
/* Select aliases take precedence over col names. This is to ensure filters work correctly and even on computed cols*/
|
|
135
|
+
if (select) {
|
|
136
|
+
/* Allow filtering by selected fields/funcs */
|
|
137
|
+
allowedSelect = select.filter(s => {
|
|
138
|
+
/* */
|
|
139
|
+
if (["function", "computed", "column"].includes(s.type)) {
|
|
140
|
+
if (s.type !== "column" || allowed_colnames.includes(s.alias)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Add remaining allowed fields */
|
|
149
|
+
allowedSelect = allowedSelect.concat(
|
|
150
|
+
p.allColumns.filter(c =>
|
|
151
|
+
allowed_colnames.includes(c.name) &&
|
|
152
|
+
!allowedSelect.find(s => s.alias === c.name)
|
|
153
|
+
).map(f => ({
|
|
154
|
+
type: f.type,
|
|
155
|
+
alias: f.name,
|
|
156
|
+
getQuery: (tableAlias) => f.getQuery({
|
|
157
|
+
tableAlias,
|
|
158
|
+
allColumns: this.columns,
|
|
159
|
+
allowedFields: allowed_colnames
|
|
160
|
+
}),
|
|
161
|
+
selected: false,
|
|
162
|
+
getFields: () => [f.name],
|
|
163
|
+
column_udt_type: f.type === "column" ? this.columns.find(c => c.name === f.name)?.udt_name : undefined
|
|
164
|
+
}))
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
/* Parse complex filters
|
|
168
|
+
{
|
|
169
|
+
$filter: [
|
|
170
|
+
{ $func: [...] },
|
|
171
|
+
"=",
|
|
172
|
+
value | { $func: [..] }
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
*/
|
|
176
|
+
const complexFilters: string[] = [];
|
|
177
|
+
const complexFilterKey = "$filter";
|
|
178
|
+
const allowedComparators = [">", "<", "=", "<=", ">=", "<>", "!="]
|
|
179
|
+
if (complexFilterKey in data) {
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* { $funcName: [arg1, arg2] }
|
|
183
|
+
* { $column: "column_name" }
|
|
184
|
+
*/
|
|
185
|
+
const getFuncQuery = (funcData: AnyObject): string => {
|
|
186
|
+
if(isObject(funcData) && "$column" in funcData){
|
|
187
|
+
const column = funcData["$column"]
|
|
188
|
+
if(typeof column !== "string"){
|
|
189
|
+
throw `expecting: \n { $column: "column_name" } received:\n ${JSON.stringify(funcData)}`;
|
|
190
|
+
}
|
|
191
|
+
if(!allowed_colnames.includes(column)){
|
|
192
|
+
throw `Dissallowed or Invalid column ${column}. Allowed columns: ${allowed_colnames}`;
|
|
193
|
+
}
|
|
194
|
+
return asNameAlias(column, tableAlias)
|
|
195
|
+
}
|
|
196
|
+
const { funcName, args } = parseFunctionObject(funcData);
|
|
197
|
+
const funcDef = parseFunction({ func: funcName, args, functions: FUNCTIONS, allowedFields: allowed_colnames });
|
|
198
|
+
return funcDef.getQuery({ args, tableAlias, allColumns: this.columns, allowedFields: allowed_colnames });
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const complexFilter = data[complexFilterKey];
|
|
202
|
+
if (!Array.isArray(complexFilter)) {
|
|
203
|
+
throw `Invalid $filter. Must contain an array of at least element but got: ${JSON.stringify(complexFilter)} `
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const [leftFilter, comparator, rightFilterOrValue] = complexFilter;
|
|
207
|
+
|
|
208
|
+
const leftVal = getFuncQuery(leftFilter);
|
|
209
|
+
let result = leftVal;
|
|
210
|
+
if (comparator) {
|
|
211
|
+
if (!allowedComparators.includes(comparator)) {
|
|
212
|
+
throw `Invalid $filter. comparator ${JSON.stringify(comparator)} is not valid. Expecting one of: ${allowedComparators}`;
|
|
213
|
+
}
|
|
214
|
+
if (!rightFilterOrValue) {
|
|
215
|
+
throw "Invalid $filter. Expecting a value or function after the comparator";
|
|
216
|
+
}
|
|
217
|
+
const rightVal = isObject(rightFilterOrValue) ? getFuncQuery(rightFilterOrValue) : asValue(rightFilterOrValue);
|
|
218
|
+
if (leftVal === rightVal){
|
|
219
|
+
throw "Invalid $filter. Cannot compare two identical function signatures: " + JSON.stringify(leftFilter);
|
|
220
|
+
}
|
|
221
|
+
result += ` ${comparator} ${rightVal}`;
|
|
222
|
+
}
|
|
223
|
+
complexFilters.push(result);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
/* Parse join filters
|
|
228
|
+
{ $joinFilter: { $ST_DWithin: [table.col, foreignTable.col, distance] }
|
|
229
|
+
will make an exists filter
|
|
230
|
+
*/
|
|
231
|
+
|
|
232
|
+
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));
|
|
233
|
+
// if(allowed_colnames){
|
|
234
|
+
// const aliasedColumns = (select || []).filter(s =>
|
|
235
|
+
// ["function", "computed", "column"].includes(s.type) && allowed_colnames.includes(s.alias) ||
|
|
236
|
+
// s.getFields().find(f => allowed_colnames.includes(f))
|
|
237
|
+
// ).map(s => s.alias);
|
|
238
|
+
// const validCols = [...allowed_colnames, ...aliasedColumns];
|
|
239
|
+
|
|
240
|
+
// }
|
|
241
|
+
const validFieldNames = allowedSelect.map(s => s.alias);
|
|
242
|
+
const invalidColumn = filterKeys
|
|
243
|
+
.find(fName => !validFieldNames.find(c =>
|
|
244
|
+
c === fName ||
|
|
245
|
+
(
|
|
246
|
+
fName.startsWith(c) && (
|
|
247
|
+
fName.slice(c.length).includes("->") ||
|
|
248
|
+
fName.slice(c.length).includes(".")
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
));
|
|
252
|
+
|
|
253
|
+
if (invalidColumn) {
|
|
254
|
+
throw `Table: ${this.name} -> disallowed/inexistent columns in filter: ${invalidColumn} \n Expecting one of: ${allowedSelect.map(s => s.type === "column" ? s.getQuery() : s.alias).join(", ")}`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* TODO: Allow filter funcs */
|
|
258
|
+
// const singleFuncs = FUNCTIONS.filter(f => f.singleColArg);
|
|
259
|
+
|
|
260
|
+
const f = pickKeys(data, filterKeys);
|
|
261
|
+
const q = parseFilterItem({
|
|
262
|
+
filter: f,
|
|
263
|
+
tableAlias,
|
|
264
|
+
pgp,
|
|
265
|
+
select: allowedSelect
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
let templates: string[] = [q].filter(q => q);
|
|
269
|
+
|
|
270
|
+
if (existsCond) templates.push(existsCond);
|
|
271
|
+
templates = templates.concat(funcConds);
|
|
272
|
+
templates = templates.concat(computedColConditions);
|
|
273
|
+
templates = templates.concat(complexFilters);
|
|
274
|
+
|
|
275
|
+
/* sorted to ensure duplicate subscription channels are not created due to different condition order */
|
|
276
|
+
return templates.sort()
|
|
277
|
+
.join(" AND \n");
|
|
278
|
+
|
|
279
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["insert.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAqC,YAAY,EAAY,MAAM,iBAAiB,CAAC;AACvG,OAAO,EAAiB,WAAW,
|
|
1
|
+
{"version":3,"file":"insert.d.ts","sourceRoot":"","sources":["insert.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAqC,YAAY,EAAY,MAAM,iBAAiB,CAAC;AACvG,OAAO,EAAiB,WAAW,EAAyC,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,wBAAsB,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,CAiL1N"}
|
package/lib/DboBuilder/insert.js
CHANGED
|
@@ -129,10 +129,10 @@ async function insert(rowOrRows, param2, param3_unused, tableRules, localParams)
|
|
|
129
129
|
const tx = localParams?.tx?.t || this.t;
|
|
130
130
|
const allowedFieldKeys = this.parseFieldFilter(fields);
|
|
131
131
|
if (tx) {
|
|
132
|
-
result = await tx[queryType](query).catch((err) => (0, DboBuilder_1.
|
|
132
|
+
result = await tx[queryType](query).catch((err) => (0, DboBuilder_1.makeErrorFromPGError)(err, localParams, this, allowedFieldKeys));
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
|
-
result = await this.db.tx(t => t[queryType](query)).catch(err => (0, DboBuilder_1.
|
|
135
|
+
result = await this.db.tx(t => t[queryType](query)).catch(err => (0, DboBuilder_1.makeErrorFromPGError)(err, localParams, this, allowedFieldKeys));
|
|
136
136
|
}
|
|
137
137
|
if (tableRules?.[ACTION]?.postValidate) {
|
|
138
138
|
if (!finalDBtx)
|
package/lib/DboBuilder/insert.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pgPromise from "pg-promise";
|
|
2
2
|
import { AnyObject, asName, FieldFilter, get, getKeys, InsertParams, isObject } from "prostgles-types";
|
|
3
|
-
import { isPlainObject, LocalParams,
|
|
3
|
+
import { isPlainObject, LocalParams, makeErrorFromPGError, parseError, pgp } from "../DboBuilder";
|
|
4
4
|
import { TableRule } from "../PublishParser";
|
|
5
5
|
import { asValue, omitKeys, pickKeys } from "../PubSubManager/PubSubManager";
|
|
6
6
|
import { TableHandler } from "./TableHandler";
|
|
@@ -149,9 +149,9 @@ export async function insert(this: TableHandler, rowOrRows: (AnyObject | AnyObje
|
|
|
149
149
|
|
|
150
150
|
const allowedFieldKeys = this.parseFieldFilter(fields);
|
|
151
151
|
if (tx) {
|
|
152
|
-
result = await (tx as any)[queryType](query).catch((err: any) =>
|
|
152
|
+
result = await (tx as any)[queryType](query).catch((err: any) => makeErrorFromPGError(err, localParams, this, allowedFieldKeys));
|
|
153
153
|
} else {
|
|
154
|
-
result = await this.db.tx(t => (t as any)[queryType](query)).catch(err =>
|
|
154
|
+
result = await this.db.tx(t => (t as any)[queryType](query)).catch(err => makeErrorFromPGError(err, localParams, this, allowedFieldKeys));
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
if(tableRules?.[ACTION]?.postValidate){
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAU,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAoC,MAAM,eAAe,CAAC;AACtF,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,oBAAY,SAAS,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,GAAG,CAAC;AAEpD,iBAAe,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,GAAG,CAAA;CAAE,CAAC,CAAA;AAC/I,iBAAe,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,GAAG,SAAS,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;AA4NzL,OAAO,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -43,7 +43,7 @@ async function subscribe(filter, params, localFunc, table_rules, localParams) {
|
|
|
43
43
|
def = def.slice(0, -1);
|
|
44
44
|
}
|
|
45
45
|
if (!def || typeof def !== "string") {
|
|
46
|
-
throw (0, DboBuilder_1.
|
|
46
|
+
throw (0, DboBuilder_1.makeErrorFromPGError)("Could get view definition");
|
|
47
47
|
}
|
|
48
48
|
const { fields } = await this.dboBuilder.dbo.sql(`SELECT * FROM ( \n ${def} \n ) prostgles_subscribe_view_definition LIMIT 0`, {});
|
|
49
49
|
const tableColumns = fields.filter(f => f.tableName && f.columnName);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyObject, asName, SubscribeParams } from "prostgles-types";
|
|
2
|
-
import { Filter, LocalParams,
|
|
2
|
+
import { Filter, LocalParams, makeErrorFromPGError, parseError } from "../DboBuilder";
|
|
3
3
|
import { TableRule } from "../PublishParser";
|
|
4
4
|
import { log, omitKeys, ViewSubscriptionOptions } from "../PubSubManager/PubSubManager";
|
|
5
5
|
import { ViewHandler } from "./ViewHandler";
|
|
@@ -62,7 +62,7 @@ async function subscribe(this: ViewHandler, filter: Filter, params: SubscribePar
|
|
|
62
62
|
def = def.slice(0, -1);
|
|
63
63
|
}
|
|
64
64
|
if (!def || typeof def !== "string") {
|
|
65
|
-
throw
|
|
65
|
+
throw makeErrorFromPGError("Could get view definition");
|
|
66
66
|
}
|
|
67
67
|
const { fields } = await this.dboBuilder.dbo.sql!(`SELECT * FROM ( \n ${def} \n ) prostgles_subscribe_view_definition LIMIT 0`, {});
|
|
68
68
|
const tableColumns = fields.filter(f => f.tableName && f.columnName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkC,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAiB,WAAW,
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkC,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,MAAM,EAAiB,WAAW,EAA2C,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,SAAS,EAAe,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,wBAAsB,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CA+JzL"}
|
package/lib/DboBuilder/update.js
CHANGED
|
@@ -108,10 +108,10 @@ async function update(filter, _newData, params, tableRules, localParams) {
|
|
|
108
108
|
return query;
|
|
109
109
|
let result;
|
|
110
110
|
if (this.t) {
|
|
111
|
-
result = await (this.t)[qType](query).catch((err) => (0, DboBuilder_1.
|
|
111
|
+
result = await (this.t)[qType](query).catch((err) => (0, DboBuilder_1.makeErrorFromPGError)(err, localParams, this, fields));
|
|
112
112
|
}
|
|
113
113
|
else {
|
|
114
|
-
result = await this.db.tx(t => t[qType](query)).catch(err => (0, DboBuilder_1.
|
|
114
|
+
result = await this.db.tx(t => t[qType](query)).catch(err => (0, DboBuilder_1.makeErrorFromPGError)(err, localParams, this, fields));
|
|
115
115
|
}
|
|
116
116
|
/** TODO: Delete old file at the end in case new file update fails */
|
|
117
117
|
// await oldFileDelete();
|
package/lib/DboBuilder/update.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyObject, getKeys, isObject, unpatchText, UpdateParams } from "prostgles-types";
|
|
2
|
-
import { Filter, isPlainObject, LocalParams,
|
|
2
|
+
import { Filter, isPlainObject, LocalParams, makeErrorFromPGError, Media, parseError } from "../DboBuilder";
|
|
3
3
|
import { TableRule, ValidateRow } from "../PublishParser";
|
|
4
4
|
import { omitKeys, pickKeys } from "../PubSubManager/PubSubManager";
|
|
5
5
|
import { TableHandler } from "./TableHandler";
|
|
@@ -129,9 +129,9 @@ export async function update(this: TableHandler, filter: Filter, _newData: AnyOb
|
|
|
129
129
|
|
|
130
130
|
let result;
|
|
131
131
|
if (this.t) {
|
|
132
|
-
result = await (this.t)[qType](query).catch((err: any) =>
|
|
132
|
+
result = await (this.t)[qType](query).catch((err: any) => makeErrorFromPGError(err, localParams, this, fields));
|
|
133
133
|
} else {
|
|
134
|
-
result = await this.db.tx(t => (t as any)[qType](query)).catch(err =>
|
|
134
|
+
result = await this.db.tx(t => (t as any)[qType](query)).catch(err => makeErrorFromPGError(err, localParams, this, fields));
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/** TODO: Delete old file at the end in case new file update fails */
|
package/lib/DboBuilder.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as pgPromise from 'pg-promise';
|
|
2
2
|
import pg = require('pg-promise/typescript/pg-subset');
|
|
3
|
-
import { ColumnInfo, SQLOptions, DbJoinMaker, PG_COLUMN_UDT_DATA_TYPE, TS_PG_Types, TableInfo as TInfo, SQLHandler, AnyObject, ProstglesError } from "prostgles-types";
|
|
3
|
+
import { ColumnInfo, SQLOptions, DbJoinMaker, PG_COLUMN_UDT_DATA_TYPE, TS_PG_Types, TableInfo as TInfo, SQLHandler, AnyObject, ProstglesError, EXISTS_KEY } from "prostgles-types";
|
|
4
4
|
export declare type SortItem = {
|
|
5
5
|
asc: boolean;
|
|
6
6
|
nulls?: "first" | "last";
|
|
@@ -181,9 +181,7 @@ export declare type ValidatedTableRules = CommonTableRules & {
|
|
|
181
181
|
returningFields: string[];
|
|
182
182
|
};
|
|
183
183
|
};
|
|
184
|
-
export declare function
|
|
185
|
-
export declare const EXISTS_KEYS: readonly ["$exists", "$notExists", "$existsJoined", "$notExistsJoined"];
|
|
186
|
-
export declare type EXISTS_KEY = typeof EXISTS_KEYS[number];
|
|
184
|
+
export declare function makeErrorFromPGError(err: any, localParams?: LocalParams, view?: ViewHandler, allowedKeys?: string[]): Promise<never>;
|
|
187
185
|
/**
|
|
188
186
|
* Ensure the error is an Object and has
|
|
189
187
|
*/
|