prostgles-server 2.0.146 → 2.0.149

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.
Files changed (76) hide show
  1. package/dist/AuthHandler.d.ts +15 -13
  2. package/dist/AuthHandler.d.ts.map +1 -1
  3. package/dist/AuthHandler.js +43 -44
  4. package/dist/AuthHandler.js.map +1 -1
  5. package/dist/DBEventsManager.d.ts +6 -5
  6. package/dist/DBEventsManager.d.ts.map +1 -1
  7. package/dist/DBEventsManager.js +8 -2
  8. package/dist/DBEventsManager.js.map +1 -1
  9. package/dist/DboBuilder.d.ts +54 -50
  10. package/dist/DboBuilder.d.ts.map +1 -1
  11. package/dist/DboBuilder.js +242 -206
  12. package/dist/DboBuilder.js.map +1 -1
  13. package/dist/FileManager.d.ts +5 -5
  14. package/dist/FileManager.d.ts.map +1 -1
  15. package/dist/FileManager.js +59 -31
  16. package/dist/FileManager.js.map +1 -1
  17. package/dist/Filtering.d.ts.map +1 -1
  18. package/dist/Filtering.js +17 -14
  19. package/dist/Filtering.js.map +1 -1
  20. package/dist/PostgresNotifListenManager.d.ts +3 -3
  21. package/dist/PostgresNotifListenManager.d.ts.map +1 -1
  22. package/dist/PostgresNotifListenManager.js +7 -5
  23. package/dist/PostgresNotifListenManager.js.map +1 -1
  24. package/dist/Prostgles.d.ts +6 -9
  25. package/dist/Prostgles.d.ts.map +1 -1
  26. package/dist/Prostgles.js +125 -86
  27. package/dist/Prostgles.js.map +1 -1
  28. package/dist/PubSubManager.d.ts +8 -8
  29. package/dist/PubSubManager.d.ts.map +1 -1
  30. package/dist/PubSubManager.js +58 -52
  31. package/dist/PubSubManager.js.map +1 -1
  32. package/dist/QueryBuilder.d.ts +6 -5
  33. package/dist/QueryBuilder.d.ts.map +1 -1
  34. package/dist/QueryBuilder.js +124 -89
  35. package/dist/QueryBuilder.js.map +1 -1
  36. package/dist/SyncReplication.js +38 -35
  37. package/dist/SyncReplication.js.map +1 -1
  38. package/dist/TableConfig.d.ts +0 -1
  39. package/dist/TableConfig.d.ts.map +1 -1
  40. package/dist/TableConfig.js +36 -28
  41. package/dist/TableConfig.js.map +1 -1
  42. package/dist/shortestPath.d.ts.map +1 -1
  43. package/dist/shortestPath.js +2 -1
  44. package/dist/shortestPath.js.map +1 -1
  45. package/dist/utils.d.ts +2 -1
  46. package/dist/utils.d.ts.map +1 -1
  47. package/dist/utils.js +3 -1
  48. package/dist/utils.js.map +1 -1
  49. package/lib/AuthHandler.ts +50 -40
  50. package/lib/DBEventsManager.ts +14 -7
  51. package/lib/DboBuilder.ts +231 -195
  52. package/lib/FileManager.ts +30 -21
  53. package/lib/Filtering.ts +19 -16
  54. package/lib/PostgresNotifListenManager.ts +11 -10
  55. package/lib/Prostgles.ts +89 -73
  56. package/lib/PubSubManager.ts +13 -11
  57. package/lib/QueryBuilder.ts +53 -29
  58. package/lib/SyncReplication.ts +10 -10
  59. package/lib/TableConfig.ts +23 -15
  60. package/lib/shortestPath.ts +6 -4
  61. package/lib/utils.ts +3 -2
  62. package/package.json +4 -3
  63. package/tests/client/PID.txt +1 -1
  64. package/tests/client/index.js +10 -7
  65. package/tests/client/index.ts +12 -8
  66. package/tests/client/package-lock.json +14 -14
  67. package/tests/client/package.json +2 -2
  68. package/tests/client/tsconfig.json +2 -2
  69. package/tests/client_only_queries.js +127 -104
  70. package/tests/client_only_queries.ts +43 -17
  71. package/tests/isomorphic_queries.js +22 -6
  72. package/tests/isomorphic_queries.ts +18 -6
  73. package/tests/server/package-lock.json +21 -19
  74. package/tests/server/package.json +2 -2
  75. package/tests/server/tsconfig.json +2 -2
  76. 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, OrderBy, InsertParams, UpdateParams, DeleteParams, SQLOptions,
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, isObject } from "./utils";
76
+ import { get, isDefined, isObject } from "./utils";
73
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, flat, ValidateRow
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: ValidateRow): Promise<{ escapedCol: string; escapedVal: string }[]> {
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: object, rule: "update" | "select" | "insert" | "delete"){
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 = null, tableRules?: TableRule, localParams?: LocalParams): Promise<any[]>{
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: object,
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?, table_rules?: TableRule, localParams?: LocalParams): Promise<any>{
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 = null, offset = 0 } = selectParams || {};
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" }, null, table_rules, localParams);
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?, param3_unused?, table_rules?: TableRule, localParams: any = {}): Promise<number>{
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 }, null, table_rules, localParams)
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?, table_rules?: TableRule, localParams: any = {}): Promise<string>{
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 }, null, table_rules, localParams)
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
- null,
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: Filter;
1138
+ filter?: Filter;
1125
1139
  select?: SelectItem[];
