pogi 2.10.2 → 3.0.0-beta2

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 (83) hide show
  1. package/.vscode/launch.json +47 -15
  2. package/CHANGELOG.md +11 -0
  3. package/docs/API/PgDb.md +25 -0
  4. package/docs/notification.md +19 -0
  5. package/jest.config.js +23 -0
  6. package/lib/bin/generateInterface.js +3 -3
  7. package/lib/bin/generateInterface.js.map +1 -1
  8. package/lib/connectionOptions.d.ts +10 -0
  9. package/lib/index.d.ts +1 -1
  10. package/lib/pgConverters.d.ts +9 -8
  11. package/lib/pgConverters.js +46 -32
  12. package/lib/pgConverters.js.map +1 -1
  13. package/lib/pgConverters.test.d.ts +1 -0
  14. package/lib/pgConverters.test.js +13 -0
  15. package/lib/pgConverters.test.js.map +1 -0
  16. package/lib/pgDb.d.ts +27 -27
  17. package/lib/pgDb.js +293 -100
  18. package/lib/pgDb.js.map +1 -1
  19. package/lib/pgDb.test.d.ts +1 -0
  20. package/lib/pgDb.test.js +1126 -0
  21. package/lib/pgDb.test.js.map +1 -0
  22. package/lib/pgDbInterface.d.ts +53 -0
  23. package/lib/pgDbInterface.js +11 -0
  24. package/lib/pgDbInterface.js.map +1 -0
  25. package/lib/pgDbOperators.d.ts +3 -3
  26. package/lib/pgDbOperators.js +4 -7
  27. package/lib/pgDbOperators.js.map +1 -1
  28. package/lib/pgDbOperators.test.d.ts +1 -0
  29. package/lib/pgDbOperators.test.js +313 -0
  30. package/lib/pgDbOperators.test.js.map +1 -0
  31. package/lib/pgSchema.d.ts +10 -9
  32. package/lib/pgSchema.js.map +1 -1
  33. package/lib/pgSchemaInterface.d.ts +12 -0
  34. package/lib/pgSchemaInterface.js +3 -0
  35. package/lib/pgSchemaInterface.js.map +1 -0
  36. package/lib/pgTable.d.ts +15 -40
  37. package/lib/pgTable.js +54 -54
  38. package/lib/pgTable.js.map +1 -1
  39. package/lib/pgTableInterface.d.ts +102 -0
  40. package/lib/pgTableInterface.js +4 -0
  41. package/lib/pgTableInterface.js.map +1 -0
  42. package/lib/pgUtils.d.ts +16 -6
  43. package/lib/pgUtils.js +162 -31
  44. package/lib/pgUtils.js.map +1 -1
  45. package/lib/queryAble.d.ts +20 -53
  46. package/lib/queryAble.js +149 -80
  47. package/lib/queryAble.js.map +1 -1
  48. package/lib/queryAbleInterface.d.ts +55 -0
  49. package/lib/queryAbleInterface.js +7 -0
  50. package/lib/queryAbleInterface.js.map +1 -0
  51. package/lib/queryWhere.d.ts +2 -2
  52. package/lib/queryWhere.js +19 -23
  53. package/lib/queryWhere.js.map +1 -1
  54. package/mkdocs.yml +1 -0
  55. package/package.json +21 -11
  56. package/src/bin/generateInterface.ts +2 -2
  57. package/src/connectionOptions.ts +48 -13
  58. package/src/index.d.ts +7 -0
  59. package/src/index.ts +1 -1
  60. package/src/pgConverters.test.ts +10 -0
  61. package/src/pgConverters.ts +34 -22
  62. package/src/pgDb.test.ts +1324 -0
  63. package/src/pgDb.ts +318 -122
  64. package/src/pgDbInterface.ts +57 -0
  65. package/src/pgDbOperators.test.ts +478 -0
  66. package/src/pgDbOperators.ts +45 -22
  67. package/src/pgSchema.ts +10 -9
  68. package/src/pgSchemaInterface.ts +12 -0
  69. package/src/pgTable.ts +66 -98
  70. package/src/pgTableInterface.ts +131 -0
  71. package/src/pgUtils.ts +166 -42
  72. package/src/queryAble.ts +167 -125
  73. package/src/queryAbleInterface.ts +104 -0
  74. package/src/queryWhere.ts +42 -43
  75. package/{spec/resources → src/test}/init.sql +23 -0
  76. package/src/test/pgServiceRestartTest.ts +1500 -0
  77. package/{spec/resources → src/test}/throw_exception.sql +0 -0
  78. package/{spec/resources → src/test}/tricky.sql +0 -0
  79. package/{src/tsconfig.json → tsconfig.json} +12 -11
  80. package/spec/run.js +0 -5
  81. package/spec/support/jasmine.json +0 -9
  82. package/src/test/pgDbOperatorSpec.ts +0 -492
  83. package/src/test/pgDbSpec.ts +0 -994
