pogi 3.0.0-beta → 3.0.0-beta5

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 (129) hide show
  1. package/.env +5 -0
  2. package/lib/bin/generateInterface.js +1 -1
  3. package/lib/connectionOptions.d.ts +7 -0
  4. package/lib/index.d.ts +1 -1
  5. package/lib/pgConverters.d.ts +9 -10
  6. package/lib/pgConverters.js +44 -39
  7. package/lib/pgConverters.js.map +1 -1
  8. package/lib/{src/pgConverters.test.d.ts → pgConverters.test.d.ts} +0 -0
  9. package/lib/{src/pgConverters.test.js → pgConverters.test.js} +0 -0
  10. package/lib/pgConverters.test.js.map +1 -0
  11. package/lib/pgDb.d.ts +24 -31
  12. package/lib/pgDb.js +66 -69
  13. package/lib/pgDb.js.map +1 -1
  14. package/lib/{src/pgDb.test.d.ts → pgDb.test.d.ts} +0 -0
  15. package/lib/{src/pgDb.test.js → pgDb.test.js} +6 -0
  16. package/lib/pgDb.test.js.map +1 -0
  17. package/lib/pgDbInterface.d.ts +22 -0
  18. package/lib/pgDbInterface.js +11 -0
  19. package/lib/pgDbInterface.js.map +1 -0
  20. package/lib/pgDbOperators.d.ts +3 -3
  21. package/lib/pgDbOperators.js +4 -7
  22. package/lib/pgDbOperators.js.map +1 -1
  23. package/lib/{src/pgDbOperators.test.d.ts → pgDbOperators.test.d.ts} +0 -0
  24. package/lib/{src/pgDbOperators.test.js → pgDbOperators.test.js} +0 -0
  25. package/lib/pgDbOperators.test.js.map +1 -0
  26. package/lib/pgSchema.d.ts +2 -3
  27. package/lib/pgSchema.js.map +1 -1
  28. package/lib/pgSchemaInterface.d.ts +0 -0
  29. package/lib/pgSchemaInterface.js +2 -0
  30. package/lib/pgSchemaInterface.js.map +1 -0
  31. package/lib/pgTable.d.ts +13 -38
  32. package/lib/pgTable.js +54 -54
  33. package/lib/pgTable.js.map +1 -1
  34. package/lib/pgTableInterface.d.ts +28 -0
  35. package/lib/{src/pgTableInterface.js → pgTableInterface.js} +0 -0
  36. package/lib/pgTableInterface.js.map +1 -0
  37. package/lib/pgUtils.d.ts +15 -5
  38. package/lib/pgUtils.js +118 -24
  39. package/lib/pgUtils.js.map +1 -1
  40. package/lib/queryAble.d.ts +15 -64
  41. package/lib/queryAble.js +46 -45
  42. package/lib/queryAble.js.map +1 -1
  43. package/lib/{src/queryAbleInterface.d.ts → queryAbleInterface.d.ts} +6 -10
  44. package/lib/{src/queryAbleInterface.js → queryAbleInterface.js} +0 -0
  45. package/lib/queryAbleInterface.js.map +1 -0
  46. package/lib/queryWhere.d.ts +2 -2
  47. package/lib/queryWhere.js +19 -23
  48. package/lib/queryWhere.js.map +1 -1
  49. package/lib/{src/bin/generateInterface.d.ts → test/pgDbOperatorSpec.d.ts} +0 -0
  50. package/lib/test/pgDbOperatorSpec.js +326 -0
  51. package/lib/test/pgDbOperatorSpec.js.map +1 -0
  52. package/lib/test/pgDbSpec.d.ts +1 -0
  53. package/lib/test/pgDbSpec.js +1139 -0
  54. package/lib/test/pgDbSpec.js.map +1 -0
  55. package/lib/test/pgServiceRestartTest.d.ts +1 -0
  56. package/lib/test/pgServiceRestartTest.js +1532 -0
  57. package/lib/test/pgServiceRestartTest.js.map +1 -0
  58. package/package.json +2 -1
  59. package/tsconfig.json +3 -5
  60. package/lib/src/bin/generateInterface.js +0 -53
  61. package/lib/src/bin/generateInterface.js.map +0 -1
  62. package/lib/src/connectionOptions.d.ts +0 -34
  63. package/lib/src/connectionOptions.js +0 -3
  64. package/lib/src/connectionOptions.js.map +0 -1
  65. package/lib/src/index.d.ts +0 -6
  66. package/lib/src/index.js +0 -12
  67. package/lib/src/index.js.map +0 -1
  68. package/lib/src/pgConverters.d.ts +0 -9
  69. package/lib/src/pgConverters.js +0 -71
  70. package/lib/src/pgConverters.js.map +0 -1
  71. package/lib/src/pgConverters.test.js.map +0 -1
  72. package/lib/src/pgDb.d.ts +0 -79
  73. package/lib/src/pgDb.js +0 -764
  74. package/lib/src/pgDb.js.map +0 -1
  75. package/lib/src/pgDb.test.js.map +0 -1
  76. package/lib/src/pgDbInterface.js +0 -11
  77. package/lib/src/pgDbInterface.js.map +0 -1
  78. package/lib/src/pgDbLogger.d.ts +0 -5
  79. package/lib/src/pgDbLogger.js +0 -3
  80. package/lib/src/pgDbLogger.js.map +0 -1
  81. package/lib/src/pgDbOperators.d.ts +0 -113
  82. package/lib/src/pgDbOperators.js +0 -41
  83. package/lib/src/pgDbOperators.js.map +0 -1
  84. package/lib/src/pgDbOperators.test.js.map +0 -1
  85. package/lib/src/pgSchema.d.ts +0 -17
  86. package/lib/src/pgSchema.js +0 -16
  87. package/lib/src/pgSchema.js.map +0 -1
  88. package/lib/src/pgSchemaInterface.d.ts +0 -12
  89. package/lib/src/pgSchemaInterface.js +0 -3
  90. package/lib/src/pgSchemaInterface.js.map +0 -1
  91. package/lib/src/pgTable.d.ts +0 -105
  92. package/lib/src/pgTable.js +0 -322
  93. package/lib/src/pgTable.js.map +0 -1
  94. package/lib/src/pgTableInterface.d.ts +0 -102
  95. package/lib/src/pgTableInterface.js.map +0 -1
  96. package/lib/src/pgUtils.d.ts +0 -41
  97. package/lib/src/pgUtils.js +0 -282
  98. package/lib/src/pgUtils.js.map +0 -1
  99. package/lib/src/queryAble.d.ts +0 -40
  100. package/lib/src/queryAble.js +0 -338
  101. package/lib/src/queryAble.js.map +0 -1
  102. package/lib/src/queryAbleInterface.js.map +0 -1
  103. package/lib/src/queryWhere.d.ts +0 -8
  104. package/lib/src/queryWhere.js +0 -245
  105. package/lib/src/queryWhere.js.map +0 -1
  106. package/src/bin/generateInterface.ts +0 -54
  107. package/src/connectionOptions.ts +0 -75
  108. package/src/index.d.ts +0 -7
  109. package/src/index.ts +0 -6
  110. package/src/pgConverters.test.ts +0 -10
  111. package/src/pgConverters.ts +0 -59
  112. package/src/pgDb.test.ts +0 -1324
  113. package/src/pgDb.ts +0 -842
  114. package/src/pgDbInterface.ts +0 -57
  115. package/src/pgDbLogger.ts +0 -13
  116. package/src/pgDbOperators.test.ts +0 -478
  117. package/src/pgDbOperators.ts +0 -85
  118. package/src/pgSchema.ts +0 -16
  119. package/src/pgSchemaInterface.ts +0 -12
  120. package/src/pgTable.ts +0 -369
  121. package/src/pgTableInterface.ts +0 -131
  122. package/src/pgUtils.ts +0 -290
  123. package/src/queryAble.ts +0 -365
  124. package/src/queryAbleInterface.ts +0 -108
  125. package/src/queryWhere.ts +0 -325
  126. package/src/test/init.sql +0 -122
  127. package/src/test/pgServiceRestartTest.ts +0 -1500
  128. package/src/test/throw_exception.sql +0 -5
  129. package/src/test/tricky.sql +0 -13
