prostgles-server 2.0.118 → 2.0.122

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/DboBuilder.ts CHANGED
@@ -8,6 +8,7 @@ import * as Bluebird from "bluebird";
8
8
  // declare global { export interface Promise<T> extends Bluebird<T> {} }
9
9
 
10
10
  import * as pgPromise from 'pg-promise';
11
+ const {ParameterizedQuery: PQ} = require('pg-promise');
11
12
  import pg = require('pg-promise/typescript/pg-subset');
12
13
  import {
13
14
  ColumnInfo, ValidatedColumnInfo, FieldFilter, SelectParams, SubscribeParams, OrderBy, InsertParams, UpdateParams, DeleteParams, SQLOptions,
@@ -1565,7 +1566,7 @@ export class ViewHandler {
1565
1566
  const nullOrder = nulls? ` NULLS ${nulls === "first"? " FIRST " : " LAST "}` : "";
1566
1567
  let colKey = (index > 0 && !nullEmpty)? index : [tableAlias, key].filter(v => v).map(asName).join(".");
1567
1568
  if(nullEmpty){
1568
- colKey = `nullif(trim(${colKey}), '')`
1569
+ colKey = `nullif(trim(${colKey}::text), '')`
1569
1570
  }
1570
1571
 
1571
1572
  const res = `${colKey} ${orderType} ${nullOrder}`;
@@ -1849,6 +1850,7 @@ export class TableHandler extends ViewHandler {
1849
1850
  // const { subOne = false } = localParams || {};
1850
1851
 
1851
1852
  if(!localFunc) {
1853
+ if(!this.dboBuilder.prostgles.isSuperUser) throw "Subscribe no possible. 1853";
1852
1854
  return await this.find(filter, { ...selectParams, limit: 0 }, null, table_rules, localParams)
1853
1855
  .then(async isValid => {
1854
1856
 
@@ -2703,19 +2705,23 @@ export class DboBuilder {
2703
2705
 
2704
2706
  if(this.prostgles.opts.watchSchema && this.prostgles.opts.watchSchemaType === "events"){
2705
2707
  if(!this.prostgles.isSuperUser){
2706
- console.warn(`watchSchemaType "events" cannot be used due because db user is not a superuser. Will fallback to watchSchemaType "queries" `)
2708
+ console.warn(`watchSchemaType "events" cannot be used because db user is not a superuser. Will fallback to watchSchemaType "queries" `)
2707
2709
  } else {
2708
2710
  onSchemaChange = (event: { command: string; query: string }) => {
2709
2711
  this.prostgles.onSchemaChange(event)
2710
2712
  }
2711
2713
  }
2712
2714
  }
2713
- this._pubSubManager = await PubSubManager.create({
2714
- dboBuilder: this,
2715
- db: this.db,
2716
- dbo: this.dbo as unknown as DbHandler,
2717
- onSchemaChange
2718
- });
2715
+
2716
+ if(this.prostgles.isSuperUser){
2717
+ console.warn(`subscribe and sync cannot be used because db user is not a superuser `)
2718
+ this._pubSubManager = await PubSubManager.create({
2719
+ dboBuilder: this,
2720
+ db: this.db,
2721
+ dbo: this.dbo as unknown as DbHandler,
2722
+ onSchemaChange
2723
+ });
2724
+ }
2719
2725
  }
2720
2726
 
2721
2727
  return this._pubSubManager;
@@ -3001,7 +3007,8 @@ export type TxCB = {
3001
3007
  let DATA_TYPES = !needType? [] : await this.db.any("SELECT oid, typname FROM pg_type");
3002
3008
  let USER_TABLES = !needType? [] : await this.db.any("SELECT relid, relname FROM pg_catalog.pg_statio_user_tables");
3003
3009
 
3004
- this.dbo.sql = async (query: string, params: any, options: SQLOptions, localParams?: LocalParams) => {
3010
+ this.dbo.sql = async (q: string, params: any, options: SQLOptions, localParams?: LocalParams) => {
3011
+ let query = q;
3005
3012
  const canRunSQL = async (localParams: LocalParams) => {
3006
3013
  if(!localParams) return true;
3007
3014
 
@@ -3027,6 +3034,10 @@ export type TxCB = {
3027
3034
  }
3028
3035
  } else if(this.db) {
3029
3036
 
3037
+ if(returnType === "arrayMode"){
3038
+ query = new PQ({ text: pgp.as.format(query, params), rowMode: "array" });
3039
+ }
3040
+
3030
3041
  let qres = await this.db.result(query, params)
3031
3042
  const { duration, fields, rows, command } = qres;
3032
3043
 
package/lib/Filtering.ts CHANGED
@@ -40,7 +40,7 @@ export const parseFilterItem = (args: ParseFilterItemArgs): string => {
40
40
  // parseExistsFilter()
41
41
  }
42
42
 
43
- let selItem;
43
+ let selItem: SelectItem | undefined;
44
44
  if(select) selItem = select.find(s => fKey === s.alias);
45
45
  let rightF: FilterDataType = _f[fKey];
46
46
 
@@ -191,6 +191,11 @@ export const parseFilterItem = (args: ParseFilterItemArgs): string => {
191
191
  }
192
192
  // console.log({ fOpType, fVal, sOpType })
193
193
 
194
+ /** JSON cannot be compared so we'll cast it to TEXT */
195
+ if(selItem?.column_udt_type === "json" || ["$ilike", "$like"].includes(fOpType)){
196
+ leftQ += "::TEXT "
197
+ }
198
+
194
199
  /** st_makeenvelope */
195
200
  if(GeomFilterKeys.includes(fOpType) && sOpType && GeomFilter_Funcs.includes(sOpType)){
196
201
  /** If leftQ is geography then this err can happen: 'Antipodal (180 degrees long) edge detected!' */
@@ -218,11 +223,13 @@ export const parseFilterItem = (args: ParseFilterItemArgs): string => {
218
223
  return leftQ + " <= " + parseRightVal(fVal);
219
224
 
220
225
  } else if(["$in"].includes(fOpType)){
226
+ if(!fVal?.length) throw "$in filter array is empty";
221
227
  let res = leftQ + " IN " + parseRightVal(fVal, "csv");
222
228
  if(fVal.includes(null)) res += ` OR ${leftQ} IS NULL `
223
229
  return res;
224
230
 
225
231
  } else if(["$nin"].includes(fOpType)){
232
+ if(!fVal?.length) throw "$nin filter array is empty";
226
233
  let res = leftQ + " NOT IN " + parseRightVal(fVal, "csv");
227
234
  if(fVal.includes(null)) res += ` AND ${leftQ} IS NOT NULL `
228
235
  return res;
@@ -234,10 +241,10 @@ export const parseFilterItem = (args: ParseFilterItemArgs): string => {
234
241
  return leftQ + " BETWEEN " + asValue(fVal[0]) + " AND " + asValue(fVal[1]);
235
242
 
236
243
  } else if(["$ilike"].includes(fOpType)){
237
- return leftQ + "::TEXT ILIKE " + asValue(fVal);
244
+ return leftQ + " ILIKE " + asValue(fVal);
238
245
 
239
246
  } else if(["$like"].includes(fOpType)){
240
- return leftQ + "::TEXT LIKE " + asValue(fVal);
247
+ return leftQ + " LIKE " + asValue(fVal);
241
248
 
242
249
  /* MAYBE TEXT OR MAYBE ARRAY */
243
250
  } else if(["@>", "<@", "$contains", "$containedBy", "&&", "@@"].includes(fOpType)){
@@ -253,7 +260,7 @@ export const parseFilterItem = (args: ParseFilterItemArgs): string => {
253
260
  /* FTSQuery */
254
261
  } else if(["@@"].includes(fOpType) && TextFilter_FullTextSearchFilterKeys.includes(sOpType)) {
255
262
  let lq = `to_tsvector(${leftQ}::text)`;
256
- if(selItem && selItem.columnDataType === "tsvector") lq = leftQ;
263
+ if(selItem && selItem.columnPGDataType === "tsvector") lq = leftQ;
257
264
 
258
265
  let res = `${lq} ${operand} ` + `${sOpType}${parseRightVal(sVal, "csv")}`;
259
266
 
package/lib/Prostgles.ts CHANGED
@@ -544,7 +544,7 @@ export class Prostgles<DBO = DbHandler> {
544
544
  if(watchSchema && this.loaded){
545
545
  console.log("Schema changed");
546
546
  const { query } = event;
547
- if(query && query.includes(PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID)){
547
+ if(typeof query === "string" && query.includes(PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID)){
548
548
  console.log("Schema change event excluded from triggers due to EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID");
549
549
  return;
550
550
  }
@@ -944,70 +944,6 @@ export class Prostgles<DBO = DbHandler> {
944
944
  }).catch(err => {
945
945
  makeSocketError(cb, err);
946
946
  })
947
-
948
- // if(!(await canRunSQL())) {
949
- // cb("Dissallowed", null);
950
- // return;
951
- // }
952
-
953
- // const { returnType }: SQLOptions = options || ({} as any);
954
- // if(returnType === "noticeSubscription"){
955
-
956
- // const sub = await this.dbEventsManager.addNotice(socket);
957
-
958
- // cb(null, sub);
959
- // } else if(returnType === "statement"){
960
- // try {
961
- // cb(null, pgp.as.format(query, params));
962
- // } catch (err){
963
- // cb(err.toString());
964
- // }
965
- // } else if(db) {
966
-
967
- // db.result(query, params)
968
- // .then(async (qres: any) => {
969
- // const { duration, fields, rows, command } = qres;
970
-
971
- // if(command === "LISTEN"){
972
- // const sub = await this.dbEventsManager.addNotify(query, socket);
973
-
974
- // cb(null, sub);
975
-
976
- // } else if(returnType === "rows") {
977
- // cb(null, rows);
978
-
979
- // } else if(returnType === "row") {
980
- // cb(null, rows[0]);
981
-
982
- // } else if(returnType === "value") {
983
- // cb(null, Object.values(rows[0])[0]);
984
-
985
- // } else if(returnType === "values") {
986
- // cb(null, rows.map(r => Object.values(r[0])));
987
-
988
- // } else {
989
- // if(fields && DATA_TYPES.length){
990
- // qres.fields = fields.map(f => {
991
- // const dataType = DATA_TYPES.find(dt => +dt.oid === +f.dataTypeID),
992
- // tableName = USER_TABLES.find(t => +t.relid === +f.tableID);
993
-
994
- // return {
995
- // ...f,
996
- // ...(dataType? { dataType: dataType.typname } : {}),
997
- // ...(tableName? { tableName: tableName.relname } : {}),
998
- // }
999
- // });
1000
- // }
1001
- // cb(null, qres)
1002
- // }
1003
-
1004
- // })
1005
- // .catch(err => {
1006
- // makeSocketError(cb, err);
1007
- // // Promise.reject(err.toString());
1008
- // });
1009
-
1010
- // } else console.error("db missing");
1011
947
  });
1012
948
  if(db){
1013
949
  // let allTablesViews = await db.any(STEP2_GET_ALL_TABLES_AND_COLUMNS);
@@ -6,7 +6,7 @@
6
6
 
7
7
  import { pgp, Filter, LocalParams, isPlainObject, TableHandler, ViewHandler, postgresToTsType } from "./DboBuilder";
8
8
  import { TableRule, flat } from "./Prostgles";
9
- import { SelectParamsBasic as SelectParams, isEmpty, FieldFilter, asName, TextFilter_FullTextSearchFilterKeys, TS_PG_Types, ColumnInfo } from "prostgles-types";
9
+ import { SelectParamsBasic as SelectParams, isEmpty, FieldFilter, asName, TextFilter_FullTextSearchFilterKeys, TS_PG_Types, ColumnInfo, PG_COLUMN_UDT_DATA_TYPE } from "prostgles-types";
10
10
  import { get } from "./utils";
11
11
 
12
12
 
@@ -15,6 +15,7 @@ export type SelectItem = {
15
15
  getFields: (args?: any[]) => string[] | "*";
16
16
  getQuery: (tableAlias?: string) => string;
17
17
  columnPGDataType?: string;
18
+ column_udt_type?: PG_COLUMN_UDT_DATA_TYPE;
18
19
  // columnName?: string; /* Must only exist if type "column" ... dissalow aliased columns? */
19
20
  alias: string;
20
21
  selected: boolean;
@@ -422,6 +423,17 @@ export const FUNCTIONS: FunctionSpec[] = [
422
423
  return pgp.as.format("LEFT(" + asNameAlias(args[0], tableAlias) + ", $1)", [args[1]]);
423
424
  }
424
425
  },
426
+ {
427
+ name: "$unnest_words",
428
+ description: ` :[column_name, number] -> substring`,
429
+ type: "function",
430
+ numArgs: 1,
431
+ singleColArg: true,
432
+ getFields: (args: any[]) => [args[0]],
433
+ getQuery: ({ allowedFields, args, tableAlias }) => {
434
+ return pgp.as.format("unnest(string_to_array(" + asNameAlias(args[0], tableAlias) + "::TEXT , ' '))");//, [args[1]]
435
+ }
436
+ },
425
437
  {
426
438
  name: "$right",
427
439
  description: ` :[column_name, number] -> substring`,
@@ -945,6 +957,7 @@ export class SelectItemBuilder {
945
957
  this.addItem({
946
958
  type: "column",
947
959
  columnPGDataType: colDef?.data_type,
960
+ column_udt_type: colDef?.udt_name,
948
961
  alias,
949
962
  getQuery: () => asName(fieldName),
950
963
  getFields: () => [fieldName],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prostgles-server",
3
- "version": "2.0.118",
3
+ "version": "2.0.122",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -31,7 +31,7 @@
31
31
  "i": "^0.3.7",
32
32
  "npm": "^8.1.4",
33
33
  "pg-promise": "^10.9.5",
34
- "prostgles-types": "^1.5.121",
34
+ "prostgles-types": "^1.5.122",
35
35
  "sharp": "^0.29.3"
36
36
  },
37
37
  "devDependencies": {
@@ -1 +1 @@
1
- 14900
1
+ 3044
@@ -11,7 +11,7 @@
11
11
  "dependencies": {
12
12
  "@types/node": "^14.14.16",
13
13
  "@types/socket.io-client": "^1.4.35",
14
- "prostgles-client": "^1.5.130",
14
+ "prostgles-client": "^1.5.131",
15
15
  "prostgles-types": "^1.5.68",
16
16
  "socket.io-client": "^4.2.0"
17
17
  }
@@ -114,17 +114,17 @@
114
114
  "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
115
115
  },
116
116
  "node_modules/prostgles-client": {
117
- "version": "1.5.130",
118
- "resolved": "https://registry.npmjs.org/prostgles-client/-/prostgles-client-1.5.130.tgz",
119
- "integrity": "sha512-Dd3b1JY7avcZ2oS5avCQ5KyzLaQTaYDzDE/q9bIiY7R5JJsesGKoRsqJISuNWyGYeVCY93n+r/EN88v0Jsj48A==",
117
+ "version": "1.5.131",
118
+ "resolved": "https://registry.npmjs.org/prostgles-client/-/prostgles-client-1.5.131.tgz",
119
+ "integrity": "sha512-LoNNxarPTtJJNZFyJW5U3LbyBMbE+pKSVsAcojiLJQdEpmxlzJ1zPqQf+711eKJ+2sE/9/gc+UeHh8SWQBaGTg==",
120
120
  "dependencies": {
121
- "prostgles-types": "^1.5.121"
121
+ "prostgles-types": "^1.5.122"
122
122
  }
123
123
  },
124
124
  "node_modules/prostgles-types": {
125
- "version": "1.5.121",
126
- "resolved": "https://registry.npmjs.org/prostgles-types/-/prostgles-types-1.5.121.tgz",
127
- "integrity": "sha512-9fzF/3tISjv1P6B0uV2ubZRKqblUvDG8K7+9INdcR8di2UOVD2vONgCgvFe7ZH12FyUC5q1OM1PUm41dgo9cqQ=="
125
+ "version": "1.5.122",
126
+ "resolved": "https://registry.npmjs.org/prostgles-types/-/prostgles-types-1.5.122.tgz",
127
+ "integrity": "sha512-YC9Glu2/uj5IeOb2/vBzz4toHTCYWl/3xDJr/gcLIORJzUq97R0a055+Zgj5afoCaYBVff61yjgujfqiTrxFBA=="
128
128
  },
129
129
  "node_modules/socket.io-client": {
130
130
  "version": "4.2.0",
@@ -275,17 +275,17 @@
275
275
  "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
276
276
  },
277
277
  "prostgles-client": {
278
- "version": "1.5.130",
279
- "resolved": "https://registry.npmjs.org/prostgles-client/-/prostgles-client-1.5.130.tgz",
280
- "integrity": "sha512-Dd3b1JY7avcZ2oS5avCQ5KyzLaQTaYDzDE/q9bIiY7R5JJsesGKoRsqJISuNWyGYeVCY93n+r/EN88v0Jsj48A==",
278
+ "version": "1.5.131",
279
+ "resolved": "https://registry.npmjs.org/prostgles-client/-/prostgles-client-1.5.131.tgz",
280
+ "integrity": "sha512-LoNNxarPTtJJNZFyJW5U3LbyBMbE+pKSVsAcojiLJQdEpmxlzJ1zPqQf+711eKJ+2sE/9/gc+UeHh8SWQBaGTg==",
281
281
  "requires": {
282
- "prostgles-types": "^1.5.121"
282
+ "prostgles-types": "^1.5.122"
283
283
  }
284
284
  },
285
285
  "prostgles-types": {
286
- "version": "1.5.121",
287
- "resolved": "https://registry.npmjs.org/prostgles-types/-/prostgles-types-1.5.121.tgz",
288
- "integrity": "sha512-9fzF/3tISjv1P6B0uV2ubZRKqblUvDG8K7+9INdcR8di2UOVD2vONgCgvFe7ZH12FyUC5q1OM1PUm41dgo9cqQ=="
286
+ "version": "1.5.122",
287
+ "resolved": "https://registry.npmjs.org/prostgles-types/-/prostgles-types-1.5.122.tgz",
288
+ "integrity": "sha512-YC9Glu2/uj5IeOb2/vBzz4toHTCYWl/3xDJr/gcLIORJzUq97R0a055+Zgj5afoCaYBVff61yjgujfqiTrxFBA=="
289
289
  },
290
290
  "socket.io-client": {
291
291
  "version": "4.2.0",
@@ -14,7 +14,7 @@
14
14
  "dependencies": {
15
15
  "@types/node": "^14.14.16",
16
16
  "@types/socket.io-client": "^1.4.35",
17
- "prostgles-client": "^1.5.130",
17
+ "prostgles-client": "^1.5.131",
18
18
  "prostgles-types": "^1.5.68",
19
19
  "socket.io-client": "^4.2.0"
20
20
  }
@@ -6,12 +6,16 @@ async function client_only(db, auth, log, methods) {
6
6
  const testRealtime = () => {
7
7
  log("Started testRealtime");
8
8
  return new Promise(async (resolve, reject) => {
9
+ var _a, _b;
9
10
  /* METHODS */
10
11
  const t222 = await methods.get();
11
12
  assert_1.strict.equal(t222, 222, "methods.get() failed");
12
13
  /* RAWSQL */
13
14
  const sqlStatement = await db.sql("SELECT $1", [1], { returnType: "statement" });
14
15
  assert_1.strict.equal(sqlStatement, "SELECT 1", "db.sql statement query failed");
16
+ const arrayMode = await db.sql("SELECT 1 as a, 2 as a", undefined, { returnType: "arrayMode" });
17
+ assert_1.strict.equal((_a = arrayMode.rows) === null || _a === void 0 ? void 0 : _a[0].join("."), "1.2", "db.sql statement arrayMode failed");
18
+ assert_1.strict.equal((_b = arrayMode.fields) === null || _b === void 0 ? void 0 : _b.map(f => f.name).join("."), "a.a", "db.sql statement arrayMode failed");
15
19
  const select1 = await db.sql("SELECT $1 as col1", [1], { returnType: "rows" });
16
20
  assert_1.strict.deepStrictEqual(select1[0], { col1: 1 }, "db.sql justRows query failed");
17
21
  const fullResult = await db.sql("SELECT $1 as col1", [1]);
@@ -17,6 +17,10 @@ export default async function client_only(db: DBHandlerClient, auth: Auth, log:
17
17
  const sqlStatement = await db.sql("SELECT $1", [1], { returnType: "statement" });
18
18
  assert.equal(sqlStatement, "SELECT 1", "db.sql statement query failed");
19
19
 
20
+ const arrayMode = await db.sql("SELECT 1 as a, 2 as a", undefined, { returnType: "arrayMode" });
21
+ assert.equal(arrayMode.rows?.[0].join("."), "1.2", "db.sql statement arrayMode failed");
22
+ assert.equal(arrayMode.fields?.map(f => f.name).join("."), "a.a", "db.sql statement arrayMode failed");
23
+
20
24
  const select1 = await db.sql("SELECT $1 as col1", [1], { returnType: "rows" });
21
25
  assert.deepStrictEqual(select1[0], { col1: 1 }, "db.sql justRows query failed");
22
26
 
@@ -174,6 +174,16 @@ async function isomorphic(db) {
174
174
  }
175
175
  ]);
176
176
  });
177
+ await tryRun("$unnest_words", async () => {
178
+ const res = await db.various.find({}, { returnType: "values", select: { name: "$unnest_words" } });
179
+ console.trace(res);
180
+ assert_1.strict.deepStrictEqual(res, [
181
+ 'abc9',
182
+ 'abc1',
183
+ 'abc81',
184
+ 'here'
185
+ ]);
186
+ });
177
187
  /**
178
188
  * Group by/Distinct
179
189
  */
@@ -172,6 +172,17 @@ export default async function isomorphic(db: Partial<DbHandler> | Partial<DBHand
172
172
  );
173
173
  });
174
174
 
175
+ await tryRun("$unnest_words", async () => {
176
+ const res = await db.various.find({}, { returnType: "values", select: { name: "$unnest_words" } });
177
+ console.trace(res)
178
+ assert.deepStrictEqual( res, [
179
+ 'abc9',
180
+ 'abc1',
181
+ 'abc81',
182
+ 'here'
183
+ ]);
184
+ })
185
+
175
186
  /**
176
187
  * Group by/Distinct
177
188
  */
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "../..": {
25
25
  "name": "prostgles-server",
26
- "version": "2.0.117",
26
+ "version": "2.0.121",
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@aws-sdk/client-s3": "^3.32.0",
@@ -33,7 +33,7 @@
33
33
  "i": "^0.3.7",
34
34
  "npm": "^8.1.4",
35
35
  "pg-promise": "^10.9.5",
36
- "prostgles-types": "^1.5.121",
36
+ "prostgles-types": "^1.5.122",
37
37
  "sharp": "^0.29.3"
38
38
  },
39
39
  "devDependencies": {
@@ -1456,7 +1456,7 @@
1456
1456
  "i": "^0.3.7",
1457
1457
  "npm": "^8.1.4",
1458
1458
  "pg-promise": "^10.9.5",
1459
- "prostgles-types": "^1.5.121",
1459
+ "prostgles-types": "^1.5.122",
1460
1460
  "sharp": "^0.29.3",
1461
1461
  "typescript": "^3.9.7"
1462
1462
  }