prostgles-server 2.0.144 → 2.0.147

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/AuthHandler.d.ts +15 -13
  2. package/dist/AuthHandler.d.ts.map +1 -1
  3. package/dist/AuthHandler.js +41 -43
  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 +62 -50
  10. package/dist/DboBuilder.d.ts.map +1 -1
  11. package/dist/DboBuilder.js +229 -170
  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 +48 -21
  16. package/dist/FileManager.js.map +1 -1
  17. package/dist/Filtering.d.ts.map +1 -1
  18. package/dist/Filtering.js +11 -9
  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 +122 -83
  27. package/dist/Prostgles.js.map +1 -1
  28. package/dist/PubSubManager.d.ts +9 -9
  29. package/dist/PubSubManager.d.ts.map +1 -1
  30. package/dist/PubSubManager.js +10 -9
  31. package/dist/PubSubManager.js.map +1 -1
  32. package/dist/QueryBuilder.d.ts +26 -8
  33. package/dist/QueryBuilder.d.ts.map +1 -1
  34. package/dist/QueryBuilder.js +114 -46
  35. package/dist/QueryBuilder.js.map +1 -1
  36. package/dist/SyncReplication.d.ts +1 -1
  37. package/dist/SyncReplication.d.ts.map +1 -1
  38. package/dist/SyncReplication.js +31 -29
  39. package/dist/SyncReplication.js.map +1 -1
  40. package/dist/TableConfig.d.ts +0 -1
  41. package/dist/TableConfig.d.ts.map +1 -1
  42. package/dist/TableConfig.js +25 -17
  43. package/dist/TableConfig.js.map +1 -1
  44. package/dist/shortestPath.d.ts.map +1 -1
  45. package/dist/shortestPath.js.map +1 -1
  46. package/dist/utils.d.ts +2 -0
  47. package/dist/utils.d.ts.map +1 -1
  48. package/dist/utils.js +6 -0
  49. package/dist/utils.js.map +1 -1
  50. package/lib/AuthHandler.ts +50 -40
  51. package/lib/DBEventsManager.ts +14 -7
  52. package/lib/DboBuilder.ts +265 -199
  53. package/lib/FileManager.ts +30 -21
  54. package/lib/Filtering.ts +19 -16
  55. package/lib/PostgresNotifListenManager.ts +11 -10
  56. package/lib/Prostgles.ts +89 -73
  57. package/lib/PubSubManager.ts +13 -11
  58. package/lib/QueryBuilder.ts +135 -54
  59. package/lib/SyncReplication.ts +10 -10
  60. package/lib/TableConfig.ts +23 -15
  61. package/lib/shortestPath.ts +6 -4
  62. package/lib/utils.ts +7 -1
  63. package/package.json +7 -8
  64. package/tests/client/PID.txt +1 -1
  65. package/tests/client/index.js +10 -7
  66. package/tests/client/index.ts +12 -8
  67. package/tests/client/package-lock.json +14 -14
  68. package/tests/client/package.json +2 -2
  69. package/tests/client/tsconfig.json +2 -2
  70. package/tests/client_only_queries.js +127 -104
  71. package/tests/client_only_queries.ts +43 -17
  72. package/tests/isomorphic_queries.js +44 -6
  73. package/tests/isomorphic_queries.ts +42 -6
  74. package/tests/server/package-lock.json +27 -29
  75. package/tests/server/package.json +2 -2
  76. package/tests/server/tsconfig.json +2 -2
  77. package/tsconfig.json +3 -2
@@ -5,9 +5,9 @@
5
5
  *--------------------------------------------------------------------------------------------*/
6
6
 
7
7
  import { pgp, Filter, LocalParams, isPlainObject, TableHandler, ViewHandler, postgresToTsType } from "./DboBuilder";
8
- import { TableRule, flat } from "./Prostgles";
8
+ import { TableRule } from "./Prostgles";
9
9
  import { SelectParamsBasic as SelectParams, isEmpty, FieldFilter, asName, TextFilter_FullTextSearchFilterKeys, TS_PG_Types, ColumnInfo, PG_COLUMN_UDT_DATA_TYPE } from "prostgles-types";
10
- import { get } from "./utils";
10
+ import { get, isObject } from "./utils";
11
11
 
12
12
 