package/src/queryWhere.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import operationsMap from "./pgDbOperators";
2
- import {FieldType} from "./pgDb";
2
+ import { FieldType } from "./pgDb";
3
+ import _ = require("lodash");
4
+ import util = require("util");
5
+ import { pgUtils } from "./pgUtils";
3
6
 
4
- const _ = require("lodash");
5
- const util = require("util");
6
-
7
- class FieldAndOperator {
7
+ interface FieldAndOperator {
8
8
  field: string;
9
9
  quotedField: string;
10
10
  operator: string;
@@ -12,8 +12,14 @@ class FieldAndOperator {
12
12
  mutator?: Function;
13
13
  }
14
14
 
15
+ interface Result {
16
+ params: any[],
17
+ predicates: string[],
18
+ offset: number
19
+ }
20
+
15
21
  /** public */
16
- function generateWhere(conditions, fieldTypes: { [index: string]: FieldType }, tableName: string, placeholderOffset = 0, skipUndefined): { where: string, params: Array<any> } {
22
+ function generateWhere(conditions: Record<string, any>, fieldTypes: { [index: string]: FieldType }, tableName: string, placeholderOffset = 0, skipUndefined?: boolean): { where: string, params: Array<any> } {
17
23
  let result = generate({
18
24
  params: [],
19
25
  predicates: [],
@@ -27,7 +33,7 @@ function generateWhere(conditions, fieldTypes: { [index: string]: FieldType }, t
27
33
  }
28
34
 
29
35
  /** private */
30
- function generate(result, conditions, fieldTypes: { [index: string]: FieldType }, tableName: string, skipUndefined) {
36
+ function generate(result: Result, conditions: Record<string, any>, fieldTypes: { [index: string]: FieldType }, tableName: string, skipUndefined?: boolean): Result {
31
37
  _.each(conditions, (value, key) => {
32
38
  //get the column field and the operator if specified
33
39
  let fieldAndOperator = parseKey(key);
@@ -53,7 +59,7 @@ function generate(result, conditions, fieldTypes: { [index: string]: FieldType }
53
59
  return result;
54
60
  }
55
61
 
56
- function handleOrAnd(result, fieldAndOperator, value, fieldTypes: { [index: string]: FieldType }, tableName: string, skipUndefined) {
62
+ function handleOrAnd(result: Result, fieldAndOperator: FieldAndOperator, value: any, fieldTypes: { [index: string]: FieldType }, tableName: string, skipUndefined?: boolean): Result {
57
63
  if (!Array.isArray(value)) {
58
64
  value = [value];
59
65
  }
@@ -67,12 +73,12 @@ function handleOrAnd(result, fieldAndOperator, value, fieldTypes: { [index: stri
67
73
  }, v, fieldTypes, tableName, skipUndefined);
68
74
 
69
75
  // encapsulate and join the individual predicates with AND to create the complete subgroup predicate
70
- acc.predicates.push(util.format('(%s)', subResult.predicates.join(' AND ')));
76
+ acc.predicates.push('(' + subResult.predicates.join(' AND ') + ')');
71
77
  acc.params = acc.params.concat(subResult.params);
72
78
  acc.offset += subResult.params.length;
73
79
 
74
80
  return acc;
75
- }, {
81
+ }, <Result>{
76
82
  params: [],
77
83
  predicates: [],
78
84
  offset: result.offset
@@ -91,30 +97,29 @@ function handleOrAnd(result, fieldAndOperator, value, fieldTypes: { [index: stri
91
97
  return result;
92
98
  }
93
99
 
94
- function handleNullValue(result, fieldAndOperator, value) {
100
+ function handleNullValue(result: Result, fieldAndOperator: FieldAndOperator, value: any): Result {
95
101
  fieldAndOperator.operator = fieldAndOperator.operator === '=' ? 'IS' : 'IS NOT';
96
102
  result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
97
103
  return result;
98
104
  }
99
105
 
100
- function handleArrayValue(result, fieldAndOperator, value, fieldTypes: { [index: string]: FieldType }) {
106
+ function handleArrayValue(result: Result, fieldAndOperator: FieldAndOperator, value: any[], fieldTypes: { [index: string]: FieldType }): Result {
101
107
  if (fieldAndOperator.mutator) {
102
- value = value.map(v => fieldAndOperator.mutator(v));
108
+ value = value.map((v: any) => fieldAndOperator.mutator!(v));
103
109
  }
104
110
  let fieldType = fieldTypes[fieldAndOperator.field];
105
111
 
112
+ let position = '$' + (result.params.length + 1 + result.offset);
106
113
  if (fieldType == FieldType.JSON &&
107
114
  ['?|', '?&'].indexOf(fieldAndOperator.operator) != -1) {
108
115
  result.params.push(value);
109
- value = util.format("$%s", result.params.length + result.offset);
110
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
116
+ result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
111
117
  return result;
112
118
  }
113
119
  else if (fieldType == FieldType.JSON &&
114
120
  ['@>', '<@', '&&'].indexOf(fieldAndOperator.operator) != -1) {
115
121
  result.params.push(JSON.stringify(value));
116
- value = util.format("$%s", result.params.length + result.offset);
117
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
122
+ result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
118
123
  return result;
119
124
  }
120
125
  else if ((!fieldType || fieldType == FieldType.TIME) &&
@@ -131,31 +136,27 @@ function handleArrayValue(result, fieldAndOperator, value, fieldTypes: { [index:
131
136
  }
132
137
 
133
138
  result.params.push(value
134
- .map(v => (fieldType == FieldType.TIME && !(value instanceof Date)) ? new Date(v) : v)
139
+ .map(v => (fieldType == FieldType.TIME && !(v instanceof Date)) ? new Date(v) : v)
135
140
  );
136
- value = util.format("$%s", result.params.length + result.offset);
137
- result.predicates.push(util.format('%s %s (%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
141
+ result.predicates.push(util.format('%s %s (%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
138
142
  return result;
139
143
  }
140
144
  else if (!fieldType && ['LIKE', 'ILIKE', 'SIMILAR TO', '~', '~*'].indexOf(fieldAndOperator.operator) != -1) {
141
145
  //defaults to any
142
146
  result.params.push(value);
143
- value = util.format("$%s", result.params.length + result.offset);
144
- result.predicates.push(util.format('%s %s ANY(%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
147
+ result.predicates.push(util.format('%s %s ANY(%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
145
148
  return result;
146
149
  }
147
150
  else if (!fieldType && ['NOT LIKE', 'NOT ILIKE', 'NOT SIMILAR TO', '!~', '!~*'].indexOf(fieldAndOperator.operator) != -1) {
148
151
  //defaults to all
149
152
  result.params.push(value);
150
- value = util.format("$%s", result.params.length + result.offset);
151
- result.predicates.push(util.format('%s %s ALL(%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
153
+ result.predicates.push(util.format('%s %s ALL(%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
152
154
  return result;
153
155
  }
154
156
  else if (fieldType == FieldType.ARRAY &&
155
157
  ['=', '<>', '<', '>', '<=', '>=', '@>', '<@', '&&'].indexOf(fieldAndOperator.operator) != -1) {
156
158
  result.params.push(value);
157
- value = util.format("$%s", result.params.length + result.offset);
158
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
159
+ result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
159
160
  return result;
160
161
  }
161
162
 
@@ -163,7 +164,7 @@ function handleArrayValue(result, fieldAndOperator, value, fieldTypes: { [index:
163
164
  }
164
165
 
165
166
 
166
- function handleSingleValue(result, fieldAndOperator: FieldAndOperator, value, fieldTypes: { [index: string]: FieldType }, tableName) {
167
+ function handleSingleValue(result: Result, fieldAndOperator: FieldAndOperator, value: any, fieldTypes: { [index: string]: FieldType }, tableName: string): Result {
167
168
  if (fieldAndOperator.mutator) {
168
169
  value = fieldAndOperator.mutator(value);
169
170
  }
@@ -237,11 +238,11 @@ function handleSingleValue(result, fieldAndOperator: FieldAndOperator, value, fi
237
238
  }
238
239
 
239
240
 
240
- function strip(arr) {
241
+ function strip(arr: string[]): string[] {
241
242
  return arr.map((s) => s.trim()).filter(v => v != '');
242
243
  }
243
244
 
244
- function getOp(str) {
245
+ function getOp(str: string): string {
245
246
  for (let i = 0; i < str.length; i++) {
246
247
  if (operationsMap[str.substr(i)]) {
247
248
  return str.substr(i);
@@ -266,7 +267,7 @@ function getOp(str) {
266
267
  * @param {String} key Key in a format resembling "field [JSON operation+path] operation"
267
268
  * @return {Object} [description]
268
269
  */
269
- function parseKey(key): FieldAndOperator {
270
+ function parseKey(key: string): FieldAndOperator {
270
271
  key = key.trim();
271
272
 
272
273
  let userOp = getOp(key);
@@ -276,32 +277,30 @@ function parseKey(key): FieldAndOperator {
276
277
  let operation = operationsMap[userOp] || {};
277
278
  let jsonRegexp = /(->[^>]|->>|#>[^>]|#>>)/;
278
279
 
279
- let field;
280
- let quotedField;
280
+ let field: string | undefined;
281
+ let quotedField: string;
281
282
 
282
283
  let quotedByUser = key.indexOf('"') > -1; //key[0]=='"'; -> lets make it possible to write transformed columns, e.g. LOWER("field")
283
284
  if (quotedByUser) {
284
285
  quotedField = key;
285
286
  //field is used for find out the type of the field, so lets restore it if possible, grab the first quoted string
286
- field = /[^"]*"([^"]*)".*/.exec(key)[1];
287
+ field = /[^"]*"([^"]*)".*/.exec(key)?.[1];
287
288
  if (!quotedField || !field) {
288
- console.error("Parsing error!");
289
+ throw new Error('Invalid field:' + key);
289
290
  }
290
291
  } else {
291
292
  let parts = strip(key.split(jsonRegexp));
292
-
293
293
  field = parts.shift();
294
- quotedField = util.format('"%s"', field);
294
+ if (!field) {
295
+ throw new Error('Invalid field:' + key);
296
+ }
297
+ quotedField = pgUtils.quoteFieldName(field);
295
298
 
296
299
  if (parts.length > 1) {
297
- let jsonOp = parts.shift();
298
- let jsonKey = parts.shift();
299
-
300
- // treat numeric json keys as array indices, otherwise quote it
301
- if (isNaN(jsonKey) && jsonKey.indexOf("'") == -1) {
302
- jsonKey = util.format("'%s'", jsonKey);
303
- }
300
+ let jsonOp = parts.shift()!;
301
+ let jsonKey = parts.shift()!;
304
302
 
303
+ jsonKey = pgUtils.quoteFieldNameJsonbOrPosition(jsonKey);
305
304
  quotedField = util.format('%s%s%s', quotedField, jsonOp, jsonKey);
306
305
  }
307
306
  }
@@ -6,6 +6,7 @@ DROP FUNCTION IF EXISTS increment();
6
6
  DROP VIEW IF EXISTS "users_view";
7
7
  DROP TABLE IF EXISTS "users";
8
8
  DROP TABLE IF EXISTS "groups";
9
+ DROP TABLE IF EXISTS "types";
9
10
  -- drop sequences
10
11
  DROP SEQUENCE IF EXISTS "users_id_seq";
11
12
  -- drop types
@@ -57,6 +58,28 @@ CREATE TABLE IF NOT EXISTS "users" (
57
58
  "createdtz" timestamptz
58
59
  );
59
60
 
61
+ CREATE TABLE IF NOT EXISTS "types" (
62
+ "text" varchar,
63
+ "int" integer,
64
+ "bigInt" bigInt,
65
+ "real" real,
66
+ "double" float8,
67
+ "bool" boolean,
68
+ "json" json,
69
+ "jsonB" jsonb,
70
+ "timestamptz" timestamptz,
71
+
72
+ "arrayText" varchar[],
73
+ "arrayInt" integer[],
74
+ "arrayBigInt" bigInt[],
75
+ "arrayReal" real[],
76
+ "arrayDouble" float8[],
77
+ "arrayBool" boolean[],
78
+ "arrayJson" json[],
79
+ "arrayJsonB" jsonb[],
80
+ "arrayTimestamptz" timestamptz[]
81
+ );
82
+
60
83
 
61
84
  CREATE OR REPLACE FUNCTION update_updated_column() RETURNS TRIGGER AS $$
62
85
  BEGIN