1126
- forcedFilter: object;
1127
- filterFields: FieldFilter;
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 = null, localParams, tableRule } = params;
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 = Object.keys(f);
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 = { ... 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, tableRules: TableRule): Promise<string> {
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 */
@@ -1378,7 +1392,7 @@ 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, localParams, tableRules)))).join(" AND ");
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 */
@@ -1444,7 +1458,7 @@ export class ViewHandler {
1444
1458
  const complexFilterKey = "$filter";
1445
1459
  const allowedComparators = [">", "<", "=", "<=", ">=", "<>", "!="]
1446
1460
  if(complexFilterKey in data){
1447
- const getFuncQuery = (funcData): string => {
1461
+ const getFuncQuery = (funcData: any): string => {
1448
1462
  const { funcName, args } = parseFunctionObject(funcData);
1449
1463
  const funcDef = parseFunction({ func: funcName, args, functions: FUNCTIONS, allowedFields: allowed_colnames });
1450
1464
  return funcDef.getQuery({ args, tableAlias, allColumns: this.columns, allowedFields: allowed_colnames });
@@ -1467,6 +1481,12 @@ export class ViewHandler {
1467
1481
  complexFilters.push(result);
1468
1482
  }
1469
1483
 
1484
+
1485
+ /* Parse join filters
1486
+ { $joinFilter: { $ST_DWithin: [table.col, foreignTable.col, distance] }
1487
+ will make an exists filter
1488
+ */
1489
+
1470
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));
1471
1491
  // if(allowed_colnames){
1472
1492
  // const aliasedColumns = (select || []).filter(s =>
@@ -1523,7 +1543,7 @@ export class ViewHandler {
1523
1543
  }
1524
1544
 
1525
1545
  /* This relates only to SELECT */
1526
- 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 {
1527
1547
  let column_names = this.column_names.slice(0);
1528
1548
 
1529
1549
  const throwErr = () => {
@@ -1534,7 +1554,7 @@ export class ViewHandler {
1534
1554
  [{ key1: true }, { key2: false }] \
1535
1555
  [{ key: 'colName', asc: true, nulls: 'first', nullEmpty: true }]"
1536
1556
  },
1537
- 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 }[] => {
1538
1558
  if(!isPlainObject(orderBy)) return throwErr();
1539
1559
 
1540
1560
  const keys = Object.keys(orderBy);
@@ -1572,7 +1592,7 @@ export class ViewHandler {
1572
1592
 
1573
1593
  if(!orderBy) return "";
1574
1594
 
1575
- let allowedFields = [];
1595
+ let allowedFields: string[] = [];
1576
1596
  if(allowed_cols){
1577
1597
  allowedFields = this.parseFieldFilter(allowed_cols);
1578
1598
  }
@@ -1624,7 +1644,7 @@ export class ViewHandler {
1624
1644
  const orderType = asc? " ASC " : " DESC ";
1625
1645
  const index = selectedAliases.indexOf(key) + 1;
1626
1646
  const nullOrder = nulls? ` NULLS ${nulls === "first"? " FIRST " : " LAST "}` : "";
1627
- let colKey = (index > 0 && !nullEmpty)? index : [tableAlias, key].filter(v => v).map(asName).join(".");
1647
+ let colKey = (index > 0 && !nullEmpty)? index : [tableAlias, key].filter(isDefined).map(asName).join(".");
1628
1648
  if(nullEmpty){
1629
1649
  colKey = `nullif(trim(${colKey}::text), '')`
1630
1650
  }
@@ -1657,7 +1677,7 @@ export class ViewHandler {
1657
1677
  } else {
1658
1678
 
1659
1679
  /* If a limit higher than maxLimit specified throw error */
1660
- if(Number.isInteger(p.select.maxLimit) && _limit > p.select.maxLimit){
1680
+ if(Number.isInteger(p.select.maxLimit) && _limit > p.select.maxLimit!){
1661
1681
  throw `Unexpected LIMIT ${_limit}. Must be less than the published maxLimit: ` + p.select.maxLimit;
1662
1682
  }
1663
1683
  }
@@ -1667,9 +1687,9 @@ export class ViewHandler {
1667
1687
  }
1668
1688
 
1669
1689
  /* This relates only to SELECT */
1670
- prepareOffsetQuery(offset: number): number{
1690
+ prepareOffsetQuery(offset?: number): number{
1671
1691
  if(Number.isInteger(offset)){
1672
- return offset;
1692
+ return offset!;
1673
1693
  }
1674
1694
 
1675
1695
  return 0;
@@ -1677,7 +1697,7 @@ export class ViewHandler {
1677
1697
 
1678
1698
 
1679
1699
  intersectColumns(allowedFields: FieldFilter, dissallowedFields: FieldFilter, fixIssues: boolean = false): string[] {
1680
- let result = [];
1700
+ let result: string[] = [];
1681
1701
  if(allowedFields){
1682
1702
  result = this.parseFieldFilter(allowedFields);
1683
1703
  }
@@ -1703,7 +1723,7 @@ export class ViewHandler {
1703
1723
  * @param {Object} forcedData - set/override property
1704
1724
  * @param {string[]} allowed_cols - allowed columns (excluding forcedData) from table rules
1705
1725
  */
1706
- prepareFieldValues(obj: object = {}, forcedData: object = {}, allowed_cols: FieldFilter, fixIssues = false): object {
1726
+ prepareFieldValues(obj: Record<string, any> = {}, forcedData: object = {}, allowed_cols: FieldFilter | undefined, fixIssues = false): AnyObject {
1707
1727
  let column_names = this.column_names.slice(0);
1708
1728
  if(!column_names || !column_names.length) throw "table column_names mising";
1709
1729
  let _allowed_cols = column_names.slice(0);
@@ -1713,7 +1733,7 @@ export class ViewHandler {
1713
1733
  _allowed_cols = this.parseFieldFilter(allowed_cols, false);
1714
1734
  }
1715
1735
  let final_filter = { ..._obj },
1716
- filter_keys = Object.keys(final_filter);
1736
+ filter_keys: Array<keyof typeof final_filter> = Object.keys(final_filter);
1717
1737
 
1718
1738
  if(fixIssues && filter_keys.length){
1719
1739
  final_filter = {};
@@ -1750,7 +1770,7 @@ export class ViewHandler {
1750
1770
  static _parseFieldFilter(fieldParams: FieldFilter = "*", allow_empty: boolean = true, all_cols: string[]): string[] {
1751
1771
  if(!all_cols) throw "all_cols missing"
1752
1772
  const all_fields = all_cols;// || this.column_names.slice(0);
1753
- let colNames = null,
1773
+ let colNames: string[] = [],
1754
1774
  initialParams = JSON.stringify(fieldParams);
1755
1775
 
1756
1776
  if(fieldParams){
@@ -1793,7 +1813,9 @@ export class ViewHandler {
1793
1813
  } else if(isPlainObject(fieldParams)){
1794
1814
 
1795
1815
  if(Object.keys(fieldParams).length){
1796
- let keys = Object.keys(fieldParams);
1816
+ let keys = Object.keys(fieldParams as {
1817
+ [key: string]: boolean | 0 | 1;
1818
+ });
1797
1819
  if(keys[0] === ""){
1798
1820
  if(allow_empty){
1799
1821
  return [""];
@@ -1806,11 +1828,11 @@ export class ViewHandler {
1806
1828
 
1807
1829
  keys.forEach(key => {
1808
1830
  const allowedVals = [true, false, 0, 1];
1809
- 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 ")}`
1810
1832
  })
1811
1833
 
1812
- let allowed = keys.filter(key => fieldParams[key]),
1813
- 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]);
1814
1836
 
1815
1837
 
1816
1838
  if(disallowed && disallowed.length){
@@ -1838,7 +1860,7 @@ export class ViewHandler {
1838
1860
  }
1839
1861
  }
1840
1862
 
1841
- function isPojoObject(obj): boolean {
1863
+ function isPojoObject<T>(obj: T): obj is Record<string, any> {
1842
1864
  if(obj && (typeof obj !== "object" || Array.isArray(obj) || obj instanceof Date)){
1843
1865
  return false;
1844
1866
  }
@@ -1847,10 +1869,10 @@ function isPojoObject(obj): boolean {
1847
1869
 
1848
1870
 
1849
1871
  type ValidatedParams = {
1850
- row: object;
1851
- forcedData: object;
1852
- allowedFields: FieldFilter;
1853
- tableRules: TableRule;
1872
+ row: AnyObject;
1873
+ forcedData?: AnyObject;
1874
+ allowedFields?: FieldFilter;
1875
+ tableRules?: TableRule;
1854
1876
  fixIssues: boolean;
1855
1877
  }
1856
1878
 
@@ -1859,7 +1881,7 @@ export class TableHandler extends ViewHandler {
1859
1881
  throttle_queries_per_sec: number;
1860
1882
  since: number,
1861
1883
  queries: number,
1862
- batching: string[]
1884
+ batching: string[] | null
1863
1885
  }
1864
1886
 
1865
1887
  constructor(db: DB, tableOrViewInfo: TableSchema, dboBuilder: DboBuilder, t?: pgPromise.ITask<{}>, dbTX?: TxHandler, joinPaths?: JoinPaths){
@@ -1894,8 +1916,8 @@ export class TableHandler extends ViewHandler {
1894
1916
  }
1895
1917
 
1896
1918
  async subscribe(filter: Filter, params: SubscribeParams, localFunc: (items: AnyObject[]) => any): Promise<{ unsubscribe: () => any }>
1897
- async subscribe(filter: Filter, params: SubscribeParams, localFunc: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams): Promise<string>
1898
- async subscribe(filter: Filter, params: SubscribeParams = {}, localFunc: (items: AnyObject[]) => any, table_rules?: TableRule, localParams?: LocalParams):
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):
1899
1921
  Promise<string | { unsubscribe: () => any }>
1900
1922
  {
1901
1923
  try {
@@ -1908,7 +1930,7 @@ export class TableHandler extends ViewHandler {
1908
1930
  }
1909
1931
 
1910
1932
  const { filterFields, forcedFilter } = get(table_rules, "select") || {},
1911
- condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: null, localParams, tableRule: table_rules }),
1933
+ condition = await this.prepareWhere({ filter, forcedFilter, addKeywords: false, filterFields, tableAlias: undefined, localParams, tableRule: table_rules }),
1912
1934
  throttle = get(params, "throttle") || 0,
1913
1935
  selectParams = filterObj(params || {}, [], ["throttle"]);
1914
1936
 
@@ -1920,21 +1942,20 @@ export class TableHandler extends ViewHandler {
1920
1942
 
1921
1943
  if(!localFunc) {
1922
1944
  if(!this.dboBuilder.prostgles.isSuperUser) throw "Subscribe not possible. Must be superuser to add triggers 1856";
1923
- return await this.find(filter, { ...selectParams, limit: 0 }, null, table_rules, localParams)
1945
+ return await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams)
1924
1946
  .then(async isValid => {
1925
1947
 
1926
- const { socket = null } = localParams;
1948
+ const { socket } = localParams ?? {};
1927
1949
  const pubSubManager = await this.dboBuilder.getPubSubManager();
1928
1950
  return pubSubManager.addSub({
1929
1951
  table_info: this.tableOrViewInfo,
1930
1952
  socket,
1931
1953
  table_rules,
1932
1954
  condition: condition,
1933
- func: localFunc,
1955
+ func: undefined,
1934
1956
  filter: { ...filter },
1935
1957
  params: { ...selectParams },
1936
- channel_name: null,
1937
- socket_id: socket.id,
1958
+ socket_id: socket?.id,
1938
1959
  table_name: this.name,
1939
1960
  throttle,
1940
1961
  last_throttled: 0,
@@ -1945,14 +1966,13 @@ export class TableHandler extends ViewHandler {
1945
1966
  const pubSubManager = await this.dboBuilder.getPubSubManager();
1946
1967
  pubSubManager.addSub({
1947
1968
  table_info: this.tableOrViewInfo,
1948
- socket: null,
1969
+ socket: undefined,
1949
1970
  table_rules,
1950
1971
  condition,
1951
1972
  func: localFunc,
1952
1973
  filter: { ...filter },
1953
1974
  params: { ...selectParams },
1954
- channel_name: null,
1955
- socket_id: null,
1975
+ socket_id: undefined,
1956
1976
  table_name: this.name,
1957
1977
  throttle,
1958
1978
  last_throttled: 0,
@@ -1977,12 +1997,12 @@ export class TableHandler extends ViewHandler {
1977
1997
  subscribeOne(filter: Filter, params: SubscribeParams = {}, localFunc: (item: AnyObject) => any, table_rules?: TableRule, localParams?: LocalParams):
1978
1998
  Promise<string | { unsubscribe: () => any }>
1979
1999
  {
1980
- let func = localParams? undefined : (rows) => localFunc(rows[0]);
2000
+ let func = localParams? undefined : (rows: AnyObject[]) => localFunc(rows[0]);
1981
2001
  return this.subscribe(filter, { ...params, limit: 2 }, func, table_rules, localParams);
1982
2002
  }
1983
2003
 
1984
2004
 
1985
- async updateBatch(data: [Filter, AnyObject][], params?: UpdateParams, tableRules?: TableRule, localParams: LocalParams = null): Promise<any>{
2005
+ async updateBatch(data: [Filter, AnyObject][], params?: UpdateParams, tableRules?: TableRule, localParams?: LocalParams): Promise<any>{
1986
2006
  try {
1987
2007
  const queries = await Promise.all(
1988
2008
  data.map(async ([filter, data]) =>
@@ -2006,20 +2026,20 @@ export class TableHandler extends ViewHandler {
2006
2026
  }
2007
2027
  }
2008
2028
 
2009
- async update(filter: Filter, newData: { [key: string]: any }, params?: UpdateParams, tableRules?: TableRule, localParams: LocalParams = null): Promise<AnyObject | void>{
2029
+ async update(filter: Filter, newData: AnyObject, params?: UpdateParams, tableRules?: TableRule, localParams?: LocalParams): Promise<AnyObject | void>{
2010
2030
  try {
2011
2031
 
2012
- const { testRule = false, returnQuery = false } = localParams || {};
2032
+ const { testRule = false, returnQuery = false } = localParams ?? {};
2013
2033
  if(!testRule){
2014
2034
  if(!newData || !Object.keys(newData).length) throw "no update data provided\nEXPECTING db.table.update(filter, updateData, options)";
2015
2035
  this.checkFilter(filter);
2016
2036
  }
2017
2037
 
2018
- let forcedFilter: object = {},
2019
- forcedData: object = {},
2020
- validate: ValidateRow,
2021
- returningFields: FieldFilter = "*",
2022
- filterFields: FieldFilter = "*",
2038
+ let forcedFilter: AnyObject | undefined = {},
2039
+ forcedData: AnyObject | undefined = {},
2040
+ validate: ValidateRow | undefined,
2041
+ returningFields: FieldFilter | undefined = "*",
2042
+ filterFields: FieldFilter | undefined = "*",
2023
2043
  fields: FieldFilter = "*";
2024
2044
 
2025
2045
  if(tableRules){
@@ -2034,7 +2054,7 @@ export class TableHandler extends ViewHandler {
2034
2054
  await this.validateViewRules(fields, filterFields, returningFields, forcedFilter, "update");
2035
2055
  if(forcedData) {
2036
2056
  try {
2037
- const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData: null, allowedFields: "*", tableRules, fixIssues: false });
2057
+ const { data, allowedCols } = this.validateNewData({ row: forcedData, forcedData: undefined, allowedFields: "*", tableRules, fixIssues: false });
2038
2058
  const updateQ = await this.colSet.getUpdateQuery(data, allowedCols, validate) //pgp.helpers.update(data, columnSet)
2039
2059
  let query = updateQ + " WHERE FALSE ";
2040
2060
  await this.db.any("EXPLAIN " + query);
@@ -2079,13 +2099,13 @@ export class TableHandler extends ViewHandler {
2079
2099
  if(c.data_type === "text" && d && isPlainObject(d) && !["from", "to"].find(key => typeof d[key] !== "number")){
2080
2100
  const unrecProps = Object.keys(d).filter(k => !["from", "to", "text", "md5"].includes(k));
2081
2101
  if(unrecProps.length) throw "Unrecognised params in textPatch field: " + unrecProps.join(", ");
2082
- patchedTextData.push({ ...d, fieldName: c.name });
2102
+ patchedTextData.push({ ...d, fieldName: c.name } as (typeof patchedTextData)[number]);
2083
2103
  }
2084
2104
  });
2085
2105
 
2086
2106
  if(patchedTextData && patchedTextData.length){
2087
2107
  if(tableRules && !tableRules.select) throw "Select needs to be permitted to patch data";
2088
- const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) }, null, tableRules);
2108
+ const rows = await this.find(filter, { select: patchedTextData.reduce((a, v) => ({ ...a, [v.fieldName]: 1 }), {}) }, undefined, tableRules);
2089
2109
 
2090
2110
  if(rows.length !== 1) {
2091
2111
  throw "Cannot patch data within a filter that affects more/less than 1 row";
@@ -2121,9 +2141,9 @@ export class TableHandler extends ViewHandler {
2121
2141
  if(returnQuery) return query as unknown as void;
2122
2142
 
2123
2143
  if(this.t){
2124
- 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));
2125
2145
  }
2126
- 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));
2127
2147
  } catch(e){
2128
2148
  if(localParams && localParams.testRule) throw e;
2129
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)})` };
@@ -2131,7 +2151,7 @@ export class TableHandler extends ViewHandler {
2131
2151
  };
2132
2152
 
2133
2153
  validateNewData({ row, forcedData, allowedFields, tableRules, fixIssues = false }: ValidatedParams): { data: any; allowedCols: string[] } {
2134
- const synced_field = get(tableRules || {}, "sync.synced_field");
2154
+ const synced_field = get(tableRules ?? {}, "sync.synced_field");
2135
2155
 
2136
2156
  /* Update synced_field if sync is on and missing */
2137
2157
  if(synced_field && !row[synced_field]){
@@ -2139,7 +2159,7 @@ export class TableHandler extends ViewHandler {
2139
2159
  }
2140
2160
 
2141
2161
  let data = this.prepareFieldValues(row, forcedData, allowedFields, fixIssues);
2142
- const dataKeys = Object.keys(data);
2162
+ const dataKeys = getKeys(data);
2143
2163
 
2144
2164
  dataKeys.map(col => {
2145
2165
  this.dboBuilder.prostgles?.tableConfigurator?.checkColVal({ table: this.name, col, value: data[col] });
@@ -2158,7 +2178,7 @@ export class TableHandler extends ViewHandler {
2158
2178
  }
2159
2179
 
2160
2180
 
2161
- private async insertDataParse(data: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused?, tableRules?: TableRule, _localParams: LocalParams = null): Promise<{
2181
+ private async insertDataParse(data: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused?: never, tableRules?: TableRule, _localParams?: LocalParams): Promise<{
2162
2182
  data?: AnyObject | AnyObject[];
2163
2183
  insertResult?: AnyObject | AnyObject[];
2164
2184
  }>{
@@ -2166,7 +2186,7 @@ export class TableHandler extends ViewHandler {
2166
2186
  let dbTX = localParams?.dbTX || this.dbTX;
2167
2187
 
2168
2188
  const isMultiInsert = Array.isArray(data);
2169
- 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));
2170
2190
 
2171
2191
  /* Nested insert is not allowed for the file table */
2172
2192
  const isNestedInsert = this.is_media? false : (Array.isArray(data)? data : [data]).some(d => getExtraKeys(d).length);
@@ -2231,7 +2251,7 @@ export class TableHandler extends ViewHandler {
2231
2251
  const _media: Media = await this.dboBuilder.prostgles.fileManager.uploadAsMedia({
2232
2252
  item: {
2233
2253
  data,
2234
- name: media.name,
2254
+ name: media.name ?? "????",
2235
2255
  content_type: media.content_type as any
2236
2256
  },
2237
2257
  // imageCompression: {
@@ -2251,21 +2271,21 @@ export class TableHandler extends ViewHandler {
2251
2271
  } else if(extraKeys.length){
2252
2272
 
2253
2273
  /* Ensure we're using the same transaction */
2254
- const _this = this.t? this : dbTX[this.name] as TableHandler;
2274
+ const _this = this.t? this : dbTX![this.name] as TableHandler;
2255
2275
 
2256
- let rootData = filterObj(data, null, extraKeys);
2276
+ let rootData = filterObj(data, undefined, extraKeys);
2257
2277
 
2258
2278
  let insertedChildren: AnyObject[];
2259
2279
  let targetTableRules: TableRule;
2260
2280
 
2261
- const fullRootResult = await _this.insert(rootData, { returning: "*" }, null, tableRules, localParams);
2262
- let returnData: AnyObject;
2281
+ const fullRootResult = await _this.insert(rootData, { returning: "*" }, undefined, tableRules, localParams);
2282
+ let returnData: AnyObject | undefined;
2263
2283
  const returning = param2?.returning;
2264
2284
  if(returning){
2265
2285
  returnData = {}
2266
2286
  const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(tableRules?.insert?.returningFields));
2267
2287
  returningItems.filter(s => s.selected).map(rs => {
2268
- returnData[rs.alias] = fullRootResult[rs.alias];
2288
+ returnData![rs.alias] = fullRootResult[rs.alias];
2269
2289
  })
2270
2290
  }
2271
2291
 
@@ -2274,7 +2294,7 @@ export class TableHandler extends ViewHandler {
2274
2294
 
2275
2295
  /* Must be allowed to insert into media table */
2276
2296
  const canInsert = async (tbl: string) => {
2277
- const childRules = await this.dboBuilder.publishParser.getValidatedRequestRuleWusr({ tableName: tbl, command: "insert", localParams });
2297
+ const childRules = await this.dboBuilder.publishParser?.getValidatedRequestRuleWusr({ tableName: tbl, command: "insert", localParams });
2278
2298
  if(!childRules || !childRules.insert) throw "Dissallowed nested insert into table " + childRules;
2279
2299
  return childRules;
2280
2300
  }
@@ -2284,9 +2304,9 @@ export class TableHandler extends ViewHandler {
2284
2304
  if(!jp) throw `Could not find a valid table for the nested data { ${targetTable} } `;
2285
2305
 
2286
2306
  const thisInfo = await this.getInfo();
2287
- const childInsert = async (cdata, tableName) => {
2307
+ const childInsert = async (cdata: AnyObject | AnyObject[], tableName: string) => {
2288
2308
  // console.log("childInsert", {data, tableName})
2289
- 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;
2290
2310
 
2291
2311
  const tableRules = await canInsert(tableName);
2292
2312
 
@@ -2295,8 +2315,8 @@ export class TableHandler extends ViewHandler {
2295
2315
  }
2296
2316
  return Promise.all(
2297
2317
  (Array.isArray(cdata)? cdata : [cdata])
2298
- .map(m => (dbTX[tableName] as TableHandler)
2299
- .insert(m, { returning: "*" }, null, tableRules, localParams)
2318
+ .map(m => (dbTX![tableName] as TableHandler)
2319
+ .insert(m, { returning: "*" }, undefined, tableRules, localParams)
2300
2320
  .catch(e => {
2301
2321
  console.trace({ childInsertErr: e })
2302
2322
  return Promise.reject({ childInsertErr: e });
@@ -2323,10 +2343,10 @@ export class TableHandler extends ViewHandler {
2323
2343
 
2324
2344
  // console.log(childDataItems, JSON.stringify(colsRefT1, null, 2))
2325
2345
  insertedChildren = await childInsert(
2326
- childDataItems.map(d => {
2346
+ childDataItems.map((d: AnyObject) => {
2327
2347
  let result = {...d};
2328
2348
  colsRefT1.map(col => {
2329
- result[col.references.cols[0]] = fullRootResult[col.references.fcols[0]]
2349
+ result[col.references!.cols[0]] = fullRootResult[col.references!.fcols[0]]
2330
2350
  })
2331
2351
  return result;
2332
2352
  }),
@@ -2339,7 +2359,7 @@ export class TableHandler extends ViewHandler {
2339
2359
  const colsRefT3 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl3);
2340
2360
  if(!colsRefT1.length || !colsRefT3.length) throw "Incorrectly referenced or missing columns for nested insert";
2341
2361
 
2342
- if(targetTable !== this.dboBuilder.prostgles.fileManager.tableName){
2362
+ if(targetTable !== this.dboBuilder.prostgles.fileManager?.tableName){
2343
2363
  throw "Only media allowed to have nested inserts more than 2 tables apart"
2344
2364
  }
2345
2365
 
@@ -2352,13 +2372,13 @@ export class TableHandler extends ViewHandler {
2352
2372
 
2353
2373
  /* Insert in key_lookup table */
2354
2374
  await Promise.all(insertedChildren.map(async t3Child => {
2355
- let tbl2Row = {};
2375
+ let tbl2Row: AnyObject = {};
2356
2376
 
2357
2377
  colsRefT3.map(col => {
2358
- tbl2Row[col.name] = t3Child[col.references.fcols[0]];
2378
+ tbl2Row[col.name] = t3Child[col.references!.fcols[0]];
2359
2379
  })
2360
2380
  colsRefT1.map(col => {
2361
- tbl2Row[col.name] = fullRootResult[col.references.fcols[0]];
2381
+ tbl2Row[col.name] = fullRootResult[col.references!.fcols[0]];
2362
2382
  })
2363
2383
  // console.log({ rootResult, tbl2Row, t3Child, colsRefT3, colsRefT1, t: this.t?.ctx?.start });
2364
2384
 
@@ -2372,18 +2392,18 @@ export class TableHandler extends ViewHandler {
2372
2392
 
2373
2393
  /* Return also the nested inserted data */
2374
2394
  if(targetTableRules && insertedChildren?.length && returning){
2375
- const targetTableHandler = dbTX[targetTable] as TableHandler;
2395
+ const targetTableHandler = dbTX![targetTable] as TableHandler;
2376
2396
  const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(targetTableRules?.insert?.returningFields));
2377
2397
  let clientTargetInserts = insertedChildren.map(d => {
2378
2398
  let _d = { ...d };
2379
- let res = {};
2399
+ let res: AnyObject = {};
2380
2400
  targetReturning.map(r => {
2381
2401
  res[r.alias] = _d[r.alias]
2382
2402
  });
2383
2403
  return res;
2384
2404
  });
2385
2405
 
2386
- returnData[targetTable] = clientTargetInserts.length === 1? clientTargetInserts[0] : clientTargetInserts;
2406
+ returnData![targetTable] = clientTargetInserts.length === 1? clientTargetInserts[0] : clientTargetInserts;
2387
2407
  }
2388
2408
  }));
2389
2409
 
@@ -2404,7 +2424,7 @@ export class TableHandler extends ViewHandler {
2404
2424
  return res;
2405
2425
  }
2406
2426
 
2407
- async insert(rowOrRows: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused?, tableRules?: TableRule, _localParams: LocalParams = null): Promise<any | any[] | boolean>{
2427
+ async insert(rowOrRows: (AnyObject | AnyObject[]), param2?: InsertParams, param3_unused?: never, tableRules?: TableRule, _localParams?: LocalParams): Promise<any | any[] | boolean>{
2408
2428
  const localParams = _localParams || {};
2409
2429
  const {dbTX} = localParams
2410
2430
  try {
@@ -2412,9 +2432,9 @@ export class TableHandler extends ViewHandler {
2412
2432
  const { returning, onConflictDoNothing, fixIssues = false } = param2 || {};
2413
2433
  const { testRule = false, returnQuery = false } = localParams || {};
2414
2434
 
2415
- let returningFields: FieldFilter,
2416
- forcedData: object,
2417
- fields: FieldFilter;
2435
+ let returningFields: FieldFilter | undefined,
2436
+ forcedData: AnyObject | undefined,
2437
+ fields: FieldFilter | undefined;
2418
2438
 
2419
2439
  if(tableRules){
2420
2440
  if(!tableRules.insert) throw "insert rules missing for " + this.name;
@@ -2430,7 +2450,7 @@ export class TableHandler extends ViewHandler {
2430
2450
  /* Safely test publish rules */
2431
2451
  if(testRule){
2432
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";
2433
- await this.validateViewRules(fields, null, returningFields, null, "insert");
2453
+ await this.validateViewRules(fields, undefined, returningFields, undefined, "insert");
2434
2454
  if(forcedData) {
2435
2455
  const keys = Object.keys(forcedData);
2436
2456
  if(keys.length){
@@ -2462,7 +2482,7 @@ export class TableHandler extends ViewHandler {
2462
2482
 
2463
2483
  if(!rowOrRows) rowOrRows = {}; //throw "Provide data in param1";
2464
2484
  let returningSelect = this.makeReturnQuery(await this.prepareReturning(returning, this.parseFieldFilter(returningFields)));
2465
- const makeQuery = async (_row, isOne = false) => {
2485
+ const makeQuery = async (_row: AnyObject | undefined, isOne = false) => {
2466
2486
  let row = { ..._row };
2467
2487
 
2468
2488
  if(!isPojoObject(row)) {
@@ -2480,7 +2500,7 @@ export class TableHandler extends ViewHandler {
2480
2500
  };
2481
2501
 
2482
2502
  let query = "";
2483
- let queryType = "none";
2503
+ let queryType: keyof pgPromise.ITask<{}> = "none";
2484
2504
 
2485
2505
  /**
2486
2506
  * If media it will: upload file and continue insert
@@ -2517,9 +2537,9 @@ export class TableHandler extends ViewHandler {
2517
2537
 
2518
2538
  const allowedFieldKeys = this.parseFieldFilter(fields);
2519
2539
  if(tx) {
2520
- 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));
2521
2541
  } else {
2522
- 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));
2523
2543
  }
2524
2544
 
2525
2545
  return result;
@@ -2532,7 +2552,7 @@ export class TableHandler extends ViewHandler {
2532
2552
  }
2533
2553
  };
2534
2554
 
2535
- prepareReturning = async (returning: FieldFilter, allowedFields: string[]): Promise<SelectItem[]> => {
2555
+ prepareReturning = async (returning: Select<AnyObject>, allowedFields: string[]): Promise<SelectItem[]> => {
2536
2556
  let result: SelectItem[] = [];
2537
2557
  if(returning){
2538
2558
  let sBuilder = new SelectItemBuilder({
@@ -2556,7 +2576,7 @@ export class TableHandler extends ViewHandler {
2556
2576
  return "";
2557
2577
  }
2558
2578
 
2559
- async delete(filter?: Filter, params?: DeleteParams, param3_unused?, table_rules?: TableRule, localParams: LocalParams = null): Promise<any> { //{ socket, func, has_rules = false, socketDb } = {}
2579
+ async delete(filter?: Filter, params?: DeleteParams, param3_unused?: never, table_rules?: TableRule, localParams?: LocalParams): Promise<any> { //{ socket, func, has_rules = false, socketDb } = {}
2560
2580
  try {
2561
2581
  const { returning } = params || {};
2562
2582
  filter = filter || {};
@@ -2564,9 +2584,9 @@ export class TableHandler extends ViewHandler {
2564
2584
 
2565
2585
  // table_rules = table_rules || {};
2566
2586
 
2567
- let forcedFilter: object = {},
2568
- filterFields: FieldFilter = "*",
2569
- returningFields: FieldFilter = "*";
2587
+ let forcedFilter: AnyObject | undefined = {},
2588
+ filterFields: FieldFilter | undefined = "*",
2589
+ returningFields: FieldFilter | undefined = "*";
2570
2590
 
2571
2591
  const { testRule = false, returnQuery = false } = localParams || {};
2572
2592
  if(table_rules){
@@ -2582,7 +2602,7 @@ export class TableHandler extends ViewHandler {
2582
2602
 
2583
2603
  /* Safely test publish rules */
2584
2604
  if(testRule){
2585
- await this.validateViewRules(null, filterFields, returningFields, forcedFilter, "delete");
2605
+ await this.validateViewRules(undefined, filterFields, returningFields, forcedFilter, "delete");
2586
2606
  return true;
2587
2607
  }
2588
2608
  }
@@ -2594,7 +2614,7 @@ export class TableHandler extends ViewHandler {
2594
2614
  if(bad_params && bad_params.length) throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
2595
2615
  }
2596
2616
 
2597
- let queryType = 'none';
2617
+ let queryType: keyof pgPromise.ITask<{}> = 'none';
2598
2618
  let _query = "DELETE FROM " + this.escapedName;
2599
2619
 
2600
2620
  _query += (await this.prepareWhere({
@@ -2614,7 +2634,7 @@ export class TableHandler extends ViewHandler {
2614
2634
  }
2615
2635
 
2616
2636
  if(returnQuery) return _query;
2617
- 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));
2618
2638
  } catch(e){
2619
2639
  // console.trace(e)
2620
2640
  if(localParams && localParams.testRule) throw e;
@@ -2622,11 +2642,11 @@ export class TableHandler extends ViewHandler {
2622
2642
  }
2623
2643
  };
2624
2644
 
2625
- remove(filter: Filter, params?: UpdateParams, param3_unused?: null, tableRules?: TableRule, localParams: LocalParams = null){
2645
+ remove(filter: Filter, params?: UpdateParams, param3_unused?: never, tableRules?: TableRule, localParams?: LocalParams){
2626
2646
  return this.delete(filter, params, param3_unused , tableRules, localParams);
2627
2647
  }
2628
2648
 
2629
- async upsert(filter: Filter, newData?: object, params?: UpdateParams, table_rules?: TableRule, localParams: LocalParams = null): Promise<any> {
2649
+ async upsert(filter: Filter, newData: AnyObject, params?: UpdateParams, table_rules?: TableRule, localParams?: LocalParams): Promise<any> {
2630
2650
  try {
2631
2651
  /* Do it within a transaction to ensure consisency */
2632
2652
  if(!this.t){
@@ -2636,12 +2656,12 @@ export class TableHandler extends ViewHandler {
2636
2656
  }
2637
2657
 
2638
2658
  async function _upsert(tblH: TableHandler){
2639
- return tblH.find(filter, { select: "", limit: 1 }, {}, table_rules, localParams)
2659
+ return tblH.find(filter, { select: "", limit: 1 }, undefined, table_rules, localParams)
2640
2660
  .then(exists => {
2641
2661
  if(exists && exists.length){
2642
2662
  return tblH.update(filter, newData, params, table_rules, localParams);
2643
2663
  } else {
2644
- return tblH.insert({ ...newData, ...filter }, params, null, table_rules, localParams);
2664
+ return tblH.insert({ ...newData, ...filter }, params, undefined, table_rules, localParams);
2645
2665
  }
2646
2666
  });
2647
2667
  }
@@ -2652,7 +2672,7 @@ export class TableHandler extends ViewHandler {
2652
2672
  };
2653
2673
 
2654
2674
  /* External request. Cannot sync from server */
2655
- 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){
2656
2676
  if(!localParams) throw "Sync not allowed within the same server code";
2657
2677
  const { socket } = localParams;
2658
2678
  if(!socket) throw "INTERNAL ERROR: socket missing";
@@ -2697,7 +2717,7 @@ export class TableHandler extends ViewHandler {
2697
2717
  });
2698
2718
 
2699
2719
  /* Step 1: parse command and params */
2700
- return this.find(filter, { select, limit: 0 }, null, table_rules, localParams)
2720
+ return this.find(filter, { select, limit: 0 }, undefined, table_rules, localParams)
2701
2721
  .then(async isValid => {
2702
2722
 
2703
2723
  const { filterFields, forcedFilter } = get(table_rules, "select") || {};
@@ -2708,7 +2728,8 @@ export class TableHandler extends ViewHandler {
2708
2728
  return pubSubManager.addSync({
2709
2729
  table_info: this.tableOrViewInfo,
2710
2730
  condition,
2711
- id_fields, synced_field, allow_delete,
2731
+ id_fields, synced_field,
2732
+ allow_delete,
2712
2733
  socket,
2713
2734
  table_rules,
2714
2735
  filter: { ...filter },
@@ -2755,18 +2776,18 @@ import { JOIN_TYPES } from "./Prostgles";
2755
2776
  import { BasicSession } from "./AuthHandler";
2756
2777
 
2757
2778
  export class DboBuilder {
2758
- tablesOrViews: TableSchema[]; //TableSchema TableOrViewInfo
2779
+ tablesOrViews?: TableSchema[]; //TableSchema TableOrViewInfo
2759
2780
  /**
2760
2781
  * Used in obtaining column names for error messages
2761
2782
  */
2762
- constraints: PGConstraint[];
2783
+ constraints?: PGConstraint[];
2763
2784
 
2764
2785
  db: DB;
2765
2786
  schema: string = "public";
2766
2787
 
2767
2788
  // dbo: DbHandler | DbHandlerTX;
2768
2789
  dbo: DbHandler;
2769
- _pubSubManager: PubSubManager;
2790
+ _pubSubManager?: PubSubManager;
2770
2791
 
2771
2792
  getPubSubManager = async () : Promise<PubSubManager> => {
2772
2793
  if(!this._pubSubManager){
@@ -2793,26 +2814,27 @@ export class DboBuilder {
2793
2814
  console.warn(`subscribe and sync cannot be used because db user is not a superuser `)
2794
2815
  }
2795
2816
  }
2796
-
2817
+ if(!this._pubSubManager) throw "Could not create this._pubSubManager";
2797
2818
  return this._pubSubManager;
2798
2819
  }
2799
2820
 
2800
- pojoDefinitions: string[];
2801
- dboDefinition: string;
2821
+ pojoDefinitions?: string[];
2822
+ dboDefinition?: string;
2802
2823
 
2803
- tsTypesDefinition: string;
2824
+ tsTypesDefinition?: string;
2804
2825
 
2805
- joins: Join[];
2806
- joinGraph: Graph;
2807
- joinPaths: JoinPaths;
2826
+ joins?: Join[];
2827
+ joinGraph?: Graph;
2828
+ joinPaths: JoinPaths = [];
2808
2829
 
2809
2830
  prostgles: Prostgles;
2810
- publishParser: PublishParser;
2831
+ publishParser?: PublishParser;
2811
2832
 
2812
- onSchemaChange: (event: { command: string; query: string }) => void;
2833
+ onSchemaChange?: (event: { command: string; query: string }) => void;
2813
2834
 
2814
2835
  private constructor(prostgles: Prostgles){
2815
2836
  this.prostgles = prostgles;
2837
+ if(!this.prostgles.db) throw "db missing"
2816
2838
  this.db = this.prostgles.db;
2817
2839
  this.schema = this.prostgles.opts.schema || "public";
2818
2840
  this.dbo = { } as unknown as DbHandler;
@@ -2874,10 +2896,10 @@ export class DboBuilder {
2874
2896
  if(dup){
2875
2897
  throw "Duplicate join declaration for table: " + dup.tables[0];
2876
2898
  }
2877
- const tovNames = this.tablesOrViews.map(t => t.name);
2899
+ const tovNames = this.tablesOrViews!.map(t => t.name);
2878
2900
 
2879
2901
  // 2 find incorrect tables
2880
- const missing = flat(joins.map(j => j.tables)).find(t => !tovNames.includes(t));
2902
+ const missing = joins.flatMap(j => j.tables).find(t => !tovNames.includes(t));
2881
2903
  if(missing){
2882
2904
  throw "Table not found: " + missing;
2883
2905
  }
@@ -2892,9 +2914,9 @@ export class DboBuilder {
2892
2914
  var t = <string>v[0],
2893
2915
  f = <string[]>v[1];
2894
2916
 
2895
- let tov = this.tablesOrViews.find(_t => _t.name === t);
2917
+ let tov = this.tablesOrViews!.find(_t => _t.name === t);
2896
2918
  if(!tov) throw "Table not found: " + t;
2897
- const m1 = f.filter(k => !tov.columns.map(c => c.name).includes(k))
2919
+ const m1 = f.filter(k => !tov!.columns.map(c => c.name).includes(k))
2898
2920
  if(m1 && m1.length){
2899
2921
  throw `Table ${t}(${tov.columns.map(c => c.name).join()}) has no fields named: ${m1.join()}`;
2900
2922
  }
@@ -2919,17 +2941,17 @@ export class DboBuilder {
2919
2941
  let _t = tables.slice().sort(),
2920
2942
  t1 = _t[0],
2921
2943
  t2 = _t[1];
2922
- this.joinGraph[t1] = this.joinGraph[t1] || {};
2923
- this.joinGraph[t1][t2] = 1;
2944
+ this.joinGraph![t1] = this.joinGraph![t1] || {};
2945
+ this.joinGraph![t1][t2] = 1;
2924
2946
 
2925
- this.joinGraph[t2] = this.joinGraph[t2] || {};
2926
- this.joinGraph[t2][t1] = 1;
2947
+ this.joinGraph![t2] = this.joinGraph![t2] || {};
2948
+ this.joinGraph![t2][t1] = 1;
2927
2949
  });
2928
- const tables = flat(this.joins.map(t => t.tables));
2950
+ const tables = this.joins.flatMap(t => t.tables);
2929
2951
  this.joinPaths = [];
2930
2952
  tables.map(t1 => {
2931
2953
  tables.map(t2 => {
2932
- const spath = findShortestPath(this.joinGraph, t1, t2);
2954
+ const spath = findShortestPath(this.joinGraph!, t1, t2);
2933
2955
  if(spath && spath.distance < Infinity){
2934
2956
 
2935
2957
  const existing1 = this.joinPaths.find(j => j.t1 === t1 && j.t2 === t2)
@@ -2976,7 +2998,7 @@ export type TxCB = {
2976
2998
 
2977
2999
  await this.parseJoins();
2978
3000
 
2979
- let joinTableNames = [];
3001
+ let joinTableNames: string[] = [];
2980
3002
 
2981
3003
  let allDataDefs = "";
2982
3004
  let i18nDef = "type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]>; }; \n"
@@ -3004,10 +3026,10 @@ export type TxCB = {
3004
3026
  const TSTableDataName = snakify(tov.name, true);
3005
3027
  const TSTableHandlerName = JSON.stringify(tov.name)
3006
3028
  if(tov.is_view){
3007
- this.dbo[tov.name] = new ViewHandler(this.db, tov, this, null, undefined, this.joinPaths);
3029
+ this.dbo[tov.name] = new ViewHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
3008
3030
  this.dboDefinition += ` ${TSTableHandlerName}: ViewHandler<${TSTableDataName}> \n`;
3009
3031
  } else {
3010
- this.dbo[tov.name] = new TableHandler(this.db, tov, this, null, undefined, this.joinPaths);
3032
+ this.dbo[tov.name] = new TableHandler(this.db, tov, this, undefined, undefined, this.joinPaths);
3011
3033
  this.dboDefinition += ` ${TSTableHandlerName}: TableHandler<${TSTableDataName}> \n`;
3012
3034
  }
3013
3035
  allDataDefs += `export type ${TSTableDataName} = { \n` +
@@ -3021,6 +3043,19 @@ export type TxCB = {
3021
3043
  let table = tov.name;
3022
3044
  joinTableNames.push(table);
3023
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
+ }
3024
3059
  this.dbo.innerJoin = this.dbo.innerJoin || {};
3025
3060
  this.dbo.leftJoin = this.dbo.leftJoin || {};
3026
3061
  this.dbo.innerJoinOne = this.dbo.innerJoinOne || {};
@@ -3037,14 +3072,6 @@ export type TxCB = {
3037
3072
  this.dbo.innerJoinOne[table] = (filter, select, options = {}) => {
3038
3073
  return makeJoin(false, filter, select, {...options, limit: 1});
3039
3074
  }
3040
- function makeJoin(isLeft = true, filter, select, options){
3041
- return {
3042
- [isLeft? "$leftJoin" : "$innerJoin"]: table,
3043
- filter,
3044
- select,
3045
- ...options
3046
- }
3047
- }
3048
3075
  }
3049
3076
  });
3050
3077
  i18nDef += " }> \n";
@@ -3074,17 +3101,17 @@ export type TxCB = {
3074
3101
  if(!this.dbo.sql){
3075
3102
 
3076
3103
  let needType = true;// this.publishRawSQL && typeof this.publishRawSQL === "function";
3077
- let DATA_TYPES = !needType? [] : await this.db.any("SELECT oid, typname FROM pg_type");
3078
- 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");
3079
3106
 
3080
- 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) => {
3081
3108
 
3082
- const canRunSQL = async (localParams: LocalParams) => {
3109
+ const canRunSQL = async (localParams?: LocalParams) => {
3083
3110
  if(!localParams) return true;
3084
3111
 
3085
3112
  const { socket } = localParams;
3086
- const publishParams = await this.prostgles.publishParser.getPublishParams({ socket });
3087
- 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);
3088
3115
  return Boolean(res && typeof res === "boolean" || res === "*");
3089
3116
  }
3090
3117
 
@@ -3095,12 +3122,12 @@ export type TxCB = {
3095
3122
 
3096
3123
  if(returnType === "noticeSubscription"){
3097
3124
  if(!socket) throw "Only allowed with client socket"
3098
- return await this.prostgles.dbEventsManager.addNotice(socket);
3125
+ return await this.prostgles.dbEventsManager?.addNotice(socket);
3099
3126
  } else if(returnType === "statement"){
3100
3127
  try {
3101
3128
  return pgp.as.format(query, params);
3102
3129
  } catch (err){
3103
- throw err.toString();
3130
+ throw (err as any).toString();
3104
3131
  }
3105
3132
  } else if(this.db) {
3106
3133
 
@@ -3109,8 +3136,8 @@ export type TxCB = {
3109
3136
  finalQuery = new PQ({ text: pgp.as.format(query, params), rowMode: "array" });
3110
3137
  }
3111
3138
 
3112
- let qres = await this.db.result(finalQuery, params)
3113
- const { duration, fields, rows, command } = qres;
3139
+ let _qres = await this.db.result(finalQuery, params)
3140
+ const { fields, rows, command } = _qres;
3114
3141
 
3115
3142
  /**
3116
3143
  * Fallback for watchSchema in case not superuser and cannot add db event listener
@@ -3132,7 +3159,7 @@ export type TxCB = {
3132
3159
 
3133
3160
  if(command === "LISTEN"){
3134
3161
  if(!socket) throw "Only allowed with client socket"
3135
- return await this.prostgles.dbEventsManager.addNotify(query, socket);
3162
+ return await this.prostgles.dbEventsManager?.addNotify(query, socket);
3136
3163
 
3137
3164
  } else if(returnType === "rows") {
3138
3165
  return rows;
@@ -3147,22 +3174,27 @@ export type TxCB = {
3147
3174
  return rows.map(r => Object.values(r[0]));
3148
3175
 
3149
3176
  } else {
3150
- if(fields && DATA_TYPES.length){
3151
- qres.fields = fields.map(f => {
3152
- const dataType = DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID),
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",
3153
3183
  tableName = USER_TABLES.find(t => +t.relid === +f.tableID),
3154
- { name } = f;
3184
+ tsDataType = postgresToTsType(dataType);
3155
3185
 
3156
3186
  return {
3157
3187
  ...f,
3158
- ...(dataType? { dataType: dataType.typname } : {}),
3159
- ...(tableName? { tableName: tableName.relname } : {}),
3188
+ tsDataType,
3189
+ dataType,
3190
+ udt_name: dataType,
3191
+ tableName: tableName?.relname
3160
3192
  }
3161
- });
3162
- }
3193
+ }) ?? []
3194
+ };
3163
3195
  return qres;
3164
3196
  }
3165
-
3197
+
3166
3198
  } else console.error("db missing");
3167
3199
  }
3168
3200
  } else {
@@ -3189,7 +3221,7 @@ export type TxCB = {
3189
3221
  getTX = (cb: TxCB) => {
3190
3222
  return this.db.tx((t) => {
3191
3223
  let dbTX: TxHandler = {};
3192
- this.tablesOrViews.map(tov => {
3224
+ this.tablesOrViews?.map(tov => {
3193
3225
  if(tov.is_view){
3194
3226
 
3195
3227
  dbTX[tov.name] = new ViewHandler(this.db, tov, this, t, dbTX, this.joinPaths);
@@ -3446,17 +3478,20 @@ function validateObj(obj: object, allowedKeys: string[]): object{
3446
3478
  }
3447
3479
 
3448
3480
 
3449
- export function isPlainObject(o) {
3481
+ export function isPlainObject(o: any): o is Record<string, any> {
3450
3482
  return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
3451
3483
  }
3452
-
3484
+ export function getKeys<T>(o: T): Array<keyof T>{
3485
+ return Object.keys(o) as any
3486
+ }
3453
3487
  export function postgresToTsType(udt_data_type: PG_COLUMN_UDT_DATA_TYPE): keyof typeof TS_PG_Types {
3454
- return Object.keys(TS_PG_Types).find(k => {
3488
+ return getKeys(TS_PG_Types).find(k => {
3489
+ // @ts-ignore
3455
3490
  return TS_PG_Types[k].includes(udt_data_type) || !TS_PG_Types[k].length;
3456
3491
  }) as keyof typeof TS_PG_Types;
3457
3492
  }
3458
3493
 
3459
- function sqlErrCodeToMsg(code){
3494
+ function sqlErrCodeToMsg(code: string){
3460
3495
  const errs = {
3461
3496
  "00000": "successful_completion",
3462
3497
  "01000": "warning",
@@ -3701,6 +3736,7 @@ function sqlErrCodeToMsg(code){
3701
3736
  },
3702
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"}
3703
3738
 
3739
+ //@ts-ignore
3704
3740
  return c2[code] || errs[code] || code;
3705
3741
 
3706
3742
  /*