prostgles-server 2.0.112 → 2.0.116
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.d.ts +9 -2
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +33 -2
- package/dist/DboBuilder.js.map +1 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +26 -4
- package/dist/Prostgles.js.map +1 -1
- package/dist/QueryBuilder.d.ts.map +1 -1
- package/dist/QueryBuilder.js +34 -12
- package/dist/QueryBuilder.js.map +1 -1
- package/lib/DboBuilder.ts +39 -3
- package/lib/Prostgles.ts +36 -8
- package/lib/QueryBuilder.ts +33 -12
- package/package.json +1 -1
- package/tests/client/PID.txt +1 -1
- package/tests/server/media/{11d31201-0142-4552-9408-86abce10a8da.txt → 3fb7451c-8bc4-4a7c-a9cb-917462fe7714.txt} +0 -0
- package/tests/server/media/{672f49c1-2d40-4d93-9e5d-be97324c297f.txt → 4f1a2e77-7ba7-44b0-b164-5813317b5b9f.txt} +0 -0
- package/tests/server/media/{ba1d9f4e-8a32-47ee-852d-8cebe73ddae6.txt → 746bdbf0-66ae-453b-9886-73737ac07d44.txt} +0 -0
- package/tests/server/media/{dd770fa3-a11c-46fd-ac10-c2c3ddefc013.txt → e27d7fa8-a585-49f3-9d70-346e684a8d1b.txt} +0 -0
- package/tests/server/package-lock.json +1 -1
package/lib/DboBuilder.ts
CHANGED
|
@@ -447,7 +447,7 @@ export class ViewHandler {
|
|
|
447
447
|
columns: TableSchema["columns"];
|
|
448
448
|
columnsForTypes: ColumnInfo[];
|
|
449
449
|
column_names: string[];
|
|
450
|
-
tableOrViewInfo: TableOrViewInfo;
|
|
450
|
+
tableOrViewInfo: TableSchema;// TableOrViewInfo;
|
|
451
451
|
colSet: ColSet;
|
|
452
452
|
tsColumnDefs: string[] = [];
|
|
453
453
|
joins: Join[];
|
|
@@ -3151,6 +3151,12 @@ export type TableSchema = {
|
|
|
3151
3151
|
})[];
|
|
3152
3152
|
is_view: boolean;
|
|
3153
3153
|
parent_tables: string[];
|
|
3154
|
+
privileges: {
|
|
3155
|
+
insert: boolean;
|
|
3156
|
+
select: boolean;
|
|
3157
|
+
update: boolean;
|
|
3158
|
+
delete: boolean;
|
|
3159
|
+
}
|
|
3154
3160
|
}
|
|
3155
3161
|
|
|
3156
3162
|
type PGConstraint = {
|
|
@@ -3185,7 +3191,37 @@ async function getConstraints(db: DB, schema: string = "public"): Promise<PGCons
|
|
|
3185
3191
|
async function getTablesForSchemaPostgresSQL(db: DB, schema: string = "public"): Promise<TableSchema[]>{
|
|
3186
3192
|
const query =
|
|
3187
3193
|
`
|
|
3188
|
-
SELECT
|
|
3194
|
+
SELECT jsonb_build_object(
|
|
3195
|
+
'insert', EXISTS (
|
|
3196
|
+
SELECT 1
|
|
3197
|
+
FROM information_schema.role_table_grants rg
|
|
3198
|
+
WHERE rg.table_name = t.table_name
|
|
3199
|
+
AND rg.privilege_type = 'INSERT'
|
|
3200
|
+
AND rg.is_grantable = 'YES'
|
|
3201
|
+
),
|
|
3202
|
+
'select', EXISTS (
|
|
3203
|
+
SELECT 1
|
|
3204
|
+
FROM information_schema.role_table_grants rg
|
|
3205
|
+
WHERE rg.table_name = t.table_name
|
|
3206
|
+
AND rg.privilege_type = 'SELECT'
|
|
3207
|
+
AND rg.is_grantable = 'YES'
|
|
3208
|
+
),
|
|
3209
|
+
'update', EXISTS (
|
|
3210
|
+
SELECT 1
|
|
3211
|
+
FROM information_schema.role_table_grants rg
|
|
3212
|
+
WHERE rg.table_name = t.table_name
|
|
3213
|
+
AND rg.privilege_type = 'UPDATE'
|
|
3214
|
+
AND rg.is_grantable = 'YES'
|
|
3215
|
+
),
|
|
3216
|
+
'delete', EXISTS (
|
|
3217
|
+
SELECT 1
|
|
3218
|
+
FROM information_schema.role_table_grants rg
|
|
3219
|
+
WHERE rg.table_name = t.table_name
|
|
3220
|
+
AND rg.privilege_type = 'DELETE'
|
|
3221
|
+
AND rg.is_grantable = 'YES'
|
|
3222
|
+
)
|
|
3223
|
+
) as privileges
|
|
3224
|
+
, t.table_schema as schema, t.table_name as name
|
|
3189
3225
|
, cc.table_oid as oid
|
|
3190
3226
|
, json_agg((SELECT x FROM (
|
|
3191
3227
|
SELECT cc.column_name as name,
|
|
@@ -3322,7 +3358,7 @@ export function isPlainObject(o) {
|
|
|
3322
3358
|
return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
|
|
3323
3359
|
}
|
|
3324
3360
|
|
|
3325
|
-
function postgresToTsType(udt_data_type: PG_COLUMN_UDT_DATA_TYPE): keyof typeof TS_PG_Types {
|
|
3361
|
+
export function postgresToTsType(udt_data_type: PG_COLUMN_UDT_DATA_TYPE): keyof typeof TS_PG_Types {
|
|
3326
3362
|
return Object.keys(TS_PG_Types).find(k => {
|
|
3327
3363
|
return TS_PG_Types[k].includes(udt_data_type) || !TS_PG_Types[k].length;
|
|
3328
3364
|
}) as keyof typeof TS_PG_Types;
|
package/lib/Prostgles.ts
CHANGED
|
@@ -1093,20 +1093,25 @@ type DboTableCommand = Request & DboTable & {
|
|
|
1093
1093
|
const RULE_TO_METHODS = [
|
|
1094
1094
|
{
|
|
1095
1095
|
rule: "getColumns",
|
|
1096
|
+
sqlRule: "select",
|
|
1096
1097
|
methods: ["getColumns"],
|
|
1097
1098
|
no_limits: true,
|
|
1098
1099
|
allowed_params: [],
|
|
1100
|
+
table_only: false,
|
|
1099
1101
|
hint: ` expecting false | true | undefined`
|
|
1100
1102
|
},
|
|
1101
1103
|
{
|
|
1102
1104
|
rule: "getInfo",
|
|
1105
|
+
sqlRule: "select",
|
|
1103
1106
|
methods: ["getInfo"],
|
|
1104
1107
|
no_limits: true,
|
|
1105
1108
|
allowed_params: [],
|
|
1109
|
+
table_only: false,
|
|
1106
1110
|
hint: ` expecting false | true | undefined`
|
|
1107
1111
|
},
|
|
1108
1112
|
{
|
|
1109
1113
|
rule: "insert",
|
|
1114
|
+
sqlRule: "insert",
|
|
1110
1115
|
methods: ["insert", "upsert"],
|
|
1111
1116
|
no_limits: <SelectRule>{ fields: "*" },
|
|
1112
1117
|
table_only: true,
|
|
@@ -1115,6 +1120,7 @@ const RULE_TO_METHODS = [
|
|
|
1115
1120
|
},
|
|
1116
1121
|
{
|
|
1117
1122
|
rule: "update",
|
|
1123
|
+
sqlRule: "update",
|
|
1118
1124
|
methods: ["update", "upsert", "updateBatch"],
|
|
1119
1125
|
no_limits: <UpdateRule>{ fields: "*", filterFields: "*", returningFields: "*" },
|
|
1120
1126
|
table_only: true,
|
|
@@ -1123,13 +1129,16 @@ const RULE_TO_METHODS = [
|
|
|
1123
1129
|
},
|
|
1124
1130
|
{
|
|
1125
1131
|
rule: "select",
|
|
1132
|
+
sqlRule: "select",
|
|
1126
1133
|
methods: ["findOne", "find", "count"],
|
|
1127
1134
|
no_limits: <SelectRule>{ fields: "*", filterFields: "*" },
|
|
1135
|
+
table_only: false,
|
|
1128
1136
|
allowed_params: <Array<keyof SelectRule>>["fields", "filterFields", "forcedFilter", "validate", "maxLimit"] ,
|
|
1129
1137
|
hint: ` expecting "*" | true | { fields: ( string | string[] | {} ) }`
|
|
1130
1138
|
},
|
|
1131
1139
|
{
|
|
1132
1140
|
rule: "delete",
|
|
1141
|
+
sqlRule: "delete",
|
|
1133
1142
|
methods: ["delete", "remove"],
|
|
1134
1143
|
no_limits: <DeleteRule>{ filterFields: "*" } ,
|
|
1135
1144
|
table_only: true,
|
|
@@ -1137,20 +1146,24 @@ const RULE_TO_METHODS = [
|
|
|
1137
1146
|
hint: ` expecting "*" | true | { filterFields: ( string | string[] | {} ) } \n Will use "select", "update", "delete" and "insert" rules`
|
|
1138
1147
|
},
|
|
1139
1148
|
{
|
|
1140
|
-
rule: "sync",
|
|
1149
|
+
rule: "sync",
|
|
1150
|
+
sqlRule: "select",
|
|
1151
|
+
methods: ["sync", "unsync"],
|
|
1141
1152
|
no_limits: null,
|
|
1142
1153
|
table_only: true,
|
|
1143
1154
|
allowed_params: <Array<keyof SyncRule>>["id_fields", "synced_field", "sync_type", "allow_delete", "throttle", "batch_size"],
|
|
1144
1155
|
hint: ` expecting "*" | true | { id_fields: string[], synced_field: string }`
|
|
1145
1156
|
},
|
|
1146
1157
|
{
|
|
1147
|
-
rule: "subscribe",
|
|
1158
|
+
rule: "subscribe",
|
|
1159
|
+
sqlRule: "select",
|
|
1160
|
+
methods: ["unsubscribe", "subscribe", "subscribeOne"],
|
|
1148
1161
|
no_limits: <SubscribeRule>{ throttle: 0 },
|
|
1149
1162
|
table_only: true,
|
|
1150
1163
|
allowed_params: <Array<keyof SubscribeRule>>["throttle"],
|
|
1151
1164
|
hint: ` expecting "*" | true | { throttle: number } \n Will use "select" rules`
|
|
1152
1165
|
}
|
|
1153
|
-
];
|
|
1166
|
+
] as const;
|
|
1154
1167
|
// const ALL_PUBLISH_METHODS = ["update", "upsert", "delete", "insert", "find", "findOne", "subscribe", "unsubscribe", "sync", "unsync", "remove"];
|
|
1155
1168
|
// const ALL_PUBLISH_METHODS = RULE_TO_METHODS.map(r => r.methods).flat();
|
|
1156
1169
|
|
|
@@ -1239,7 +1252,7 @@ export class PublishParser {
|
|
|
1239
1252
|
|
|
1240
1253
|
if(!command || !tableName) throw "command OR tableName are missing";
|
|
1241
1254
|
|
|
1242
|
-
let rtm = RULE_TO_METHODS.find(rtms => rtms.methods.includes(command));
|
|
1255
|
+
let rtm = RULE_TO_METHODS.find(rtms => (rtms.methods as any).includes(command));
|
|
1243
1256
|
if(!rtm){
|
|
1244
1257
|
throw "Invalid command: " + command;
|
|
1245
1258
|
}
|
|
@@ -1285,7 +1298,9 @@ export class PublishParser {
|
|
|
1285
1298
|
let table_rules = _publish[tableName];// applyParamsIfFunc(_publish[tableName], localParams, this.dbo, this.db, user);
|
|
1286
1299
|
|
|
1287
1300
|
/* Get view or table specific rules */
|
|
1288
|
-
const
|
|
1301
|
+
const tHandler = (this.dbo[tableName] as TableHandler | ViewHandler);
|
|
1302
|
+
|
|
1303
|
+
const is_view = tHandler.is_view,
|
|
1289
1304
|
MY_RULES = RULE_TO_METHODS.filter(r => !is_view || !r.table_only);
|
|
1290
1305
|
|
|
1291
1306
|
// if(tableName === "various") console.warn(1033, MY_RULES)
|
|
@@ -1295,7 +1310,14 @@ export class PublishParser {
|
|
|
1295
1310
|
if([true, "*"].includes(table_rules as any)){
|
|
1296
1311
|
table_rules = {};
|
|
1297
1312
|
MY_RULES.map(r => {
|
|
1298
|
-
|
|
1313
|
+
/** Check PG User privileges */
|
|
1314
|
+
if(
|
|
1315
|
+
tHandler.tableOrViewInfo.privileges[r.sqlRule]
|
|
1316
|
+
){
|
|
1317
|
+
table_rules[r.rule] = { ...r.no_limits };
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
|
|
1299
1321
|
});
|
|
1300
1322
|
// if(tableName === "various") console.warn(1042, table_rules)
|
|
1301
1323
|
}
|
|
@@ -1315,7 +1337,7 @@ export class PublishParser {
|
|
|
1315
1337
|
|
|
1316
1338
|
if(table_rules[r.rule]){
|
|
1317
1339
|
/* Add implied methods if not falsy */
|
|
1318
|
-
r.methods.map(method => {
|
|
1340
|
+
(r.methods as any).map(method => {
|
|
1319
1341
|
if(table_rules[method] === undefined){
|
|
1320
1342
|
const publishedTable = (table_rules as PublishTable);
|
|
1321
1343
|
if(method === "updateBatch" && !publishedTable.update){
|
|
@@ -1340,11 +1362,17 @@ export class PublishParser {
|
|
|
1340
1362
|
|
|
1341
1363
|
ruleKeys.filter(m => table_rules[m])
|
|
1342
1364
|
.find(method => {
|
|
1343
|
-
let rm = MY_RULES.find(r => r.rule === method || r.methods.includes(method));
|
|
1365
|
+
let rm = MY_RULES.find(r => r.rule === method || (r.methods as any).includes(method));
|
|
1344
1366
|
if(!rm){
|
|
1345
1367
|
throw `Invalid rule in publish.${tableName} -> ${method} \nExpecting any of: ${flat(MY_RULES.map(r => [r.rule, ...r.methods])).join(", ")}`;
|
|
1346
1368
|
}
|
|
1347
1369
|
|
|
1370
|
+
/** Check user privileges */
|
|
1371
|
+
if(!tHandler.tableOrViewInfo.privileges[rm.sqlRule]){
|
|
1372
|
+
delete table_rules[method];
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1348
1376
|
/* Check RULES for invalid params */
|
|
1349
1377
|
/* Methods do not have params -> They use them from rules */
|
|
1350
1378
|
if(method === rm.rule){
|
package/lib/QueryBuilder.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
5
5
|
*--------------------------------------------------------------------------------------------*/
|
|
6
6
|
|
|
7
|
-
import { pgp, Filter, LocalParams, isPlainObject, TableHandler, ViewHandler } from "./DboBuilder";
|
|
7
|
+
import { pgp, Filter, LocalParams, isPlainObject, TableHandler, ViewHandler, postgresToTsType } from "./DboBuilder";
|
|
8
8
|
import { TableRule, flat } from "./Prostgles";
|
|
9
9
|
import { SelectParamsBasic as SelectParams, isEmpty, FieldFilter, asName, TextFilter_FullTextSearchFilterKeys, TS_PG_Types, ColumnInfo } from "prostgles-types";
|
|
10
10
|
import { get } from "./utils";
|
|
@@ -694,28 +694,49 @@ export const FUNCTIONS: FunctionSpec[] = [
|
|
|
694
694
|
if(returnType === "index"){
|
|
695
695
|
res = `CASE WHEN position(${term} IN ${col}) > 0 THEN position(${term} IN ${col}) - 1 ELSE -1 END`;
|
|
696
696
|
|
|
697
|
-
} else if(returnType === "boolean"){
|
|
698
|
-
|
|
697
|
+
// } else if(returnType === "boolean"){
|
|
698
|
+
// res = `CASE WHEN position(${term} IN ${col}) > 0 THEN TRUE ELSE FALSE END`;
|
|
699
699
|
|
|
700
|
-
} else if(returnType === "object"){
|
|
700
|
+
} else if(returnType === "object" || returnType === "boolean"){
|
|
701
|
+
const hasChars = Boolean(term && /[a-z]/i.test(term));
|
|
701
702
|
res = `CASE
|
|
702
703
|
${cols.map(c => {
|
|
703
704
|
const colInfo = allColumns.find(ac => ac.name === c);
|
|
704
|
-
|
|
705
|
+
return {
|
|
706
|
+
key: c,
|
|
707
|
+
colInfo
|
|
708
|
+
}
|
|
709
|
+
}).filter(c =>
|
|
710
|
+
/** Exclude numeric columns when the search tern contains a character */
|
|
711
|
+
!hasChars ||
|
|
712
|
+
c.colInfo?.udt_name &&
|
|
713
|
+
postgresToTsType(c.colInfo.udt_name) !== "number"
|
|
714
|
+
)
|
|
715
|
+
.map(c => {
|
|
716
|
+
const colNameEscaped = asNameAlias(c.key, tableAlias)
|
|
705
717
|
let colSelect = `${colNameEscaped}::TEXT`;
|
|
706
|
-
|
|
707
|
-
|
|
718
|
+
const isTstamp = c.colInfo?.udt_name.startsWith("timestamp");
|
|
719
|
+
if(isTstamp || c.colInfo?.udt_name === "date"){
|
|
720
|
+
colSelect = `( CASE WHEN ${colNameEscaped} IS NULL THEN ''
|
|
721
|
+
ELSE concat_ws(' ',
|
|
708
722
|
${colNameEscaped}::TEXT,
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
'
|
|
723
|
+
${isTstamp? `'TZ' || trim(to_char(${colNameEscaped}, 'OF')), `: ''}
|
|
724
|
+
trim(to_char(${colNameEscaped}, 'Day Month')),
|
|
725
|
+
'Q' || trim(to_char(${colNameEscaped}, 'Q')),
|
|
726
|
+
'WK' || trim(to_char(${colNameEscaped}, 'WW'))
|
|
712
727
|
) END)`
|
|
713
728
|
}
|
|
714
729
|
let colTxt = `COALESCE(${colSelect}, '')`; // position(${term} IN ${colTxt}) > 0
|
|
730
|
+
if(returnType === "boolean"){
|
|
731
|
+
return `
|
|
732
|
+
WHEN ${colTxt} ${matchCase? "LIKE" : "ILIKE"} ${asValue('%' + rawTerm + '%')}
|
|
733
|
+
THEN TRUE
|
|
734
|
+
`
|
|
735
|
+
}
|
|
715
736
|
return `
|
|
716
737
|
WHEN ${colTxt} ${matchCase? "LIKE" : "ILIKE"} ${asValue('%' + rawTerm + '%')}
|
|
717
738
|
THEN json_build_object(
|
|
718
|
-
${asValue(c)},
|
|
739
|
+
${asValue(c.key)},
|
|
719
740
|
${makeTextMatcherArray(
|
|
720
741
|
colTxt,
|
|
721
742
|
term
|
|
@@ -723,7 +744,7 @@ export const FUNCTIONS: FunctionSpec[] = [
|
|
|
723
744
|
)::jsonb
|
|
724
745
|
`
|
|
725
746
|
}).join(" ")}
|
|
726
|
-
ELSE NULL
|
|
747
|
+
ELSE ${(returnType === "boolean")? "FALSE" : "NULL"}
|
|
727
748
|
|
|
728
749
|
END`;
|
|
729
750
|
|
package/package.json
CHANGED
package/tests/client/PID.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
18519
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|