@@ -1,108 +0,0 @@
1
- import { PgDbLogger } from "./pgDbLogger";
2
- import { IPgSchema } from "./pgSchemaInterface";
3
- import * as stream from "stream";
4
- import { ResultFieldType, IPgDb } from "./pgDbInterface";
5
-
6
- export interface QueryOptions {
7
- limit?: number;
8
- offset?: number;
9
- orderBy?: string | string[] | { [fieldName: string]: 'asc' | 'desc' };//free text or column list
10
- /**
11
- * only used with orderBy
12
- * true -> nulls first,
13
- * false -> nulls last
14
- */
15
- orderByNullsFirst?: boolean;
16
- groupBy?: string | string[];//free text or column list
17
- fields?: string | string[];//free text or column list
18
- logger?: PgDbLogger;
19
- forUpdate?: boolean;
20
- distinct?: boolean;
21
- skipUndefined?: boolean;
22
- forceEscapeColumns?: boolean | {
23
- select?: boolean
24
- where?: boolean
25
- orderBy?: boolean
26
- groupBy?: boolean
27
- }
28
- }
29
-
30
- export interface SqlQueryOptions {
31
- logger?: PgDbLogger;
32
- }
33
-
34
-
35
-
36
- export interface ResultType {
37
- command: 'SELECT' | 'UPDATE' | 'DELETE',
38
- rowCount: number,
39
- oid: number,
40
- rows: any[],
41
- fields: ResultFieldType[],
42
- _parsers: Function[][],
43
- RowCtor: Function[],
44
- rowsAsArray: boolean,
45
- _getTypeParser: Function[]
46
- }
47
-
48
- export interface PgRowResult {
49
- columns: string[],
50
- rows: any[]
51
- }
52
-
53
- let defaultLogger = {
54
- log: () => { },
55
- error: () => { }
56
- };
57
-
58
-
59
-
60
- export interface IQueryAble {
61
- db: IPgDb & IQueryAble; // assigned in async init
62
- schema: IPgSchema;
63
- logger: PgDbLogger;
64
-
65
- /*connectionErrorListener : () => { }*/
66
-
67
- setLogger(logger: PgDbLogger): void
68
-
69
- getLogger(useConsoleAsDefault: boolean): PgDbLogger
70
-
71
- /** alias to {@link query} */
72
- run(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any[]>
73
-
74
- /**
75
- * Params can be
76
- * 1) array, then sql should have $1 $2 for placeholders
77
- * 2) object, then sql should have:
78
- * :example -> for params in statements (set/where), will be transformed to $1 $2 ...
79
- * :!example -> for DDL names (schema, table, column), will be replaced in the query
80
- * e.g. query('select * from a.b where id=$1;',['the_stage_is_set']);
81
- * e.g. query('select * from :!schema.:!table where id=:id;',{schema:'a',table:'b', id:'the_stage_is_set'});
82
- */
83
- query(sql: string, params?: any[] | {} | null, options?: SqlQueryOptions): Promise<any[]>
84
-
85
- /**
86
- * Same as query but response is two array: columns and rows and rows are arrays also not objects
87
- * This is useful for queries which have colliding column names
88
- */
89
- queryAsRows(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<PgRowResult>
90
-
91
- /**
92
- * If the callback function return true, the connection will be closed.
93
- */
94
- queryWithOnCursorCallback(sql: string, params: any[] | Record<string, any> | null, options: SqlQueryOptions | null, callback: (res: any) => any): Promise<void>
95
-
96
- queryAsStream(sql: string, params?: any[] | Record<string, any> | null, options?: SqlQueryOptions | null): Promise<stream.Readable>
97
-
98
- queryOne(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any>
99
-
100
- queryFirst(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any>
101
-
102
- /** @return one record's one field */
103
- queryOneField(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any>
104
-
105
- /** @return one column for the matching records */
106
- queryOneColumn(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any[]>
107
-
108
- }
package/src/queryWhere.ts DELETED
@@ -1,325 +0,0 @@
1
- import operationsMap from "./pgDbOperators";
2
- import { FieldType } from "./pgDb";
3
- import _ = require("lodash");
4
- import util = require("util");
5
- import { pgUtils } from "./pgUtils";
6
-
7
- interface FieldAndOperator {
8
- field: string;
9
- quotedField: string;
10
- operator: string;
11
- originalOp: string;
12
- mutator?: Function;
13
- }
14
-
15
- interface Result {
16
- params: any[],
17
- predicates: string[],
18
- offset: number
19
- }
20
-
21
- /** public */
22
- function generateWhere(conditions: Record<string, any>, fieldTypes: { [index: string]: FieldType }, tableName: string, placeholderOffset = 0, skipUndefined?: boolean): { where: string, params: Array<any> } {
23
- let result = generate({
24
- params: [],
25
- predicates: [],
26
- offset: placeholderOffset,
27
- }, conditions, fieldTypes, tableName, skipUndefined);
28
-
29
- return {
30
- where: result.predicates.length > 0 ? ' WHERE ' + result.predicates.join(' AND ') : '',
31
- params: result.params
32
- };
33
- }
34
-
35
- /** private */
36
- function generate(result: Result, conditions: Record<string, any>, fieldTypes: { [index: string]: FieldType }, tableName: string, skipUndefined?: boolean): Result {
37
- _.each(conditions, (value, key) => {
38
- //get the column field and the operator if specified
39
- let fieldAndOperator = parseKey(key);
40
-
41
- if (value === undefined) { //null is ok, but undefined is skipped if requested
42
- if (skipUndefined === true) return;
43
- throw new Error('Invalid conditions! Field value undefined: "' + fieldAndOperator.field + '". Either delete the field, set it to null or use the options.skipUndefined parameter.');
44
- }
45
- else if (fieldAndOperator.field === 'or' || fieldAndOperator.field === 'and') {
46
- result = handleOrAnd(result, fieldAndOperator, value, fieldTypes, tableName, skipUndefined);
47
- }
48
- else if (value === null) {
49
- result = handleNullValue(result, fieldAndOperator, value);
50
- }
51
- else if (Array.isArray(value)) {
52
- result = handleArrayValue(result, fieldAndOperator, value, fieldTypes);
53
- }
54
- else {
55
- result = handleSingleValue(result, fieldAndOperator, value, fieldTypes, tableName);
56
- }
57
- });
58
-
59
- return result;
60
- }
61
-
62
- function handleOrAnd(result: Result, fieldAndOperator: FieldAndOperator, value: any, fieldTypes: { [index: string]: FieldType }, tableName: string, skipUndefined?: boolean): Result {
63
- if (!Array.isArray(value)) {
64
- value = [value];
65
- }
66
-
67
- let groupResult = _.reduce(value, (acc, v) => {
68
- // assemble predicates for each subgroup in this 'or' array
69
- let subResult = generate({
70
- params: [],
71
- predicates: [],
72
- offset: result.params.length + acc.offset // ensure the offset from predicates outside the subgroup is counted
73
- }, v, fieldTypes, tableName, skipUndefined);
74
-
75
- // encapsulate and join the individual predicates with AND to create the complete subgroup predicate
76
- acc.predicates.push('(' + subResult.predicates.join(' AND ') + ')');
77
- acc.params = acc.params.concat(subResult.params);
78
- acc.offset += subResult.params.length;
79
-
80
- return acc;
81
- }, <Result>{
82
- params: [],
83
- predicates: [],
84
- offset: result.offset
85
- });
86
-
87
- // join the compiled subgroup predicates with OR, encapsulate, and push the
88
- // complex predicate ("((x = $1 AND y = $2) OR (z = $3))") onto the result object
89
- result.params = result.params.concat(groupResult.params);
90
- if (groupResult.predicates.length) {
91
- if (fieldAndOperator.field === 'and') {
92
- result.predicates.push(util.format('(%s)', groupResult.predicates.join(' AND ')));
93
- } else {
94
- result.predicates.push(util.format('(%s)', groupResult.predicates.join(' OR ')));
95
- }
96
- }
97
- return result;
98
- }
99
-
100
- function handleNullValue(result: Result, fieldAndOperator: FieldAndOperator, value: any): Result {
101
- fieldAndOperator.operator = fieldAndOperator.operator === '=' ? 'IS' : 'IS NOT';
102
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
103
- return result;
104
- }
105
-
106
- function handleArrayValue(result: Result, fieldAndOperator: FieldAndOperator, value: any[], fieldTypes: { [index: string]: FieldType }): Result {
107
- if (fieldAndOperator.mutator) {
108
- value = value.map((v: any) => fieldAndOperator.mutator!(v));
109
- }
110
- let fieldType = fieldTypes[fieldAndOperator.field];
111
-
112
- let position = '$' + (result.params.length + 1 + result.offset);
113
- if (fieldType == FieldType.JSON &&
114
- ['?|', '?&'].indexOf(fieldAndOperator.operator) != -1) {
115
- result.params.push(value);
116
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
117
- return result;
118
- }
119
- else if (fieldType == FieldType.JSON &&
120
- ['@>', '<@', '&&'].indexOf(fieldAndOperator.operator) != -1) {
121
- result.params.push(JSON.stringify(value));
122
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
123
- return result;
124
- }
125
- else if ((!fieldType || fieldType == FieldType.TIME) &&
126
- ['=', '<>', 'IN', 'NOT IN'].includes(fieldAndOperator.operator)) {
127
- if (fieldAndOperator.operator === '=' || fieldAndOperator.operator === 'IN') {
128
- fieldAndOperator.operator = '= ANY';
129
- } else {
130
- fieldAndOperator.operator = '<> ALL';
131
- }
132
-
133
- if (value.length === 0) { // avoid empty "[NOT] IN ()"
134
- throw new Error('Invalid conditions! empty array for field:"' + fieldAndOperator.field + '" and operator:"' + fieldAndOperator.operator + '"');
135
- //return result;
136
- }
137
-
138
- result.params.push(value
139
- .map(v => (fieldType == FieldType.TIME && !(v instanceof Date)) ? new Date(v) : v)
140
- );
141
- result.predicates.push(util.format('%s %s (%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
142
- return result;
143
- }
144
- else if (!fieldType && ['LIKE', 'ILIKE', 'SIMILAR TO', '~', '~*'].indexOf(fieldAndOperator.operator) != -1) {
145
- //defaults to any
146
- result.params.push(value);
147
- result.predicates.push(util.format('%s %s ANY(%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
148
- return result;
149
- }
150
- else if (!fieldType && ['NOT LIKE', 'NOT ILIKE', 'NOT SIMILAR TO', '!~', '!~*'].indexOf(fieldAndOperator.operator) != -1) {
151
- //defaults to all
152
- result.params.push(value);
153
- result.predicates.push(util.format('%s %s ALL(%s)', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
154
- return result;
155
- }
156
- else if (fieldType == FieldType.ARRAY &&
157
- ['=', '<>', '<', '>', '<=', '>=', '@>', '<@', '&&'].indexOf(fieldAndOperator.operator) != -1) {
158
- result.params.push(value);
159
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, position));
160
- return result;
161
- }
162
-
163
- throw new Error('[325] Not implemented operator: "' + fieldAndOperator.operator + '" for field ' + fieldAndOperator.field + ' with type ' + fieldType);
164
- }
165
-
166
-
167
- function handleSingleValue(result: Result, fieldAndOperator: FieldAndOperator, value: any, fieldTypes: { [index: string]: FieldType }, tableName: string): Result {
168
- if (fieldAndOperator.mutator) {
169
- value = fieldAndOperator.mutator(value);
170
- }
171
- let fieldType = fieldTypes[fieldAndOperator.field];
172
- if (fieldAndOperator.operator === '@@') {
173
- /**
174
- * field can be string -> to_tsquery(string)
175
- * or object {lang:'english', txt:string} -> to_tsquery(o.lang, o.txt)
176
- */
177
- if (typeof value == 'object') {
178
- if (!(value.lang || value.language) || !(value.query || value.plainquery)) {
179
- throw new Error('[499] only "lang"/"language" and "query/plainquery" properties are supported!');
180
- }
181
- if (fieldType == FieldType.TSVECTOR) {
182
- //language is already set
183
- result.params.push(value.lang || value.language);
184
- result.params.push(value.query || value.plainquery);
185
- let template = value.query ? "%s %s to_tsquery($%s, $%s)" : "%s %s plainto_tsquery($%s, $%s)";
186
- result.predicates.push(util.format(template,
187
- fieldAndOperator.quotedField,
188
- fieldAndOperator.operator,
189
- result.params.length - 1 + result.offset, //lang
190
- result.params.length + result.offset //query
191
- ));
192
- } else {
193
- result.params.push(value.lang || value.language);
194
- result.params.push(value.lang || value.language);
195
- result.params.push(value.query || value.plainquery);
196
- let template = value.query ? "to_tsvector($%s, %s) %s to_tsquery($%s, $%s)" : "to_tsvector($%s, %s) %s plainto_tsquery($%s, $%s)";
197
- result.predicates.push(util.format(template,
198
- result.params.length - 2 + result.offset, //lang
199
- fieldAndOperator.quotedField,
200
- fieldAndOperator.operator,
201
- result.params.length - 1 + result.offset, //lang
202
- result.params.length + result.offset //query
203
- ));
204
- }
205
- } else {
206
- result.params.push(value);
207
- let template = fieldType == FieldType.TSVECTOR ? "%s %s plainto_tsquery($%s)" : "to_tsvector(%s) %s plainto_tsquery($%s)";
208
- result.predicates.push(util.format(template, fieldAndOperator.quotedField, fieldAndOperator.operator, result.params.length + result.offset));
209
- }
210
- }
211
- else if (fieldType == FieldType.ARRAY) {
212
- if (['=', '<>'].indexOf(fieldAndOperator.operator) != -1) {
213
- if (fieldAndOperator.originalOp == '=*') {
214
- result.params.push([value]);
215
- value = util.format("$%s", result.params.length + result.offset);
216
- result.predicates.push(util.format('%s && %s', fieldAndOperator.quotedField, value));
217
- } else {
218
- result.params.push(value);
219
- value = util.format("$%s", result.params.length + result.offset);
220
- result.predicates.push(util.format('%s %s ANY(%s)', value, fieldAndOperator.operator, fieldAndOperator.quotedField));
221
- }
222
- }
223
- else if (['LIKE', 'ILIKE', 'NOT LIKE', 'NOT ILIKE', 'SIMILAR TO', 'NOT SIMILAR TO'].indexOf(fieldAndOperator.operator) != -1) {
224
- result.params.push(value);
225
- value = util.format("$%s", result.params.length + result.offset);
226
-
227
- let q = 'EXISTS (SELECT * FROM (SELECT UNNEST(' + tableName + '.%s) _el) _arr WHERE _arr._el %s %s)';
228
- result.predicates.push(util.format(q, fieldAndOperator.quotedField, fieldAndOperator.operator, value));
229
- } else {
230
- throw new Error('[326] Not implemented operator: "' + fieldAndOperator.operator + '" for type ' + fieldType);
231
- }
232
- } else {
233
- result.params.push((fieldType == FieldType.TIME && !(value instanceof Date)) ? new Date(value) : value);
234
- value = util.format("$%s", result.params.length + result.offset);
235
- result.predicates.push(util.format('%s %s %s', fieldAndOperator.quotedField, fieldAndOperator.operator, value));
236
- }
237
- return result;
238
- }
239
-
240
-
241
- function strip(arr: string[]): string[] {
242
- return arr.map((s) => s.trim()).filter(v => v != '');
243
- }
244
-
245
- function getOp(str: string): string {
246
- for (let i = 0; i < str.length; i++) {
247
- if (operationsMap[str.substr(i)]) {
248
- return str.substr(i);
249
- }
250
- }
251
- return '';
252
- }
253
-
254
- /**
255
- * Parse out a criterion key into something more intelligible. Supports quoted
256
- * field names and whitespace between components. If a function is applied on the field
257
- * it takes the first quoted string to assume to be the column. (e.g. max("score") -> field: "score"
258
- * in order to be able to recognize the field type)
259
- *
260
- * 'createdTs >' => {
261
- * field: 'createdTs',
262
- * quotedField: '"createdTs"',
263
- * operator:'>',
264
- * mutator:null
265
- * }
266
- *
267
- * @param {String} key Key in a format resembling "field [JSON operation+path] operation"
268
- * @return {Object} [description]
269
- */
270
- function parseKey(key: string): FieldAndOperator {
271
- key = key.trim();
272
-
273
- let userOp = getOp(key);
274
- if (userOp) {
275
- key = key.substr(0, key.length - userOp.length)
276
- }
277
- let operation = operationsMap[userOp] || {};
278
- let jsonRegexp = /(->[^>]|->>|#>[^>]|#>>)/;
279
-
280
- let field: string | undefined;
281
- let quotedField: string;
282
-
283
- let quotedByUser = key.indexOf('"') > -1; //key[0]=='"'; -> lets make it possible to write transformed columns, e.g. LOWER("field")
284
- if (quotedByUser) {
285
- quotedField = key;
286
- //field is used for find out the type of the field, so lets restore it if possible, grab the first quoted string
287
- field = /[^"]*"([^"]*)".*/.exec(key)?.[1];
288
- if (!quotedField || !field) {
289
- throw new Error('Invalid field:' + key);
290
- }
291
- } else {
292
- let parts = strip(key.split(jsonRegexp));
293
- field = parts.shift();
294
- if (!field) {
295
- throw new Error('Invalid field:' + key);
296
- }
297
- quotedField = pgUtils.quoteFieldName(field);
298
-
299
- if (parts.length > 1) {
300
- let jsonOp = parts.shift()!;
301
- let jsonKey = parts.shift()!;
302
-
303
- jsonKey = pgUtils.quoteFieldNameJsonbOrPosition(jsonKey);
304
- quotedField = util.format('%s%s%s', quotedField, jsonOp, jsonKey);
305
- }
306
- }
307
-
308
-
309
- if (operation.fieldMutator) {
310
- quotedField = operation.fieldMutator(field, quotedField);
311
- }
312
-
313
-
314
- return {
315
- field: field,
316
- quotedField: quotedField,
317
- operator: (operation.operator || '=').toUpperCase(),
318
- mutator: operation.mutator,
319
- originalOp: userOp
320
- };
321
- }
322
-
323
-
324
- export default generateWhere;
325
-
package/src/test/init.sql DELETED
@@ -1,122 +0,0 @@
1
- SET search_path TO __SCHEMA__;
2
- DROP FUNCTION IF EXISTS list_gold_users();
3
- DROP FUNCTION IF EXISTS increment();
4
-
5
- -- drop tables
6
- DROP VIEW IF EXISTS "users_view";
7
- DROP TABLE IF EXISTS "users";
8
- DROP TABLE IF EXISTS "groups";
9
- DROP TABLE IF EXISTS "types";
10
- -- drop sequences
11
- DROP SEQUENCE IF EXISTS "users_id_seq";
12
- -- drop types
13
- DROP TYPE IF EXISTS __SCHEMA__."membershipType";
14
- DROP TYPE IF EXISTS __SCHEMA__."categoryType";
15
- DROP TYPE IF EXISTS __SCHEMA__."permissionForResourceType";
16
- DROP TYPE IF EXISTS __SCHEMA__."permissionType";
17
-
18
- DROP FUNCTION IF EXISTS update_tsv();
19
-
20
-
21
- CREATE TYPE __SCHEMA__."membershipType" AS ENUM ('bronze', 'silver', 'gold');
22
- CREATE TYPE __SCHEMA__."categoryType" AS ENUM ('sport', 'food', 'tech', 'music');
23
- CREATE TYPE __SCHEMA__."permissionType" AS ENUM ('read', 'write', 'admin');
24
- CREATE TYPE __SCHEMA__."permissionForResourceType" AS (
25
- "permission" "permissionType",
26
- "resource" "text"
27
- );
28
-
29
- CREATE TABLE IF NOT EXISTS "groups" (
30
- "id" SERIAL PRIMARY KEY,
31
- "name" varchar UNIQUE NOT NULL
32
- );
33
-
34
- CREATE SEQUENCE "users_id_seq";
35
- CREATE TABLE IF NOT EXISTS "users" (
36
- "id" varchar PRIMARY KEY NOT NULL DEFAULT ('us' || nextval('users_id_seq')::text || (LPAD(floor(random()*100)::text, 2, '0'))),
37
- "name" varchar UNIQUE NOT NULL,
38
- "aCategory" varchar,
39
-
40
- "textList" text[],
41
- "jsonbList" jsonb[],
42
- "numberList" integer[], -- int4
43
- "bigNumberList" bigInt[], -- int8
44
- "timestamptzList" timestamptz[],
45
-
46
- "membership" "membershipType",
47
- "favourites" "categoryType"[],
48
-
49
- "jsonList" jsonb,
50
- "jsonObject" jsonb,
51
- "mainGroup" integer REFERENCES groups(id),
52
- "permission" "permissionForResourceType",
53
- "permissionList" "permissionForResourceType"[],
54
-
55
- "tsv" tsvector,
56
- "updated" timestamp with time zone,
57
- "created" timestamp,
58
- "createdtz" timestamptz
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
-
83
-
84
- CREATE OR REPLACE FUNCTION update_updated_column() RETURNS TRIGGER AS $$
85
- BEGIN
86
- NEW.updated = now();
87
- RETURN NEW;
88
- END;
89
- $$ language 'plpgsql';
90
-
91
- CREATE TRIGGER "update_users_updated" BEFORE INSERT ON "users" FOR EACH ROW EXECUTE PROCEDURE __SCHEMA__.update_updated_column();
92
-
93
- CREATE OR REPLACE FUNCTION list_gold_users()
94
- RETURNS SETOF varchar AS $$
95
- SELECT name FROM __SCHEMA__.users WHERE membership = 'gold';
96
- $$ LANGUAGE SQL;
97
-
98
- CREATE OR REPLACE FUNCTION increment(i INT)
99
- RETURNS INT AS $$
100
- BEGIN
101
- RETURN i + 1;
102
- END;
103
- $$ LANGUAGE plpgsql;
104
-
105
- CREATE FUNCTION update_tsv() RETURNS trigger AS $$
106
- begin
107
- new.tsv :=
108
- setweight(to_tsvector('pg_catalog.english', coalesce(new.name,'')), 'A') ||
109
- setweight(to_tsvector('pg_catalog.english', coalesce(new."aCategory",'')), 'B') ||
110
- setweight(to_tsvector('pg_catalog.english', coalesce(new."jsonList"::text,'')), 'C');
111
- return new;
112
- end
113
- $$ LANGUAGE plpgsql;
114
-
115
- CREATE TRIGGER update_tsv BEFORE INSERT OR UPDATE ON __SCHEMA__."users" FOR EACH ROW EXECUTE PROCEDURE update_tsv();
116
-
117
- CREATE OR REPLACE FUNCTION LOWER(text[]) RETURNS text[] LANGUAGE SQL IMMUTABLE AS
118
- $$
119
- SELECT array_agg(LOWER(value)) FROM unnest($1) value;
120
- $$;
121
-
122
- CREATE OR REPLACE VIEW users_view AS SELECT * FROM users;