prostgles-server 4.2.157 → 4.2.159

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 (159) hide show
  1. package/dist/Auth/AuthHandler.js +2 -2
  2. package/dist/Auth/AuthHandler.js.map +1 -1
  3. package/dist/Auth/AuthTypes.d.ts +4 -8
  4. package/dist/Auth/AuthTypes.d.ts.map +1 -1
  5. package/dist/Auth/setAuthProviders.d.ts +1 -1
  6. package/dist/Auth/setAuthProviders.d.ts.map +1 -1
  7. package/dist/Auth/setAuthProviders.js +6 -7
  8. package/dist/Auth/setAuthProviders.js.map +1 -1
  9. package/dist/Auth/setEmailProvider.d.ts +1 -1
  10. package/dist/Auth/setEmailProvider.d.ts.map +1 -1
  11. package/dist/Auth/setEmailProvider.js +22 -2
  12. package/dist/Auth/setEmailProvider.js.map +1 -1
  13. package/dist/Auth/setupAuthRoutes.js +1 -1
  14. package/dist/Auth/setupAuthRoutes.js.map +1 -1
  15. package/dist/Prostgles.d.ts +1 -0
  16. package/dist/Prostgles.d.ts.map +1 -1
  17. package/dist/Prostgles.js +6 -0
  18. package/dist/Prostgles.js.map +1 -1
  19. package/dist/initProstgles.d.ts.map +1 -1
  20. package/dist/initProstgles.js +2 -6
  21. package/dist/initProstgles.js.map +1 -1
  22. package/package.json +1 -1
  23. package/lib/Auth/AuthHandler.ts +0 -436
  24. package/lib/Auth/AuthTypes.ts +0 -285
  25. package/lib/Auth/getSafeReturnURL.ts +0 -35
  26. package/lib/Auth/sendEmail.ts +0 -83
  27. package/lib/Auth/setAuthProviders.ts +0 -129
  28. package/lib/Auth/setEmailProvider.ts +0 -63
  29. package/lib/Auth/setupAuthRoutes.ts +0 -161
  30. package/lib/DBEventsManager.ts +0 -178
  31. package/lib/DBSchemaBuilder.ts +0 -225
  32. package/lib/DboBuilder/DboBuilder.ts +0 -319
  33. package/lib/DboBuilder/DboBuilderTypes.ts +0 -361
  34. package/lib/DboBuilder/QueryBuilder/Functions.ts +0 -1153
  35. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +0 -288
  36. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +0 -263
  37. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +0 -271
  38. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +0 -136
  39. package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +0 -22
  40. package/lib/DboBuilder/QueryStreamer.ts +0 -250
  41. package/lib/DboBuilder/TableHandler/DataValidator.ts +0 -428
  42. package/lib/DboBuilder/TableHandler/TableHandler.ts +0 -205
  43. package/lib/DboBuilder/TableHandler/delete.ts +0 -115
  44. package/lib/DboBuilder/TableHandler/insert.ts +0 -183
  45. package/lib/DboBuilder/TableHandler/insertTest.ts +0 -78
  46. package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +0 -62
  47. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +0 -134
  48. package/lib/DboBuilder/TableHandler/update.ts +0 -126
  49. package/lib/DboBuilder/TableHandler/updateBatch.ts +0 -49
  50. package/lib/DboBuilder/TableHandler/updateFile.ts +0 -48
  51. package/lib/DboBuilder/TableHandler/upsert.ts +0 -34
  52. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +0 -393
  53. package/lib/DboBuilder/ViewHandler/count.ts +0 -38
  54. package/lib/DboBuilder/ViewHandler/find.ts +0 -153
  55. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +0 -73
  56. package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +0 -74
  57. package/lib/DboBuilder/ViewHandler/getInfo.ts +0 -32
  58. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +0 -84
  59. package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +0 -96
  60. package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +0 -105
  61. package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +0 -208
  62. package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +0 -163
  63. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +0 -90
  64. package/lib/DboBuilder/ViewHandler/size.ts +0 -37
  65. package/lib/DboBuilder/ViewHandler/subscribe.ts +0 -118
  66. package/lib/DboBuilder/ViewHandler/validateViewRules.ts +0 -70
  67. package/lib/DboBuilder/dboBuilderUtils.ts +0 -222
  68. package/lib/DboBuilder/getColumns.ts +0 -114
  69. package/lib/DboBuilder/getCondition.ts +0 -201
  70. package/lib/DboBuilder/getSubscribeRelatedTables.ts +0 -190
  71. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +0 -426
  72. package/lib/DboBuilder/insertNestedRecords.ts +0 -355
  73. package/lib/DboBuilder/parseUpdateRules.ts +0 -187
  74. package/lib/DboBuilder/prepareShortestJoinPaths.ts +0 -186
  75. package/lib/DboBuilder/runSQL.ts +0 -182
  76. package/lib/DboBuilder/runTransaction.ts +0 -50
  77. package/lib/DboBuilder/sqlErrCodeToMsg.ts +0 -254
  78. package/lib/DboBuilder/uploadFile.ts +0 -69
  79. package/lib/Event_Trigger_Tags.ts +0 -118
  80. package/lib/FileManager/FileManager.ts +0 -358
  81. package/lib/FileManager/getValidatedFileType.ts +0 -69
  82. package/lib/FileManager/initFileManager.ts +0 -187
  83. package/lib/FileManager/upload.ts +0 -62
  84. package/lib/FileManager/uploadStream.ts +0 -79
  85. package/lib/Filtering.ts +0 -463
  86. package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +0 -502
  87. package/lib/JSONBValidation/validation.ts +0 -143
  88. package/lib/Logging.ts +0 -127
  89. package/lib/PostgresNotifListenManager.ts +0 -143
  90. package/lib/Prostgles.ts +0 -479
  91. package/lib/ProstglesTypes.ts +0 -196
  92. package/lib/PubSubManager/PubSubManager.ts +0 -609
  93. package/lib/PubSubManager/addSub.ts +0 -138
  94. package/lib/PubSubManager/addSync.ts +0 -141
  95. package/lib/PubSubManager/getCreatePubSubManagerError.ts +0 -72
  96. package/lib/PubSubManager/getPubSubManagerInitQuery.ts +0 -662
  97. package/lib/PubSubManager/initPubSubManager.ts +0 -79
  98. package/lib/PubSubManager/notifListener.ts +0 -173
  99. package/lib/PubSubManager/orphanTriggerCheck.ts +0 -70
  100. package/lib/PubSubManager/pushSubData.ts +0 -55
  101. package/lib/PublishParser/PublishParser.ts +0 -162
  102. package/lib/PublishParser/getFileTableRules.ts +0 -124
  103. package/lib/PublishParser/getSchemaFromPublish.ts +0 -141
  104. package/lib/PublishParser/getTableRulesWithoutFileTable.ts +0 -177
  105. package/lib/PublishParser/publishTypesAndUtils.ts +0 -399
  106. package/lib/RestApi.ts +0 -127
  107. package/lib/SchemaWatch/SchemaWatch.ts +0 -90
  108. package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +0 -3
  109. package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +0 -45
  110. package/lib/SchemaWatch/getWatchSchemaTagList.ts +0 -27
  111. package/lib/SyncReplication.ts +0 -557
  112. package/lib/TableConfig/TableConfig.ts +0 -468
  113. package/lib/TableConfig/getColumnDefinitionQuery.ts +0 -111
  114. package/lib/TableConfig/getConstraintDefinitionQueries.ts +0 -95
  115. package/lib/TableConfig/getFutureTableSchema.ts +0 -64
  116. package/lib/TableConfig/getPGIndexes.ts +0 -53
  117. package/lib/TableConfig/getTableColumnQueries.ts +0 -129
  118. package/lib/TableConfig/initTableConfig.ts +0 -326
  119. package/lib/index.ts +0 -13
  120. package/lib/initProstgles.ts +0 -322
  121. package/lib/onSocketConnected.ts +0 -102
  122. package/lib/runClientRequest.ts +0 -129
  123. package/lib/shortestPath.ts +0 -122
  124. package/lib/typeTests/DBoGenerated.d.ts +0 -320
  125. package/lib/typeTests/dboTypeCheck.ts +0 -81
  126. package/lib/utils.ts +0 -15
  127. package/tests/client/hooks.spec.ts +0 -205
  128. package/tests/client/index.ts +0 -139
  129. package/tests/client/package-lock.json +0 -637
  130. package/tests/client/package.json +0 -26
  131. package/tests/client/renderReactHook.ts +0 -177
  132. package/tests/client/tsconfig.json +0 -15
  133. package/tests/client/useProstgles.spec.ts +0 -120
  134. package/tests/clientFileTests.spec.ts +0 -102
  135. package/tests/clientOnlyQueries.spec.ts +0 -667
  136. package/tests/clientRestApi.spec.ts +0 -82
  137. package/tests/config_test/DBoGenerated.d.ts +0 -407
  138. package/tests/config_test/index.html +0 -109
  139. package/tests/config_test/index.js +0 -86
  140. package/tests/config_test/index.js.map +0 -1
  141. package/tests/config_test/index.ts +0 -91
  142. package/tests/config_test/init.sql +0 -48
  143. package/tests/config_test/package.json +0 -29
  144. package/tests/config_test/tsconfig.json +0 -23
  145. package/tests/config_testDBoGenerated.d.ts +0 -407
  146. package/tests/isomorphicQueries.spec.ts +0 -1493
  147. package/tests/server/DBoGenerated.d.ts +0 -537
  148. package/tests/server/index.html +0 -73
  149. package/tests/server/index.ts +0 -289
  150. package/tests/server/init.sql +0 -224
  151. package/tests/server/package-lock.json +0 -2164
  152. package/tests/server/package.json +0 -25
  153. package/tests/server/publishTypeCheck.ts +0 -136
  154. package/tests/server/server.ts +0 -35
  155. package/tests/server/testPublish.ts +0 -147
  156. package/tests/server/testTableConfig.ts +0 -156
  157. package/tests/server/tsconfig.json +0 -22
  158. package/tests/serverOnlyQueries.spec.ts +0 -32
  159. package/tests/test.sh +0 -20