13
13
  export type SelectItem = {
@@ -47,6 +47,65 @@ export const asNameAlias = (field: string, tableAlias?: string) => {
47
47
  return result;
48
48
  }
49
49
 
50
+ export const parseFunctionObject = (funcData: any): { funcName: string; args: any[] } => {
51
+ const makeErr = (msg: string) => `Function not specified correctly. Expecting { $funcName: ["columnName",...] } object but got: ${JSON.stringify(funcData)} \n ${msg}`
52
+ if(!isObject(funcData)) throw makeErr("");
53
+ const keys = Object.keys(funcData);
54
+ if(keys.length !== 1) throw makeErr("");
55
+ const funcName = keys[0];
56
+ const args = funcData[funcName];
57
+ if(!args || !Array.isArray(args)){
58
+ throw makeErr("Arguments missing or invalid");
59
+ }
60
+
61
+ return { funcName, args };
62
+ }
63
+
64
+ export const parseFunction = (funcData: { func: string | FunctionSpec, args: any[], functions: FunctionSpec[]; allowedFields: string[]; }): FunctionSpec => {
65
+ const { func, args, functions, allowedFields } = funcData;
66
+
67
+ /* Function is computed column. No checks needed */
68
+ if(typeof func !== "string"){
69
+ const computedCol = COMPUTED_FIELDS.find(c => c.name === func.name);
70
+ if(!computedCol) throw `Unexpected function: computed column spec not found for ${JSON.stringify(func.name)}`;
71
+ return func;
72
+ }
73
+
74
+ const funcName = func;
75
+ const makeErr = (msg: string): string => {
76
+ return `Issue with function ${JSON.stringify({ [funcName]: args })}: \n${msg}`
77
+ }
78
+
79
+ /* Find function */
80
+ const funcDef = functions.find(f => f.name === funcName);
81
+
82
+ if(!funcDef) {
83
+ const sf = functions.filter(f => f.name.toLowerCase().slice(1).startsWith(funcName.toLowerCase())).sort((a, b) => (a.name.length - b.name.length));
84
+ const hint = (sf.length? `. \n Maybe you meant: \n | ${sf.map(s => s.name + " " + (s.description || "")).join(" \n | ")} ?` : "");
85
+ throw "\n Function " + funcName + " does not exist or is not allowed " + hint;
86
+ }
87
+
88
+ /* Validate fields */
89
+ const fields = funcDef.getFields(args);
90
+ if(fields !== "*"){
91
+ fields.forEach(fieldKey => {
92
+ if(typeof fieldKey !== "string" || !allowedFields.includes(fieldKey)) {
93
+ throw makeErr(`getFields() => field name ${JSON.stringify(fieldKey)} is invalid or disallowed`)
94
+ }
95
+ });
96
+ if((funcDef.minCols ?? 0) > fields.length){
97
+ throw makeErr(`Less columns provided than necessary (minCols=${funcDef.minCols})`)
98
+ }
99
+ }
100
+
101
+ if(funcDef.numArgs && funcDef.minCols !== 0 && fields !== "*" && Array.isArray(fields) && !fields.length) {
102
+ throw `\n Function "${funcDef.name}" expects at least a field name but has not been provided with one`;
103
+ }
104
+
105
+ return funcDef;
106
+ }
107
+
108
+
50
109
  type GetQueryArgs = {
51
110
  allColumns: ColumnInfo[];
52
111
  allowedFields: string[];
@@ -84,17 +143,29 @@ export type FunctionSpec = {
84
143
  */
85
144
  // returnsBoolean?: boolean;
86
145
 
146
+ /**
147
+ * Number of arguments expected
148
+ */
87
149
  numArgs: number;
150
+
151
+ /**
152
+ * If provided then the number of column names provided to the function (from getFields()) must not be less than this
153
+ * By default every function is checked against numArgs
154
+ */
155
+ minCols?: number;
156
+
88
157
  type: "function" | "aggregation" | "computed";
89
158
  /**
90
159
  * getFields: string[] -> used to validate user supplied field names. It will be fired before querying to validate against allowed columns
91
160
  * if not field names are used from arguments then return an empty array
92
161
  */
93
- getFields: (args: any[], allowedFields: string[]) => "*" | string[];
162
+ getFields: (args: any[]) => "*" | string[];
94
163
  /**
95
164
  * allowedFields passed for multicol functions (e.g.: $rowhash)
96
165
  */
97
166
  getQuery: (params: GetQueryArgs) => string;
167
+
168
+ returnType?: PG_COLUMN_UDT_DATA_TYPE;
98
169
  };
99
170
 
100
171
  const MAX_COL_NUM = 1600;
@@ -187,8 +258,10 @@ let PostGIS_Funcs: FunctionSpec[] = [
187
258
 
188
259
  if(!isPlainObject(arg2)) mErr();
189
260
  const col = allColumns.find(c => c.name === args[0]);
261
+ if(!col) throw new Error("Col not found: " + args[0])
190
262
 
191
- const { lat, lng, srid = 4326,
263
+ const {
264
+ lat, lng, srid = 4326,
192
265
  geojson, text, use_spheroid,
193
266
  distance, spheroid = 'SPHEROID["WGS 84",6378137,298.257223563]',
194
267
  debug
@@ -528,7 +601,7 @@ export const FUNCTIONS: FunctionSpec[] = [
528
601
  second: "minute"
529
602
  };
530
603
 
531
- let res = `(date_trunc(${asValue(prevInt[unit] || "hour")}, ${col}) + date_part(${asValue(unit, "::text")}, ${col})::int / ${val} * interval ${asValue(val + " " + unit)})`;
604
+ let res = `(date_trunc(${asValue(prevInt[unit as "month"] || "hour")}, ${col}) + date_part(${asValue(unit, "::text")}, ${col})::int / ${val} * interval ${asValue(val + " " + unit)})`;
532
605
  // console.log(res);
533
606
  return res;
534
607
  }
@@ -595,7 +668,7 @@ export const FUNCTIONS: FunctionSpec[] = [
595
668
  } as FunctionSpec)),
596
669
 
597
670
  /* Basic 1 arg col funcs */
598
- ...["upper", "lower", "length", "reverse", "trim", "initcap", "round", "ceil", "floor", "sign", "age", "md5"].map(funcName => ({
671
+ ...["upper", "lower", "length", "reverse", "trim", "initcap", "round", "ceil", "floor", "sign", "md5"].map(funcName => ({
599
672
  name: "$" + funcName,
600
673
  type: "function",
601
674
  numArgs: 1,
@@ -606,6 +679,27 @@ export const FUNCTIONS: FunctionSpec[] = [
606
679
  }
607
680
  } as FunctionSpec)),
608
681
 
682
+ /* Interval funcs */
683
+ ...["age", "difference"].map(funcName => ({
684
+ name: "$" + funcName,
685
+ type: "function",
686
+ numArgs: 1,
687
+ singleColArg: true,
688
+ getFields: (args: any[]) => args,
689
+ getQuery: ({ allowedFields, args, tableAlias }) => {
690
+ const validCols = args.filter(a => typeof a === "string").length
691
+ if(funcName === "difference" && validCols !== 2) throw new Error("Must have two column names")
692
+ if(![1,2].includes(validCols)) throw new Error("Must have one or two column names")
693
+ const [leftField, rightField] = args;
694
+ const leftQ = asNameAlias(leftField, tableAlias);
695
+ const rightQ = rightField? ("," + asNameAlias(rightField, tableAlias)) : "";
696
+ if(funcName === "age"){
697
+ return `${funcName}(${leftQ}, ${rightQ})`;
698
+ } else {
699
+ return `${leftQ} - ${rightQ}`;
700
+ }
701
+ }
702
+ } as FunctionSpec)),
609
703
 
610
704
  /* pgcrypto funcs */
611
705
  ...["crypt"].map(funcName => ({
@@ -643,8 +737,9 @@ export const FUNCTIONS: FunctionSpec[] = [
643
737
  name: "$" + funcName,
644
738
  type: "function",
645
739
  numArgs: 1,
740
+ minCols: 0,
646
741
  singleColArg: false,
647
- getFields: (args: any[], allowedFields) => allowedFields.filter(fName => args?.[0]?.includes(`{${fName}}`)),
742
+ getFields: (args: any[]) => [] as string[], // Fields not validated because we'll use the allowed ones anyway
648
743
  getQuery: ({ allowedFields, args, tableAlias }) => {
649
744
  let value = asValue(args[0]);
650
745
  if(typeof value !== "string") throw "expecting string argument";
@@ -761,7 +856,7 @@ export const FUNCTIONS: FunctionSpec[] = [
761
856
  let _cols = validCols.filter(c =>
762
857
  /** Exclude numeric columns when the search tern contains a character */
763
858
  !hasChars ||
764
- postgresToTsType(c.colInfo.udt_name) !== "number"
859
+ postgresToTsType(c.colInfo!.udt_name) !== "number"
765
860
  );
766
861
 
767
862
  /** This will break GROUP BY (non-integer constant in GROUP BY) */
@@ -947,28 +1042,16 @@ export class SelectItemBuilder {
947
1042
  this.select.push(item);
948
1043
  }
949
1044
 
950
- private addFunctionByName = (funcName: string, args: any[], alias: string) => {
951
- const funcDef = this.functions.find(f => f.name === funcName);
952
- if(!funcDef) {
953
- const sf = this.functions.filter(f => f.name.toLowerCase().slice(1).startsWith(funcName.toLowerCase())).sort((a, b) => (a.name.length - b.name.length));
954
- const hint = (sf.length? `. \n Maybe you meant: \n | ${sf.map(s => s.name + " " + (s.description || "")).join(" \n | ")} ?` : "");
955
- throw "\n Function " + funcName + " does not exist or is not allowed " + hint;
956
- }
957
- this.addFunction(funcDef, args, alias);
958
- }
1045
+ private addFunction = (func: FunctionSpec | string, args: any[], alias: string) => {
1046
+ const funcDef = parseFunction({
1047
+ func, args, functions: this.functions,
1048
+ allowedFields: this.allowedFieldsIncludingComputed,
1049
+ });
959
1050
 
960
- private addFunction = (funcDef: FunctionSpec, args: any[], alias: string) => {
961
- if(funcDef.numArgs) {
962
- const fields = funcDef.getFields(args, this.allowedFields);// && (! || !funcDef.getFields(args) !== "*" !funcDef.getFields(args).filter(f => f).length
963
- if(fields !== "*" && Array.isArray(fields) && !fields.length ){
964
- console.log(fields)
965
- throw `\n Function "${funcDef.name}" is missing a field name argument`;
966
- }
967
- }
968
1051
  this.addItem({
969
1052
  type: funcDef.type,
970
1053
  alias,
971
- getFields: () => funcDef.getFields(args, this.allowedFields),
1054
+ getFields: () => funcDef.getFields(args),
972
1055
  getQuery: (tableAlias?: string) => funcDef.getQuery({ allColumns: this.columns, allowedFields: this.allowedFields, args, tableAlias,
973
1056
  ctidField: undefined,
974
1057
 
@@ -1046,7 +1129,7 @@ export class SelectItemBuilder {
1046
1129
 
1047
1130
  } else {
1048
1131
  await Promise.all(selectKeys.map(async key => {
1049
- const val = userSelect[key],
1132
+ const val: any = userSelect[key as keyof typeof userSelect],
1050
1133
  throwErr = (extraErr: string = "") => {
1051
1134
  console.trace(extraErr)
1052
1135
  throw "Unexpected select -> " + JSON.stringify({ [key]: val }) + "\n" + extraErr;
@@ -1084,14 +1167,13 @@ export class SelectItemBuilder {
1084
1167
  }
1085
1168
  funcName = val;
1086
1169
  args = [key];
1170
+
1171
+ /** Function full notation { $funcName: ["colName", ...args] } */
1087
1172
  } else {
1088
- const callKeys = Object.keys(val);
1089
- if(callKeys.length !== 1 || !Array.isArray(val[callKeys[0]])) throw "\nIssue with select. \nUnexpected function definition. \nExpecting { field_name: func_name } OR { result_key: { func_name: [arg1, arg2 ...] } } \nBut got -> " + JSON.stringify({ [key]: val });
1090
- funcName = callKeys[0];
1091
- args = val[funcName];
1173
+ ({ funcName, args } = parseFunctionObject(val));
1092
1174
  }
1093
1175
 
1094
- this.addFunctionByName(funcName, args, key);
1176
+ this.addFunction(funcName, args, key);
1095
1177
 
1096
1178
  /* Join */
1097
1179
  } else {
@@ -1114,10 +1196,10 @@ export class SelectItemBuilder {
1114
1196
  export async function getNewQuery(
1115
1197
  _this: TableHandler,
1116
1198
  filter: Filter,
1117
- selectParams: SelectParams & { alias?: string },
1199
+ selectParams: (SelectParams & { alias?: string }) = {},
1118
1200
  param3_unused = null,
1119
- tableRules: TableRule,
1120
- localParams: LocalParams,
1201
+ tableRules: TableRule | undefined,
1202
+ localParams: LocalParams | undefined,
1121
1203
  columns: ColumnInfo[],
1122
1204
  ): Promise<NewQuery> {
1123
1205
 
@@ -1145,7 +1227,6 @@ export async function getNewQuery(
1145
1227
 
1146
1228
  // const all_colnames = _this.column_names.slice(0).concat(COMPUTED_FIELDS.map(c => c.name));
1147
1229
 
1148
- selectParams = selectParams || {};
1149
1230
  const { select: userSelect = "*" } = selectParams,
1150
1231
  // allCols = _this.column_names.slice(0),
1151
1232
  // allFieldsIncludingComputed = allCols.concat(COMPUTED_FIELDS.map(c => c.name)),
@@ -1160,10 +1241,10 @@ export async function getNewQuery(
1160
1241
  // console.log({ key, val })
1161
1242
  let j_filter: Filter = {},
1162
1243
  j_selectParams: SelectParams = {},
1163
- j_path: string[],
1164
- j_alias: string,
1165
- j_tableRules: TableRule,
1166
- j_table: string,
1244
+ j_path: string[] | undefined,
1245
+ j_alias: string | undefined,
1246
+ j_tableRules: TableRule | undefined,
1247
+ j_table: string | undefined,
1167
1248
  j_isLeftJoin: boolean = true;
1168
1249
 
1169
1250
  if(val === "*"){
@@ -1199,7 +1280,7 @@ export async function getNewQuery(
1199
1280
  j_table = key;
1200
1281
  }
1201
1282
  }
1202
-
1283
+ if(!j_table) throw "j_table missing"
1203
1284
  const _thisJoinedTable: any = _this.dboBuilder.dbo[j_table];
1204
1285
  if(!_thisJoinedTable) {
1205
1286
  throw `Joined table ${JSON.stringify(j_table)} is disallowed or inexistent \nOr you've forgot to put the function arguments into an array`;
@@ -1208,7 +1289,7 @@ export async function getNewQuery(
1208
1289
  let isLocal = true;
1209
1290
  if(localParams && (localParams.socket || localParams.httpReq)){
1210
1291
  isLocal = false;
1211
- j_tableRules = await _this.dboBuilder.publishParser.getValidatedRequestRuleWusr({ tableName: j_table, command: "find", localParams });
1292
+ j_tableRules = await _this.dboBuilder.publishParser?.getValidatedRequestRuleWusr({ tableName: j_table, command: "find", localParams });
1212
1293
  }
1213
1294
 
1214
1295
  if(isLocal || j_tableRules){
@@ -1262,7 +1343,7 @@ export async function getNewQuery(
1262
1343
  where,
1263
1344
  // having: cond.having,
1264
1345
  limit: _this.prepareLimitQuery(selectParams.limit, p),
1265
- orderBy: [_this.prepareSort(selectParams.orderBy, allowedFields, selectParams.alias, null, select)],
1346
+ orderBy: [_this.prepareSort(selectParams.orderBy, allowedFields, selectParams.alias, undefined, select)],
1266
1347
  offset: _this.prepareOffsetQuery(selectParams.offset)
1267
1348
  } as NewQuery;
1268
1349
 
@@ -1279,19 +1360,19 @@ export function makeQuery(
1279
1360
  q: NewQuery,
1280
1361
  depth: number = 0,
1281
1362
  joinFields: string[] = [],
1282
- selectParams: SelectParams,
1363
+ selectParams: SelectParams = {},
1283
1364
  ): string {
1284
1365
  const PREF = `prostgles`,
1285
1366
  joins = q.joins || [],
1286
1367
  // aggs = q.aggs || [],
1287
1368
  makePref = (q: NewQuery) => !q.tableAlias? q.table : `${q.tableAlias || ""}_${q.table}`,
1288
- makePrefANON = (joinAlias, table) => asName(!joinAlias? table : `${joinAlias || ""}_${table}`),
1369
+ makePrefANON = (joinAlias: string | undefined, table: string) => asName(!joinAlias? table : `${joinAlias || ""}_${table}`),
1289
1370
  makePrefAN = (q: NewQuery) => asName(makePref(q));
1290
1371
 
1291
- const indentLine = (numInd, str, indentStr = " ") => new Array(numInd).fill(indentStr).join("") + str;
1292
- const indStr = (numInd, str: string) => str.split("\n").map(s => indentLine(numInd, s)).join("\n");
1293
- const indjArr = (numInd, strArr: string[], indentStr = " "): string[] => strArr.map(str => indentLine(numInd, str) );
1294
- const indJ = (numInd, strArr: string[], separator = " \n ", indentStr = " ") => indjArr(numInd, strArr, indentStr).join(separator);
1372
+ const indentLine = (numInd: number, str: string, indentStr = " ") => new Array(numInd).fill(indentStr).join("") + str;
1373
+ const indStr = (numInd: number, str: string) => str.split("\n").map(s => indentLine(numInd, s)).join("\n");
1374
+ const indjArr = (numInd: number, strArr: string[], indentStr = " "): string[] => strArr.map(str => indentLine(numInd, str) );
1375
+ const indJ = (numInd: number, strArr: string[], separator = " \n ", indentStr = " ") => indjArr(numInd, strArr, indentStr).join(separator);
1295
1376
  const selectArrComma = (strArr: string[]): string[] => strArr.map((s, i, arr)=> s + (i < arr.length - 1? " , " : " "));
1296
1377
  const prefJCAN = (q: NewQuery, str: string) => asName(`${q.tableAlias || q.table}_${PREF}_${str}`);
1297
1378
 
@@ -1300,7 +1381,7 @@ export function makeQuery(
1300
1381
  const joinInfo = _this.getJoins(q1.table, q2.table, q2.$path, true);
1301
1382
  const paths = joinInfo.paths;
1302
1383
 
1303
- return flat(paths.map(({ table, on }, i) => {
1384
+ return paths.flatMap(({ table, on }, i) => {
1304
1385
  const getColName = (col: string, q: NewQuery) => {
1305
1386
  if(table === q.table){
1306
1387
  const colFromSelect = q.select.find(s => s.getQuery() === asName(col));
@@ -1347,7 +1428,7 @@ export function makeQuery(
1347
1428
  /* Rename aggs to avoid collision with join cols */
1348
1429
  if(s.type === "aggregation") return asName(`agg_${s.alias}`) + " AS " + asName(s.alias);
1349
1430
  return asName(s.alias);
1350
- }).concat(q2.joins.map(j => asName(j.table))).join(", ");
1431
+ }).concat(q2.joins?.map(j => asName(j.table)) ?? []).join(", ");
1351
1432
 
1352
1433
  const _iiQ = makeQuery(
1353
1434
  _this,
@@ -1384,7 +1465,7 @@ export function makeQuery(
1384
1465
  }`
1385
1466
  ];
1386
1467
  return jres;
1387
- }))
1468
+ });
1388
1469
  }
1389
1470
 
1390
1471
  const getGroupBy = (rootSelectItems: SelectItem[], groupByItems: SelectItem[]): string => {
@@ -1464,7 +1545,7 @@ export function makeQuery(
1464
1545
 
1465
1546
  const rootSelectItems = q.select.filter(s => depth || s.selected)
1466
1547
 
1467
- let rootGroupBy: string;
1548
+ let rootGroupBy: string | undefined;
1468
1549
  if((selectParams.groupBy || aggs.length || q.joins && q.joins.length) && nonAggs.length){
1469
1550
  // console.log({ aggs, nonAggs, joins: q.joins })
1470
1551
  // rootGroupBy = getGroupBy(rootSelectItems, depth? rootSelectItems : nonAggs) + (aggs?.length? "" : ", ctid")
@@ -1528,7 +1609,7 @@ export function makeQuery(
1528
1609
  , `${q.where} `
1529
1610
  ])
1530
1611
  , `) ${makePrefAN(q)} `
1531
- , ...flat(joins.map((j, i)=> joinTables(q, j)))
1612
+ , ...joins.flatMap((j, i)=> joinTables(q, j))
1532
1613
  ])
1533
1614
  , ") t1"
1534
1615
  ])
@@ -82,10 +82,10 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
82
82
  throw `dbo.${table_name}.find or .count are missing or not allowed`;
83
83
  }
84
84
 
85
- const first_rows = await _this.dbo?.[table_name]?.find?.(_filter, { orderBy: (orderByAsc as OrderBy), select: sync_fields, limit, offset }, null, table_rules);
86
- const last_rows = first_rows.slice(-1);
85
+ const first_rows = await _this.dbo?.[table_name]?.find?.(_filter, { orderBy: (orderByAsc as OrderBy), select: sync_fields, limit, offset }, undefined, table_rules);
86
+ const last_rows = first_rows?.slice(-1);
87
87
  // const last_rows = await _this?.dbo[table_name]?.find?.(_filter, { orderBy: (orderByDesc as OrderBy), select: sync_fields, limit: 1, offset: -offset || 0 }, null, table_rules);
88
- const count = await _this.dbo?.[table_name]?.count?.(_filter, null, null, table_rules);
88
+ const count = await _this.dbo?.[table_name]?.count?.(_filter, undefined, undefined, table_rules);
89
89
 
90
90
  return { s_fr: first_rows?.[0] || null, s_lr: last_rows?.[0] || null, s_count: count }
91
91
  },
@@ -146,7 +146,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
146
146
  offset: offset || 0,
147
147
  limit: batch_size
148
148
  },
149
- null,
149
+ undefined,
150
150
  table_rules
151
151
  );
152
152
 
@@ -164,7 +164,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
164
164
  return Promise.all(deleted.map(async d => {
165
165
  const id_filter = filterObj(d, id_fields);
166
166
  try {
167
- await (_this.dbo[table_name] as TableHandler).delete(id_filter, undefined, null, table_rules);
167
+ await (_this.dbo[table_name] as TableHandler).delete(id_filter, undefined, undefined, table_rules);
168
168
  return 1;
169
169
  } catch (e){
170
170
  console.error(e)
@@ -195,7 +195,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
195
195
  select: [synced_field, ...id_fields] ,
196
196
  orderBy: (orderByAsc as OrderBy),
197
197
  },
198
- null,
198
+ undefined,
199
199
  table_rules
200
200
  );
201
201
  const inserts = data.filter(d => !existingData.find(ed => rowsIdsMatch(ed, d)));
@@ -216,7 +216,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
216
216
  if(table_rules.insert && inserts.length){
217
217
  // const qs = await tbl.insert(inserts, { fixIssues: true }, null, table_rules, { returnQuery: true });
218
218
  // console.log("inserts", qs)
219
- await tbl.insert(inserts, { fixIssues: true }, null, table_rules);
219
+ await tbl.insert(inserts, { fixIssues: true }, undefined, table_rules);
220
220
  inserted = inserts.length;
221
221
  }
222
222
 
@@ -308,7 +308,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
308
308
  sync_fields.map(key => {
309
309
  _filter[key] = c_lr[key];
310
310
  });
311
- server_row = await _this?.dbo?.[table_name]?.find?.(_filter, { select: sync_fields, limit: 1 }, null, table_rules);
311
+ server_row = await _this?.dbo?.[table_name]?.find?.(_filter, { select: sync_fields, limit: 1 }, undefined, table_rules);
312
312
  }
313
313
 
314
314
  // if(rowsFullyMatch(c_lr, s_lr)){ //c_count === s_count &&
@@ -337,7 +337,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
337
337
  console.error({ syncIssue: "sync.lr[synced_field] is greater than lastRow[synced_field]"})
338
338
  }
339
339
  sync.lr = lastRow;
340
- sync.last_synced = +sync.lr[synced_field];
340
+ sync.last_synced = +sync.lr?.[synced_field];
341
341
  }
342
342
  },
343
343
 
@@ -381,7 +381,7 @@ export const syncData = async (_this: PubSubManager, sync: SyncParams, clientDat
381
381
  });
382
382
  await Promise.all(to_delete.map(d => {
383
383
  deleted++;
384
- return (_this.dbo[table_name] as TableHandler).delete(filterObj(d, id_fields), { }, null, table_rules);
384
+ return (_this.dbo[table_name] as TableHandler).delete(filterObj(d, id_fields), { }, undefined, table_rules);
385
385
  }));
386
386
  sData = await getServerData(min_synced, offset);
387
387
  }
@@ -1,5 +1,5 @@
1
1
  import { AnyObject, asName } from "prostgles-types";
2
- import { DboBuilder, JoinInfo, LocalParams } from "./DboBuilder";
2
+ import { DboBuilder, getKeys, JoinInfo, LocalParams } from "./DboBuilder";
3
3
  import { asSQLIdentifier, ALLOWED_EXTENSION, ALLOWED_CONTENT_TYPE } from "./FileManager";
4
4
  import { DB, DbHandler, Prostgles } from "./Prostgles";
5
5
  import { asValue } from "./PubSubManager";
@@ -184,9 +184,15 @@ export type TableConfig<LANG_IDS = { en: 1 }> = {
184
184
  export default class TableConfigurator {
185
185
 
186
186
  config?: TableConfig;
187
- get dbo(): DbHandler { return this.prostgles.dbo };
188
- get db(): DB { return this.prostgles.db };
189
- sidKeyName: string;
187
+ get dbo(): DbHandler {
188
+ if(!this.prostgles.dbo) throw "this.prostgles.dbo missing"
189
+ return this.prostgles.dbo
190
+ };
191
+ get db(): DB {
192
+ if(!this.prostgles.db) throw "this.prostgles.db missing"
193
+ return this.prostgles.db
194
+ };
195
+ // sidKeyName: string;
190
196
  prostgles: Prostgles
191
197
 
192
198
  constructor(prostgles: Prostgles){
@@ -203,7 +209,7 @@ export default class TableConfigurator {
203
209
  }
204
210
 
205
211
  getColInfo = (params: {col: string, table: string}): ColExtraInfo | undefined => {
206
- return this.config[params.table]?.[params.col]?.info;
212
+ return (this.config as any)[params.table]?.[params.col]?.info;
207
213
  }
208
214
 
209
215
  checkColVal = (params: {col: string, table: string, value: any }): void => {
@@ -218,6 +224,7 @@ export default class TableConfigurator {
218
224
 
219
225
  getJoinInfo = (sourceTable: string, targetTable: string): JoinInfo | undefined => {
220
226
  if(
227
+ this.config &&
221
228
  sourceTable in this.config &&
222
229
  this.config[sourceTable] &&
223
230
  "columns" in this.config[sourceTable]
@@ -247,9 +254,10 @@ export default class TableConfigurator {
247
254
  async init(){
248
255
  let queries: string[] = [];
249
256
 
257
+ if(!this.config || !this.prostgles.pgp) throw "config or pgp missing"
250
258
  /* Create lookup tables */
251
259
  Object.keys(this.config).map(tableName => {
252
- const tableConf = this.config[tableName];
260
+ const tableConf = this.config![tableName];
253
261
  const { dropIfExists = false, dropIfExistsCascade = false } = tableConf;
254
262
  if(dropIfExistsCascade){
255
263
  queries.push(`DROP TABLE IF EXISTS ${tableName} CASCADE;`);
@@ -266,8 +274,8 @@ export default class TableConfigurator {
266
274
  );`);
267
275
 
268
276
  rows.map(row => {
269
- const values = this.prostgles.pgp.helpers.values(row)
270
- queries.push(this.prostgles.pgp.as.format(`INSERT INTO ${tableName} (${["id", ...keys].map(t => asName(t)).join(", ")}) ` + " VALUES ${values:raw} ;", { values} ))
277
+ const values = this.prostgles.pgp!.helpers.values(row)
278
+ queries.push(this.prostgles.pgp!.as.format(`INSERT INTO ${tableName} (${["id", ...keys].map(t => asName(t)).join(", ")}) ` + " VALUES ${values:raw} ;", { values} ))
271
279
  });
272
280
  // console.log("Created lookup table " + tableName)
273
281
  }
@@ -284,7 +292,7 @@ export default class TableConfigurator {
284
292
 
285
293
  /* Create referenced columns */
286
294
  await Promise.all(Object.keys(this.config).map(async tableName => {
287
- const tableConf = this.config[tableName];
295
+ const tableConf = this.config![tableName];
288
296
  if("columns" in tableConf){
289
297
  const getColDef = (name: string, colConf: ColumnConfig): string => {
290
298
  const colNameEsc = asName(name);
@@ -318,13 +326,13 @@ export default class TableConfigurator {
318
326
  }
319
327
  }
320
328
 
321
- const colDefs = [];
329
+ const colDefs: string[] = [];
322
330
  Object.keys(tableConf.columns).filter(c => !("joinDef" in tableConf.columns[c])).map(colName => {
323
331
  const colConf = tableConf.columns[colName];
324
332
 
325
333
  if(!this.dbo[tableName]){
326
334
  colDefs.push(getColDef(colName, colConf))
327
- } else if(!colDefs.length && !this.dbo[tableName].columns.find(c => colName === c.name)) {
335
+ } else if(!colDefs.length && !this.dbo[tableName].columns?.find(c => colName === c.name)) {
328
336
 
329
337
  if("references" in colConf && colConf.references){
330
338
 
@@ -354,13 +362,13 @@ export default class TableConfigurator {
354
362
  }
355
363
  }
356
364
  if("constraints" in tableConf && tableConf.constraints){
357
- Object.keys(tableConf.constraints).map(constraintName => {
358
- queries.push(`ALTER TABLE ${asName(tableName)} ADD CONSTRAINT ${asName(constraintName)} ${tableConf.constraints[constraintName]} ;`);
365
+ getKeys(tableConf.constraints).map(constraintName => {
366
+ queries.push(`ALTER TABLE ${asName(tableName)} ADD CONSTRAINT ${asName(constraintName)} ${tableConf.constraints![constraintName]} ;`);
359
367
  });
360
368
  }
361
369
  if("indexes" in tableConf && tableConf.indexes){
362
- Object.keys(tableConf.indexes).map(indexName => {
363
- const { concurrently, unique, using, definition, replace } = tableConf.indexes[indexName];
370
+ getKeys(tableConf.indexes).map(indexName => {
371
+ const { concurrently, unique, using, definition, replace } = tableConf.indexes![indexName];
364
372
  if(replace || typeof replace !== "boolean" && tableConf.replaceUniqueIndexes){
365
373
  queries.push(`DROP INDEX IF EXISTS ${asName(indexName)} ;`);
366
374
  }
@@ -1,4 +1,6 @@
1
- const shortestDistanceNode = (distances, visited) => {
1
+ import { AnyObject } from "prostgles-types";
2
+
3
+ const shortestDistanceNode = (distances: AnyObject, visited: AnyObject) => {
2
4
  let shortest = null;
3
5
 
4
6
  for (let node in distances) {
@@ -16,18 +18,18 @@ export type Graph = {
16
18
 
17
19
  export const findShortestPath = (graph: Graph, startNode: string, endNode: string): { distance: number, path: string[] } => {
18
20
  // establish object for recording distances from the start node
19
- let distances = {};
21
+ let distances: AnyObject = {};
20
22
  distances[endNode] = "Infinity";
21
23
  distances = Object.assign(distances, graph[startNode]);
22
24
 
23
25
  // track paths
24
- let parents = { endNode: null };
26
+ let parents: AnyObject = { endNode: null };
25
27
  for (let child in graph[startNode]) {
26
28
  parents[child] = startNode;
27
29
  }
28
30
 
29
31
  // track nodes that have already been visited
30
- let visited = [];
32
+ let visited: AnyObject = [];
31
33
 
32
34
  // find the nearest node
33
35
  let node = shortestDistanceNode(distances, visited);
package/lib/utils.ts CHANGED
@@ -1 +1,7 @@
1
- export { get } from "prostgles-types";
1
+ export { get } from "prostgles-types";
2
+
3
+
4
+ export function isObject(obj: any): obj is Record<string, any> {
5
+ return Boolean(obj && typeof obj === "object" && !Array.isArray(obj) );
6
+ }
7
+ export const isDefined = <T>(v: T | undefined | void): v is T => v !== undefined && v !== null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prostgles-server",
3
- "version": "2.0.144",
3
+ "version": "2.0.147",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -24,20 +24,19 @@
24
24
  },
25
25
  "homepage": "https://github.com/prostgles/prostgles-server-js#readme",
26
26
  "dependencies": {
27
- "@aws-sdk/client-s3": "^3.86.0",
28
- "aws-sdk": "^2.1134.0",
27
+ "@aws-sdk/client-s3": "^3.95.0",
28
+ "aws-sdk": "^2.1141.0",
29
29
  "bluebird": "^3.7.2",
30
30
  "file-type": "^16.5.3",
31
- "i": "^0.3.7",
32
- "npm": "^8.1.4",
33
- "pg-promise": "^10.9.5",
34
- "prostgles-types": "^1.5.123",
35
- "sharp": "^0.30.4"
31
+ "pg-promise": "^10.11.1",
32
+ "prostgles-types": "^1.5.124",
33
+ "sharp": "^0.30.5"
36
34
  },
37
35
  "devDependencies": {
38
36
  "@aws-sdk/types": "^3.34.0",
39
37
  "@types/bluebird": "^3.5.36",
40
38
  "@types/node": "^14.14.35",
39
+ "@types/sharp": "^0.30.2",
41
40
  "typescript": "^3.9.7"
42
41
  }
43
42
  }
@@ -1 +1 @@
1
- 23745
1
+ 57757