prostgles-server 2.0.145 → 2.0.148

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 +275 -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 +21 -8
  33. package/dist/QueryBuilder.d.ts.map +1 -1
  34. package/dist/QueryBuilder.js +179 -107
  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 -0
  46. package/dist/utils.d.ts.map +1 -1
  47. package/dist/utils.js +7 -0
  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 +265 -199
  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 +128 -55
  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 +7 -1
  62. package/package.json +8 -9
  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 +43 -6
  72. package/tests/isomorphic_queries.ts +41 -6
  73. package/tests/server/package-lock.json +29 -31
  74. package/tests/server/package.json +2 -2
  75. package/tests/server/tsconfig.json +2 -2
  76. 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,10 +143,13 @@ export type FunctionSpec = {
84
143
  */
85
144
  // returnsBoolean?: boolean;
86
145
 
146
+ /**
147
+ * Number of arguments expected
148
+ */
87
149
  numArgs: number;
88
150
 
89
151
  /**
90
- * If provided then the number of column names provided to the function must not be less than this
152
+ * If provided then the number of column names provided to the function (from getFields()) must not be less than this
91
153
  * By default every function is checked against numArgs
92
154
  */
93
155
  minCols?: number;
@@ -97,11 +159,13 @@ export type FunctionSpec = {
97
159
  * getFields: string[] -> used to validate user supplied field names. It will be fired before querying to validate against allowed columns
98
160
  * if not field names are used from arguments then return an empty array
99
161
  */
100
- getFields: (args: any[], allowedFields: string[]) => "*" | string[];
162
+ getFields: (args: any[]) => "*" | string[];
101
163
  /**
102
164
  * allowedFields passed for multicol functions (e.g.: $rowhash)
103
165
  */
104
166
  getQuery: (params: GetQueryArgs) => string;
167
+
168
+ returnType?: PG_COLUMN_UDT_DATA_TYPE;
105
169
  };
106
170
 
107
171
  const MAX_COL_NUM = 1600;
@@ -194,8 +258,10 @@ let PostGIS_Funcs: FunctionSpec[] = [
194
258
 
195
259
  if(!isPlainObject(arg2)) mErr();
196
260
  const col = allColumns.find(c => c.name === args[0]);
261
+ if(!col) throw new Error("Col not found: " + args[0])
197
262
 
198
- const { lat, lng, srid = 4326,
263
+ const {
264
+ lat, lng, srid = 4326,
199
265
  geojson, text, use_spheroid,
200
266
  distance, spheroid = 'SPHEROID["WGS 84",6378137,298.257223563]',
201
267
  debug
@@ -535,7 +601,7 @@ export const FUNCTIONS: FunctionSpec[] = [
535
601
  second: "minute"
536
602
  };
537
603
 
538
- 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)})`;
539
605
  // console.log(res);
540
606
  return res;
541
607
  }
@@ -602,7 +668,7 @@ export const FUNCTIONS: FunctionSpec[] = [
602
668
  } as FunctionSpec)),
603
669
 
604
670
  /* Basic 1 arg col funcs */
605
- ...["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 => ({
606
672
  name: "$" + funcName,
607
673
  type: "function",
608
674
  numArgs: 1,
@@ -613,6 +679,27 @@ export const FUNCTIONS: FunctionSpec[] = [
613
679
  }
614
680
  } as FunctionSpec)),
615
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)),
616
703
 
617
704
  /* pgcrypto funcs */
618
705
  ...["crypt"].map(funcName => ({
@@ -652,7 +739,7 @@ export const FUNCTIONS: FunctionSpec[] = [
652
739
  numArgs: 1,
653
740
  minCols: 0,
654
741
  singleColArg: false,
655
- 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
656
743
  getQuery: ({ allowedFields, args, tableAlias }) => {
657
744
  let value = asValue(args[0]);
658
745
  if(typeof value !== "string") throw "expecting string argument";
@@ -769,7 +856,7 @@ export const FUNCTIONS: FunctionSpec[] = [
769
856
  let _cols = validCols.filter(c =>
770
857
  /** Exclude numeric columns when the search tern contains a character */
771
858
  !hasChars ||
772
- postgresToTsType(c.colInfo.udt_name) !== "number"
859
+ postgresToTsType(c.colInfo!.udt_name) !== "number"
773
860
  );
774
861
 
775
862
  /** This will break GROUP BY (non-integer constant in GROUP BY) */
@@ -955,28 +1042,16 @@ export class SelectItemBuilder {
955
1042
  this.select.push(item);
956
1043
  }
957
1044
 
958
- private addFunctionByName = (funcName: string, args: any[], alias: string) => {
959
- const funcDef = this.functions.find(f => f.name === funcName);
960
- if(!funcDef) {
961
- const sf = this.functions.filter(f => f.name.toLowerCase().slice(1).startsWith(funcName.toLowerCase())).sort((a, b) => (a.name.length - b.name.length));
962
- const hint = (sf.length? `. \n Maybe you meant: \n | ${sf.map(s => s.name + " " + (s.description || "")).join(" \n | ")} ?` : "");
963
- throw "\n Function " + funcName + " does not exist or is not allowed " + hint;
964
- }
965
- this.addFunction(funcDef, args, alias);
966
- }
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
+ });
967
1050
 
968
- private addFunction = (funcDef: FunctionSpec, args: any[], alias: string) => {
969
- if(funcDef.numArgs) {
970
- const fields = funcDef.getFields(args, this.allowedFields);
971
- if(funcDef.minCols !== 0 && fields !== "*" && Array.isArray(fields) && !fields.length ){
972
- console.log(fields)
973
- throw `\n Function "${funcDef.name}" expects at least a field name but has not been provided with one`;
974
- }
975
- }
976
1051
  this.addItem({
977
1052
  type: funcDef.type,
978
1053
  alias,
979
- getFields: () => funcDef.getFields(args, this.allowedFields),
1054
+ getFields: () => funcDef.getFields(args),
980
1055
  getQuery: (tableAlias?: string) => funcDef.getQuery({ allColumns: this.columns, allowedFields: this.allowedFields, args, tableAlias,
981
1056
  ctidField: undefined,
982
1057
 
@@ -1054,7 +1129,7 @@ export class SelectItemBuilder {
1054
1129
 
1055
1130
  } else {
1056
1131
  await Promise.all(selectKeys.map(async key => {
1057
- const val = userSelect[key],
1132
+ const val: any = userSelect[key as keyof typeof userSelect],
1058
1133
  throwErr = (extraErr: string = "") => {
1059
1134
  console.trace(extraErr)
1060
1135
  throw "Unexpected select -> " + JSON.stringify({ [key]: val }) + "\n" + extraErr;
@@ -1092,14 +1167,13 @@ export class SelectItemBuilder {
1092
1167
  }
1093
1168
  funcName = val;
1094
1169
  args = [key];
1170
+
1171
+ /** Function full notation { $funcName: ["colName", ...args] } */
1095
1172
  } else {
1096
- const callKeys = Object.keys(val);
1097
- 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 });
1098
- funcName = callKeys[0];
1099
- args = val[funcName];
1173
+ ({ funcName, args } = parseFunctionObject(val));
1100
1174
  }
1101
1175
 
1102
- this.addFunctionByName(funcName, args, key);
1176
+ this.addFunction(funcName, args, key);
1103
1177
 
1104
1178
  /* Join */
1105
1179
  } else {
@@ -1122,10 +1196,10 @@ export class SelectItemBuilder {
1122
1196
  export async function getNewQuery(
1123
1197
  _this: TableHandler,
1124
1198
  filter: Filter,
1125
- selectParams: SelectParams & { alias?: string },
1199
+ selectParams: (SelectParams & { alias?: string }) = {},
1126
1200
  param3_unused = null,
1127
- tableRules: TableRule,
1128
- localParams: LocalParams,
1201
+ tableRules: TableRule | undefined,
1202
+ localParams: LocalParams | undefined,
1129
1203
  columns: ColumnInfo[],
1130
1204
  ): Promise<NewQuery> {
1131
1205
 
@@ -1153,7 +1227,6 @@ export async function getNewQuery(
1153
1227
 
1154
1228
  // const all_colnames = _this.column_names.slice(0).concat(COMPUTED_FIELDS.map(c => c.name));
1155
1229
 
1156
- selectParams = selectParams || {};
1157
1230
  const { select: userSelect = "*" } = selectParams,
1158
1231
  // allCols = _this.column_names.slice(0),
1159
1232
  // allFieldsIncludingComputed = allCols.concat(COMPUTED_FIELDS.map(c => c.name)),
@@ -1168,10 +1241,10 @@ export async function getNewQuery(
1168
1241
  // console.log({ key, val })
1169
1242
  let j_filter: Filter = {},
1170
1243
  j_selectParams: SelectParams = {},
1171
- j_path: string[],
1172
- j_alias: string,
1173
- j_tableRules: TableRule,
1174
- j_table: string,
1244
+ j_path: string[] | undefined,
1245
+ j_alias: string | undefined,
1246
+ j_tableRules: TableRule | undefined,
1247
+ j_table: string | undefined,
1175
1248
  j_isLeftJoin: boolean = true;
1176
1249
 
1177
1250
  if(val === "*"){
@@ -1207,7 +1280,7 @@ export async function getNewQuery(
1207
1280
  j_table = key;
1208
1281
  }
1209
1282
  }
1210
-
1283
+ if(!j_table) throw "j_table missing"
1211
1284
  const _thisJoinedTable: any = _this.dboBuilder.dbo[j_table];
1212
1285
  if(!_thisJoinedTable) {
1213
1286
  throw `Joined table ${JSON.stringify(j_table)} is disallowed or inexistent \nOr you've forgot to put the function arguments into an array`;
@@ -1216,7 +1289,7 @@ export async function getNewQuery(
1216
1289
  let isLocal = true;
1217
1290
  if(localParams && (localParams.socket || localParams.httpReq)){
1218
1291
  isLocal = false;
1219
- 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 });
1220
1293
  }