@@ -1,79 +0,0 @@
1
- import { FileManager, OnProgress, UploadedItem } from "./FileManager";
2
- import * as fs from 'fs';
3
- import * as stream from 'stream';
4
- import * as path from "path";
5
-
6
- export function uploadStream(
7
- this: FileManager,
8
- name: string,
9
- mime: string,
10
- onProgress?: OnProgress,
11
- onError?: (error: any)=>void,
12
- onEnd?: (item: UploadedItem)=>void,
13
- expectedSizeBytes?: number
14
- ){
15
- const passThrough = new stream.PassThrough();
16
-
17
- if(!this.cloudClient && "localFolderPath" in this.config) {
18
-
19
- try {
20
- this.checkFreeSpace(this.config.localFolderPath, expectedSizeBytes).catch(err => {
21
- onError?.(err)
22
- passThrough.end();
23
- });
24
- const url = this.getLocalFileUrl(name)
25
- fs.mkdirSync(this.config.localFolderPath, { recursive: true });
26
- const filePath = path.resolve(`${this.config.localFolderPath}/${name}`);
27
- const writeStream = fs.createWriteStream(filePath);
28
-
29
- let errored = false;
30
- let loaded = 0;
31
- writeStream.on('error', err => {
32
- errored = true;
33
- onError?.(err)
34
- });
35
-
36
- let lastProgress = Date.now();
37
- const throttle = 1000;
38
- if(onProgress){
39
- passThrough.on('data', function(chunk){
40
- loaded += chunk.length;
41
- const now = Date.now();
42
- if(now - lastProgress > throttle){
43
- lastProgress = now;
44
- onProgress?.({ loaded, total: expectedSizeBytes ?? 0 });
45
- }
46
- });
47
- }
48
-
49
- if(onEnd) {
50
- writeStream.on('finish', () => {
51
- if(errored) return;
52
- let content_length = 0;
53
- try {
54
- content_length = fs.statSync(filePath).size;
55
-
56
- onEnd?.({
57
- url,
58
- filePath,
59
- etag: `none`,
60
- content_length
61
- })
62
- } catch (err){
63
- onError?.(err)
64
- }
65
- })
66
- }
67
-
68
-
69
- passThrough.pipe(writeStream);
70
- } catch(err){
71
- onError?.(err)
72
- }
73
- } else {
74
- this.upload(passThrough, name, mime, onProgress).then(onEnd)
75
- .catch(onError)
76
- }
77
-
78
- return passThrough;
79
- }
package/lib/Filtering.ts DELETED
@@ -1,463 +0,0 @@
1
-
2
-
3
- import {
4
- BetweenFilterKeys,
5
- CompareFilterKeys,
6
- CompareInFilterKeys,
7
- FilterDataType,
8
- FullFilter,
9
- GeomFilterKeys, GeomFilter_Funcs,
10
- JsonbFilterKeys,
11
- TextFilterKeys,
12
- TextFilter_FullTextSearchFilterKeys,
13
- getKeys,
14
- isEmpty,
15
- isObject
16
- } from "prostgles-types";
17
- import { SelectItem } from "./DboBuilder/QueryBuilder/QueryBuilder";
18
- import { pgp } from "./DboBuilder/DboBuilderTypes";
19
-
20
-
21
- export const FILTER_OPERANDS = [
22
- ...TextFilterKeys,
23
- ...JsonbFilterKeys,
24
- ...CompareFilterKeys,
25
- ...BetweenFilterKeys,
26
- ...CompareInFilterKeys
27
- ] as const;
28
-
29
- export const FILTER_OPERAND_TO_SQL_OPERAND = Object.fromEntries(
30
- FILTER_OPERANDS.map(filterOperand => {
31
- let sqlOperand = filterOperand as string;
32
- if (filterOperand === "$eq") sqlOperand = "=";
33
- else if (filterOperand === "$gt") sqlOperand = ">";
34
- else if (filterOperand === "$gte") sqlOperand = ">=";
35
- else if (filterOperand === "$lt") sqlOperand = "<";
36
- else if (filterOperand === "$lte") sqlOperand = "<=";
37
- else if (filterOperand === "$ne") sqlOperand = "<>";
38
- else if (filterOperand === "$like") sqlOperand = "LIKE";
39
- else if (filterOperand === "$ilike") sqlOperand = "ILIKE";
40
- else if (filterOperand === "$nlike") sqlOperand = "NOT LIKE";
41
- else if (filterOperand === "$nilike") sqlOperand = "NOT ILIKE";
42
- else if (filterOperand === "$in") sqlOperand = "IN";
43
- else if (filterOperand === "$nin") sqlOperand = "NOT IN";
44
- else if (filterOperand === "$between") sqlOperand = "BETWEEN";
45
- else if (filterOperand === "$notBetween") sqlOperand = "NOT BETWEEN";
46
- else if (filterOperand === "$isDistinctFrom") sqlOperand = "IS DISTINCT FROM";
47
- else if (filterOperand === "$isNotDistinctFrom") sqlOperand = "IS NOT DISTINCT FROM";
48
- return [filterOperand, sqlOperand];
49
- })
50
- ) as Record<typeof FILTER_OPERANDS[number], string>;
51
-
52
- /**
53
- * Parse a single filter
54
- * Ensure only single key objects reach this point
55
- */
56
- type ParseFilterItemArgs = {
57
- filter: FullFilter<void, void>;
58
- select: SelectItem[] | undefined;
59
- tableAlias: string | undefined;
60
- allowedColumnNames: string[];
61
- };
62
-
63
- export const parseFilterItem = (args: ParseFilterItemArgs): string => {
64
- const { filter: _f, select, tableAlias, allowedColumnNames } = args;
65
-
66
- if(!_f || isEmpty(_f)) return "";
67
-
68
- const mErr = (msg: string) => {
69
- throw `${msg}: ${JSON.stringify(_f, null, 2)}`
70
- };
71
- const asValue = (v: any) => pgp.as.format("$1", [v]);
72
-
73
- const fKeys = getKeys(_f)
74
- if(fKeys.length === 0){
75
- return "";
76
-
77
- /**
78
- * { field1: cond1, field2: cond2 }
79
- */
80
- } else if(fKeys.length > 1){
81
- return fKeys.map(fk => parseFilterItem({
82
- filter: { [fk]: _f[fk] },
83
- select,
84
- tableAlias,
85
- allowedColumnNames,
86
- }))
87
- .sort() /* sorted to ensure duplicate subscription channels are not created due to different condition order */
88
- .join(" AND ")
89
- }
90
-
91
- const fKey: string = fKeys[0]!;
92
-
93
- let selItem: SelectItem | undefined;
94
- if(select) {
95
- selItem = select.find(s => fKey === s.alias);
96
- }
97
- let rightF: FilterDataType<any> = (_f as any)[fKey];
98
-
99
- const validateSelectedItemFilter = (selectedItem: SelectItem | undefined) => {
100
- const fields = selectedItem?.getFields();
101
- if(Array.isArray(fields) && fields.length > 1) {
102
- const dissallowedFields = fields.filter(fname => !allowedColumnNames.includes(fname));
103
- if(dissallowedFields.length){
104
- throw new Error(`Invalid/disallowed columns found in filter: ${dissallowedFields}`)
105
- }
106
- }
107
- }
108
- const getLeftQ = (selItm: SelectItem) => {
109
- validateSelectedItemFilter(selItem);
110
- if(selItm.type === "function" || selItm.type === "aggregation") return selItm.getQuery();
111
- return selItm.getQuery(tableAlias);
112
- }
113
-
114
- /**
115
- * Parsed left side of the query
116
- */
117
- let leftQ: string | undefined;// = asName(selItem.alias);
118
-
119
- /*
120
- Select item not found.
121
- Check if dot/json notation. Build obj if necessary
122
- */
123
- const dot_notation_delims = ["->", "."];
124
- if(!selItem){
125
-
126
- /* See if dot notation. Pick the best matching starting string */
127
- if(select){
128
- selItem = select.find(s =>
129
- dot_notation_delims.find(delimiter => fKey.startsWith(s.alias + delimiter))
130
- );
131
- validateSelectedItemFilter(selItem);
132
- }
133
- if(!selItem) {
134
- return mErr("Bad filter. Could not match to a column or alias or dot notation" + select?.map(s => s.alias));
135
- }
136
-
137
- let remainingStr = fKey.slice(selItem.alias.length);
138
-
139
- /* Is json path spec */
140
- if(remainingStr.startsWith("->")){
141
-
142
- /** Has shorthand operand 'col->>key.<>' */
143
- const matchingOperand = CompareFilterKeys.find(operand => remainingStr.endsWith(`.${operand}`));
144
- if(matchingOperand){
145
- remainingStr = remainingStr.slice(0, -matchingOperand.length - 1)
146
- rightF = { [matchingOperand]: rightF }
147
- }
148
-
149
- leftQ = getLeftQ(selItem);
150
-
151
- /**
152
- * get json path separators. Expecting -> to come first
153
- */
154
- type GetSepRes = { idx: number; sep: string } | undefined
155
- const getSep = (fromIdx = 0): GetSepRes => {
156
- const strPart = remainingStr.slice(fromIdx)
157
- let idx = strPart.indexOf("->");
158
- const idxx = strPart.indexOf("->>");
159
- if(idx > -1) {
160
- /* if -> matches then check if it's the last separator */
161
- if(idx === idxx) return { idx: idx + fromIdx, sep: "->>" }
162
- return { idx: idx + fromIdx, sep: "->" }
163
- }
164
- idx = strPart.indexOf("->>");
165
- if(idx > -1) {
166
- return { idx: idx + fromIdx, sep: "->>" }
167
- }
168
-
169
- return undefined;
170
- }
171
-
172
-
173
- let currSep = getSep();
174
- while(currSep){
175
- let nextSep = getSep(currSep.idx + currSep.sep.length);
176
-
177
- let nextIdx = nextSep? nextSep.idx : remainingStr.length;
178
-
179
- /* If ending in set then add set as well into key */
180
- if(nextSep && nextIdx + nextSep.sep.length === remainingStr.length) {
181
- nextIdx = remainingStr.length;
182
- nextSep = undefined;
183
- }
184
-
185
- leftQ += currSep.sep + asValue(remainingStr.slice(currSep.idx + currSep.sep.length, nextIdx));
186
- currSep = nextSep;
187
- }
188
-
189
- /*
190
- Is collapsed filter spec e.g. { "col.$ilike": 'text' }
191
- will transform into { col: { $ilike: ['text'] } }
192
- */
193
- } else if(remainingStr.startsWith(".")){
194
- leftQ = getLeftQ(selItem);
195
-
196
- const getSep = (fromIdx = 0) => {
197
- const idx = remainingStr.slice(fromIdx).indexOf(".");
198
- if(idx > -1) return fromIdx + idx;
199
- return idx;
200
- }
201
- let currIdx = getSep();
202
- const res: any = {};
203
- let curObj = res;
204
-
205
- while(currIdx > -1){
206
- let nextIdx = getSep(currIdx + 1);
207
- let nIdx = nextIdx > -1? nextIdx : remainingStr.length;
208
-
209
- /* If ending in dot then add dot as well into key */
210
- if(nextIdx + 1 === remainingStr.length) {
211
- nIdx = remainingStr.length;
212
- nextIdx = -1;
213
- }
214
-
215
- const key = remainingStr.slice(currIdx + 1, nIdx);
216
- curObj[key] = nextIdx > -1? {} : (_f as any)[fKey];
217
- curObj = curObj[key];
218
-
219
- currIdx = nextIdx;
220
- }
221
-
222
- rightF = res;
223
- } else {
224
- // console.trace(141, select, selItem, remainingStr)
225
- mErr("Bad filter. Could not find the valid col name or alias or col json path")
226
- }
227
-
228
- } else {
229
- leftQ = getLeftQ(selItem);
230
- }
231
-
232
- if(!leftQ) mErr("Internal error: leftQ missing?!");
233
-
234
- const parseRightVal = (val: any, expect?: "csv" | "array" | "json" | "jsonb") => {
235
- try {
236
- return parseFilterRightValue(val, { selectItem: selItem, expect });
237
- } catch(e: any){
238
- return mErr(e);
239
- }
240
- }
241
-
242
- /* Matching sel item */
243
- if(isObject(rightF)){
244
-
245
- const filterKeys = Object.keys(rightF);
246
- let filterOperand: typeof FILTER_OPERANDS[number] = filterKeys[0] as any;
247
-
248
- /** JSON cannot be compared so we'll cast it to TEXT */
249
- if(selItem?.column_udt_type === "json" || TextFilterKeys.includes(filterOperand as any)){
250
- leftQ += "::TEXT "
251
- }
252
-
253
- /** It's an object key which means it's an equality comparison against a json object */
254
- if(selItem?.column_udt_type?.startsWith("json") && !FILTER_OPERANDS.includes(filterOperand)){
255
- return leftQ + " = " + parseRightVal(rightF);
256
- }
257
-
258
- let filterValue = rightF[filterOperand];
259
- const ALLOWED_FUNCS = [ ...GeomFilter_Funcs, ...TextFilter_FullTextSearchFilterKeys] as const;
260
- let funcName: undefined | typeof ALLOWED_FUNCS[number];
261
- let funcArgs: undefined | any[];
262
-
263
- if(selItem.column_udt_type === "interval" && isObject(rightF) && Object.values(rightF).every(v => Number.isFinite(v))){
264
- filterOperand = "=";
265
- filterValue = Object.entries(rightF).map(([k, v]) => `${v}${k}`).join(" ");
266
-
267
- } else if(filterKeys.length !== 1 && selItem.column_udt_type !== "jsonb") {
268
- return mErr("Bad filter. Expecting one key only");
269
-
270
- } else if(isObject(filterValue) && !(filterValue instanceof Date)){
271
-
272
- /**
273
- * Filter notation
274
- * geom && st_makeenvelope(funcArgs)
275
- */
276
- const filterValueKeys = Object.keys(filterValue);
277
- funcName = filterValueKeys[0] as any;
278
- if(ALLOWED_FUNCS.includes(funcName as any)){
279
- funcArgs = filterValue[funcName as any];
280
- } else {
281
- funcName = undefined;
282
- }
283
- }
284
-
285
- /** st_makeenvelope */
286
- if(GeomFilterKeys.includes(filterOperand as any) && funcName && GeomFilter_Funcs.includes(funcName as any)){
287
-
288
- /**
289
- * If leftQ is geography then:
290
- * - err can happen: 'Antipodal (180 degrees long) edge detected!'
291
- * - inacurrate results at large envelopes due to the curvature of the earth
292
- * https://gis.stackexchange.com/questions/78816/maximum-size-on-the-bounding-box-with-st-makeenvelope-and-and-geography-colum
293
- */
294
- if(funcName.toLowerCase() === "st_makeenvelope") {
295
- leftQ += "::geometry";
296
- }
297
-
298
- return `${leftQ} ${filterOperand} ${funcName}${parseRightVal(funcArgs, "csv")}`;
299
-
300
- } else if(["=", "$eq"].includes(filterOperand) && !funcName){
301
- if(filterValue === null) return leftQ + " IS NULL ";
302
- return leftQ + " = " + parseRightVal(filterValue);
303
-
304
- } else if(["<>", "$ne"].includes(filterOperand)){
305
- if(filterValue === null) return leftQ + " IS NOT NULL ";
306
- return leftQ + " <> " + parseRightVal(filterValue);
307
-
308
- } else if([">", "$gt"].includes(filterOperand)){
309
- return leftQ + " > " + parseRightVal(filterValue);
310
-
311
- } else if(["<", "$lt"].includes(filterOperand)){
312
- return leftQ + " < " + parseRightVal(filterValue);
313
-
314
- } else if([">=", "$gte"].includes(filterOperand)){
315
- return leftQ + " >= " + parseRightVal(filterValue);
316
-
317
- } else if(["<=", "$lte"].includes(filterOperand)){
318
- return leftQ + " <= " + parseRightVal(filterValue);
319
-
320
- } else if(["$in"].includes(filterOperand)){
321
- if(!filterValue?.length) {
322
- return " FALSE ";
323
- }
324
-
325
- const filterNonNullValues: any[] = filterValue.filter((v: any) => v !== null);
326
- let c1 = "", c2 = "";
327
- if(filterNonNullValues.length) {
328
- c1 = leftQ + " IN " + parseRightVal(filterNonNullValues, "csv");
329
- }
330
- if(filterValue.includes(null)) {
331
- c2 = ` ${leftQ} IS NULL `;
332
- }
333
- return [c1, c2].filter(c => c).join(" OR ");
334
-
335
- } else if(["$nin"].includes(filterOperand)){
336
- if(!filterValue?.length) {
337
- return " TRUE ";
338
- }
339
-
340
- const nonNullFilterValues: any[] = filterValue.filter((v: any) => v !== null);
341
- let c1 = "", c2 = "";
342
- if(nonNullFilterValues.length) c1 = leftQ + " NOT IN " + parseRightVal(nonNullFilterValues, "csv");
343
- if(filterValue.includes(null)) c2 = ` ${leftQ} IS NOT NULL `;
344
- return [c1, c2].filter(c => c).join(" AND ");
345
-
346
- } else if(["$between"].includes(filterOperand)){
347
- if(!Array.isArray(filterValue) || filterValue.length !== 2){
348
- return mErr("Between filter expects an array of two values");
349
- }
350
- return leftQ + " BETWEEN " + asValue(filterValue[0]) + " AND " + asValue(filterValue[1]);
351
-
352
- } else if(["$ilike"].includes(filterOperand)){
353
- return leftQ + " ILIKE " + asValue(filterValue);
354
-
355
- } else if(["$like"].includes(filterOperand)){
356
- return leftQ + " LIKE " + asValue(filterValue);
357
-
358
- } else if(["$nilike"].includes(filterOperand)){
359
- return leftQ + " NOT ILIKE " + asValue(filterValue);
360
-
361
- } else if(["$nlike"].includes(filterOperand)){
362
- return leftQ + " NOT LIKE " + asValue(filterValue);
363
-
364
- } else if(filterOperand === "$isDistinctFrom" || filterOperand === "$isNotDistinctFrom"){
365
- const operator = FILTER_OPERAND_TO_SQL_OPERAND[filterOperand];
366
- return leftQ + ` ${operator} ` + asValue(filterValue);
367
-
368
- /* MAYBE TEXT OR MAYBE ARRAY */
369
- } else if(["@>", "<@", "$contains", "$containedBy", "$overlaps", "&&", "@@"].includes(filterOperand)){
370
- const operand = filterOperand === "@@"? "@@":
371
- ["@>", "$contains"].includes(filterOperand)? "@>" :
372
- ["&&", "$overlaps"].includes(filterOperand)? "&&" :
373
- "<@";
374
-
375
- /* Array for sure */
376
- if(Array.isArray(filterValue)){
377
- return leftQ + operand + parseRightVal(filterValue, "array");
378
-
379
- /* FTSQuery */
380
- } else if(["@@"].includes(filterOperand) && TextFilter_FullTextSearchFilterKeys.includes(funcName! as any)) {
381
- let lq = `to_tsvector(${leftQ}::text)`;
382
- if(selItem && selItem.columnPGDataType === "tsvector") lq = leftQ!;
383
-
384
- const res = `${lq} ${operand} ` + `${funcName}${parseRightVal(funcArgs, "csv")}`;
385
-
386
- return res;
387
- } else {
388
- return mErr("Unrecognised filter operand: " + filterOperand + " ");
389
- }
390
-
391
- } else {
392
-
393
- return mErr("Unrecognised filter operand: " + filterOperand + " ");
394
- }
395
-
396
-
397
- } else {
398
-
399
- /* Is an equal filter */
400
- if(rightF === null){
401
- return leftQ + " IS NULL ";
402
- } else {
403
-
404
- /**
405
- * Ensure that when comparing an array to a json column, the array is cast to json
406
- */
407
- let valueStr = asValue(rightF);
408
- if(selItem?.column_udt_type?.startsWith("json") && Array.isArray(rightF)){
409
- valueStr = pgp.as.format(`$1::jsonb`, [JSON.stringify(rightF)]);
410
- }
411
- return `${leftQ} = ${valueStr}`;
412
- }
413
- }
414
- }
415
-
416
- type ParseRightValOpts = {
417
- expect?: "csv" | "array" | "json" | "jsonb";
418
- selectItem: SelectItem | undefined;
419
- }
420
- export const parseFilterRightValue = (val: any, { expect, selectItem }: ParseRightValOpts) => {
421
- const asValue = (v: any) => pgp.as.format("$1", [v]);
422
- const checkIfArr = () => {
423
- if(!Array.isArray(val)) {
424
- throw "This type of filter/column expects an Array of items";
425
- }
426
- }
427
- if(expect === "csv" || expect?.startsWith("json")){
428
- checkIfArr();
429
- return pgp.as.format(`($1:${expect})`, [val]);
430
-
431
- } else if(expect === "array" || selectItem?.columnPGDataType === "ARRAY"){
432
- checkIfArr();
433
- return pgp.as.format(" ARRAY[$1:csv]", [val]);
434
-
435
- }
436
-
437
- return asValue(val);
438
- }
439
-
440
- // ensure pgp is not NULL!!!
441
- // const asValue = v => v;// pgp.as.value;
442
-
443
- // const filters: FilterSpec[] = [
444
- // ...(["ilike", "like"].map(op => ({
445
- // operands: ["$" + op],
446
- // tsDataTypes: ["any"] as TSDataType[],
447
- // tsDefinition: ` { $${op}: string } `,
448
- // // data_types:
449
- // getQuery: (leftQuery: string, rightVal: any) => {
450
- // return `${leftQuery}::text ${op.toUpperCase()} ${asValue(rightVal)}::text`
451
- // }
452
- // }))),
453
- // {
454
- // operands: ["", "="],
455
- // tsDataTypes: ["any"],
456
- // tsDefinition: ` { "=": any } | any `,
457
- // // data_types:
458
- // getQuery: (leftQuery: string, rightVal: any) => {
459
- // if(rightVal === null) return`${leftQuery} IS NULL `;
460
- // return `${leftQuery} = ${asValue(rightVal)}`;
461
- // }
462
- // }
463
- // ];