1221
1294
 
1222
1295
  if(isLocal || j_tableRules){
@@ -1270,7 +1343,7 @@ export async function getNewQuery(
1270
1343
  where,
1271
1344
  // having: cond.having,
1272
1345
  limit: _this.prepareLimitQuery(selectParams.limit, p),
1273
- orderBy: [_this.prepareSort(selectParams.orderBy, allowedFields, selectParams.alias, null, select)],
1346
+ orderBy: [_this.prepareSort(selectParams.orderBy, allowedFields, selectParams.alias, undefined, select)],
1274
1347
  offset: _this.prepareOffsetQuery(selectParams.offset)
1275
1348
  } as NewQuery;
1276
1349
 
@@ -1287,19 +1360,19 @@ export function makeQuery(
1287
1360
  q: NewQuery,
1288
1361
  depth: number = 0,
1289
1362
  joinFields: string[] = [],
1290
- selectParams: SelectParams,
1363
+ selectParams: SelectParams = {},
1291
1364
  ): string {
1292
1365
  const PREF = `prostgles`,
1293
1366
  joins = q.joins || [],
1294
1367
  // aggs = q.aggs || [],
1295
1368
  makePref = (q: NewQuery) => !q.tableAlias? q.table : `${q.tableAlias || ""}_${q.table}`,
1296
- makePrefANON = (joinAlias, table) => asName(!joinAlias? table : `${joinAlias || ""}_${table}`),
1369
+ makePrefANON = (joinAlias: string | undefined, table: string) => asName(!joinAlias? table : `${joinAlias || ""}_${table}`),
1297
1370
  makePrefAN = (q: NewQuery) => asName(makePref(q));
1298
1371
 
1299
- const indentLine = (numInd, str, indentStr = " ") => new Array(numInd).fill(indentStr).join("") + str;
1300
- const indStr = (numInd, str: string) => str.split("\n").map(s => indentLine(numInd, s)).join("\n");
1301
- const indjArr = (numInd, strArr: string[], indentStr = " "): string[] => strArr.map(str => indentLine(numInd, str) );
1302
- 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);
1303
1376
  const selectArrComma = (strArr: string[]): string[] => strArr.map((s, i, arr)=> s + (i < arr.length - 1? " , " : " "));
1304
1377
  const prefJCAN = (q: NewQuery, str: string) => asName(`${q.tableAlias || q.table}_${PREF}_${str}`);
1305
1378
 
@@ -1308,7 +1381,7 @@ export function makeQuery(
1308
1381
  const joinInfo = _this.getJoins(q1.table, q2.table, q2.$path, true);
1309
1382
  const paths = joinInfo.paths;
1310
1383
 
1311
- return flat(paths.map(({ table, on }, i) => {
1384
+ return paths.flatMap(({ table, on }, i) => {
1312
1385
  const getColName = (col: string, q: NewQuery) => {
1313
1386
  if(table === q.table){
1314
1387
  const colFromSelect = q.select.find(s => s.getQuery() === asName(col));
@@ -1355,7 +1428,7 @@ export function makeQuery(
1355
1428
  /* Rename aggs to avoid collision with join cols */
1356
1429
  if(s.type === "aggregation") return asName(`agg_${s.alias}`) + " AS " + asName(s.alias);
1357
1430
  return asName(s.alias);
1358
- }).concat(q2.joins.map(j => asName(j.table))).join(", ");
1431
+ }).concat(q2.joins?.map(j => asName(j.table)) ?? []).join(", ");
1359
1432
 
1360
1433
  const _iiQ = makeQuery(
1361
1434
  _this,
@@ -1392,7 +1465,7 @@ export function makeQuery(
1392
1465
  }`
1393
1466
  ];
1394
1467
  return jres;
1395
- }))
1468
+ });
1396
1469
  }
1397
1470
 
1398
1471
  const getGroupBy = (rootSelectItems: SelectItem[], groupByItems: SelectItem[]): string => {
@@ -1472,7 +1545,7 @@ export function makeQuery(
1472
1545
 
1473
1546
  const rootSelectItems = q.select.filter(s => depth || s.selected)
1474
1547
 
1475
- let rootGroupBy: string;
1548
+ let rootGroupBy: string | undefined;
1476
1549
  if((selectParams.groupBy || aggs.length || q.joins && q.joins.length) && nonAggs.length){
1477
1550
  // console.log({ aggs, nonAggs, joins: q.joins })
1478
1551
  // rootGroupBy = getGroupBy(rootSelectItems, depth? rootSelectItems : nonAggs) + (aggs?.length? "" : ", ctid")
@@ -1536,7 +1609,7 @@ export function makeQuery(
1536
1609
  , `${q.where} `
1537
1610
  ])
1538
1611
  , `) ${makePrefAN(q)} `
1539
- , ...flat(joins.map((j, i)=> joinTables(q, j)))
1612
+ , ...joins.flatMap((j, i)=> joinTables(q, j))
1540
1613
  ])
1541
1614
  , ") t1"
1542
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.145",
3
+ "version": "2.0.148",
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",
41
- "typescript": "^3.9.7"
39
+ "@types/sharp": "^0.30.2",
40
+ "typescript": "^4.7.2"
42
41
  }
43
42
  }
@@ -1 +1 @@
1
- 7614
1
+ 59576