prostgles-server 4.0.57 → 4.0.59

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 (221) hide show
  1. package/dist/DboBuilder/getColumns.d.ts.map +1 -1
  2. package/dist/DboBuilder/getColumns.js +1 -13
  3. package/dist/DboBuilder/getColumns.js.map +1 -1
  4. package/dist/DboBuilder/runSQL.js +2 -2
  5. package/dist/DboBuilder/runSQL.js.map +1 -1
  6. package/dist/Prostgles.d.ts.map +1 -1
  7. package/dist/PubSubManager/PubSubManager.d.ts +1 -1
  8. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  9. package/dist/PubSubManager/PubSubManager.js +14 -1
  10. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  11. package/lib/DboBuilder/getColumns.ts +1 -18
  12. package/lib/DboBuilder/runSQL.ts +2 -2
  13. package/lib/Prostgles.ts +3 -3
  14. package/lib/PubSubManager/PubSubManager.ts +14 -1
  15. package/package.json +2 -2
  16. package/tests/client/PID.txt +1 -1
  17. package/tests/client/package.json +2 -2
  18. package/tests/client/tsconfig.json +2 -1
  19. package/tests/isomorphic_queries.ts +11 -9
  20. package/tests/server/DBoGenerated.d.ts +1 -1
  21. package/tests/server/dboTypeCheck.ts +3 -3
  22. package/tests/server/index.ts +7 -6
  23. package/tests/server/package-lock.json +1 -1
  24. package/tests/server/package.json +3 -3
  25. package/tests/server/publishTypeCheck.ts +1 -1
  26. package/tests/server/tsconfig.json +3 -2
  27. package/tests/test.sh +2 -0
  28. package/dist/FileManager.d.ts +0 -143
  29. package/dist/FileManager.d.ts.map +0 -1
  30. package/dist/FileManager.js +0 -646
  31. package/dist/FileManager.js.map +0 -1
  32. package/dist/TableConfig.d.ts +0 -267
  33. package/dist/TableConfig.d.ts.map +0 -1
  34. package/dist/TableConfig.js +0 -463
  35. package/dist/TableConfig.js.map +0 -1
  36. package/dist/validation.d.ts +0 -126
  37. package/dist/validation.d.ts.map +0 -1
  38. package/dist/validation.js +0 -405
  39. package/dist/validation.js.map +0 -1
  40. package/lib/AuthHandler.d.ts +0 -187
  41. package/lib/AuthHandler.d.ts.map +0 -1
  42. package/lib/AuthHandler.js +0 -478
  43. package/lib/DBEventsManager.d.ts +0 -38
  44. package/lib/DBEventsManager.d.ts.map +0 -1
  45. package/lib/DBEventsManager.js +0 -140
  46. package/lib/DBSchemaBuilder.d.ts +0 -13
  47. package/lib/DBSchemaBuilder.d.ts.map +0 -1
  48. package/lib/DBSchemaBuilder.js +0 -145
  49. package/lib/DboBuilder/QueryBuilder/Functions.d.ts +0 -64
  50. package/lib/DboBuilder/QueryBuilder/Functions.d.ts.map +0 -1
  51. package/lib/DboBuilder/QueryBuilder/Functions.js +0 -984
  52. package/lib/DboBuilder/QueryBuilder/QueryBuilder.d.ts +0 -73
  53. package/lib/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +0 -1
  54. package/lib/DboBuilder/QueryBuilder/QueryBuilder.js +0 -335
  55. package/lib/DboBuilder/QueryBuilder/makeSelectQuery.d.ts +0 -8
  56. package/lib/DboBuilder/QueryBuilder/makeSelectQuery.d.ts.map +0 -1
  57. package/lib/DboBuilder/QueryBuilder/makeSelectQuery.js +0 -227
  58. package/lib/DboBuilder/TableHandler.d.ts +0 -37
  59. package/lib/DboBuilder/TableHandler.d.ts.map +0 -1
  60. package/lib/DboBuilder/TableHandler.js +0 -213
  61. package/lib/DboBuilder/ViewHandler.d.ts +0 -119
  62. package/lib/DboBuilder/ViewHandler.d.ts.map +0 -1
  63. package/lib/DboBuilder/ViewHandler.js +0 -1023
  64. package/lib/DboBuilder/delete.d.ts +0 -6
  65. package/lib/DboBuilder/delete.d.ts.map +0 -1
  66. package/lib/DboBuilder/delete.js +0 -128
  67. package/lib/DboBuilder/find.d.ts +0 -8
  68. package/lib/DboBuilder/find.d.ts.map +0 -1
  69. package/lib/DboBuilder/find.js +0 -91
  70. package/lib/DboBuilder/getColumns.d.ts +0 -12
  71. package/lib/DboBuilder/getColumns.d.ts.map +0 -1
  72. package/lib/DboBuilder/getColumns.js +0 -92
  73. package/lib/DboBuilder/getCondition.d.ts +0 -22
  74. package/lib/DboBuilder/getCondition.d.ts.map +0 -1
  75. package/lib/DboBuilder/getCondition.js +0 -236
  76. package/lib/DboBuilder/getSubscribeRelatedTables.d.ts +0 -20
  77. package/lib/DboBuilder/getSubscribeRelatedTables.d.ts.map +0 -1
  78. package/lib/DboBuilder/getSubscribeRelatedTables.js +0 -152
  79. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.d.ts +0 -3
  80. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.d.ts.map +0 -1
  81. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.js +0 -207
  82. package/lib/DboBuilder/insert.d.ts +0 -6
  83. package/lib/DboBuilder/insert.d.ts.map +0 -1
  84. package/lib/DboBuilder/insert.js +0 -180
  85. package/lib/DboBuilder/insertDataParse.d.ts +0 -12
  86. package/lib/DboBuilder/insertDataParse.d.ts.map +0 -1
  87. package/lib/DboBuilder/insertDataParse.js +0 -253
  88. package/lib/DboBuilder/parseUpdateRules.d.ts +0 -18
  89. package/lib/DboBuilder/parseUpdateRules.d.ts.map +0 -1
  90. package/lib/DboBuilder/parseUpdateRules.js +0 -123
  91. package/lib/DboBuilder/runSQL.d.ts +0 -7
  92. package/lib/DboBuilder/runSQL.d.ts.map +0 -1
  93. package/lib/DboBuilder/runSQL.js +0 -135
  94. package/lib/DboBuilder/subscribe.d.ts +0 -20
  95. package/lib/DboBuilder/subscribe.d.ts.map +0 -1
  96. package/lib/DboBuilder/subscribe.js +0 -90
  97. package/lib/DboBuilder/update.d.ts +0 -6
  98. package/lib/DboBuilder/update.d.ts.map +0 -1
  99. package/lib/DboBuilder/update.js +0 -151
  100. package/lib/DboBuilder/uploadFile.d.ts +0 -7
  101. package/lib/DboBuilder/uploadFile.d.ts.map +0 -1
  102. package/lib/DboBuilder/uploadFile.js +0 -53
  103. package/lib/DboBuilder.d.ts +0 -306
  104. package/lib/DboBuilder.d.ts.map +0 -1
  105. package/lib/DboBuilder.js +0 -745
  106. package/lib/Event_Trigger_Tags.d.ts +0 -4
  107. package/lib/Event_Trigger_Tags.d.ts.map +0 -1
  108. package/lib/Event_Trigger_Tags.js +0 -116
  109. package/lib/FileManager/FileManager.d.ts +0 -135
  110. package/lib/FileManager/FileManager.d.ts.map +0 -1
  111. package/lib/FileManager/FileManager.js +0 -303
  112. package/lib/FileManager/initFileManager.d.ts +0 -4
  113. package/lib/FileManager/initFileManager.d.ts.map +0 -1
  114. package/lib/FileManager/initFileManager.js +0 -231
  115. package/lib/FileManager/parseFile.d.ts +0 -15
  116. package/lib/FileManager/parseFile.d.ts.map +0 -1
  117. package/lib/FileManager/parseFile.js +0 -58
  118. package/lib/FileManager/upload.d.ts +0 -6
  119. package/lib/FileManager/upload.d.ts.map +0 -1
  120. package/lib/FileManager/upload.js +0 -98
  121. package/lib/FileManager/uploadStream.d.ts +0 -5
  122. package/lib/FileManager/uploadStream.d.ts.map +0 -1
  123. package/lib/FileManager/uploadStream.js +0 -92
  124. package/lib/Filtering.d.ts +0 -15
  125. package/lib/Filtering.d.ts.map +0 -1
  126. package/lib/Filtering.js +0 -336
  127. package/lib/JSONBValidation/validate_jsonb_schema_sql.d.ts +0 -4
  128. package/lib/JSONBValidation/validate_jsonb_schema_sql.d.ts.map +0 -1
  129. package/lib/JSONBValidation/validate_jsonb_schema_sql.js +0 -500
  130. package/lib/JSONBValidation/validation.d.ts +0 -9
  131. package/lib/JSONBValidation/validation.d.ts.map +0 -1
  132. package/lib/JSONBValidation/validation.js +0 -131
  133. package/lib/PostgresNotifListenManager.d.ts +0 -28
  134. package/lib/PostgresNotifListenManager.d.ts.map +0 -1
  135. package/lib/PostgresNotifListenManager.js +0 -134
  136. package/lib/Prostgles.d.ts +0 -289
  137. package/lib/Prostgles.d.ts.map +0 -1
  138. package/lib/Prostgles.js +0 -685
  139. package/lib/PubSubManager/PubSubManager.d.ts +0 -175
  140. package/lib/PubSubManager/PubSubManager.d.ts.map +0 -1
  141. package/lib/PubSubManager/PubSubManager.js +0 -452
  142. package/lib/PubSubManager/addSub.d.ts +0 -8
  143. package/lib/PubSubManager/addSub.d.ts.map +0 -1
  144. package/lib/PubSubManager/addSub.js +0 -166
  145. package/lib/PubSubManager/addSync.d.ts +0 -8
  146. package/lib/PubSubManager/addSync.d.ts.map +0 -1
  147. package/lib/PubSubManager/addSync.js +0 -109
  148. package/lib/PubSubManager/getInitQuery.d.ts +0 -9
  149. package/lib/PubSubManager/getInitQuery.d.ts.map +0 -1
  150. package/lib/PubSubManager/getInitQuery.js +0 -552
  151. package/lib/PubSubManager/initPubSubManager.d.ts +0 -3
  152. package/lib/PubSubManager/initPubSubManager.d.ts.map +0 -1
  153. package/lib/PubSubManager/initPubSubManager.js +0 -116
  154. package/lib/PubSubManager/notifListener.d.ts +0 -5
  155. package/lib/PubSubManager/notifListener.d.ts.map +0 -1
  156. package/lib/PubSubManager/notifListener.js +0 -100
  157. package/lib/PubSubManager/pushSubData.d.ts +0 -3
  158. package/lib/PubSubManager/pushSubData.d.ts.map +0 -1
  159. package/lib/PubSubManager/pushSubData.js +0 -51
  160. package/lib/PublishParser.d.ts +0 -284
  161. package/lib/PublishParser.d.ts.map +0 -1
  162. package/lib/PublishParser.js +0 -421
  163. package/lib/SchemaWatch.d.ts +0 -13
  164. package/lib/SchemaWatch.d.ts.map +0 -1
  165. package/lib/SchemaWatch.js +0 -35
  166. package/lib/SyncReplication.d.ts +0 -34
  167. package/lib/SyncReplication.d.ts.map +0 -1
  168. package/lib/SyncReplication.js +0 -412
  169. package/lib/TableConfig/TableConfig.d.ts +0 -284
  170. package/lib/TableConfig/TableConfig.d.ts.map +0 -1
  171. package/lib/TableConfig/TableConfig.js +0 -437
  172. package/lib/TableConfig/getColumnDefinitionQuery.d.ts +0 -27
  173. package/lib/TableConfig/getColumnDefinitionQuery.d.ts.map +0 -1
  174. package/lib/TableConfig/getColumnDefinitionQuery.js +0 -87
  175. package/lib/TableConfig/getConstraintDefinitionQueries.d.ts +0 -34
  176. package/lib/TableConfig/getConstraintDefinitionQueries.d.ts.map +0 -1
  177. package/lib/TableConfig/getConstraintDefinitionQueries.js +0 -65
  178. package/lib/TableConfig/getFutureTableSchema.d.ts +0 -15
  179. package/lib/TableConfig/getFutureTableSchema.d.ts.map +0 -1
  180. package/lib/TableConfig/getFutureTableSchema.js +0 -43
  181. package/lib/TableConfig/getTableColumnQueries.d.ts +0 -16
  182. package/lib/TableConfig/getTableColumnQueries.d.ts.map +0 -1
  183. package/lib/TableConfig/getTableColumnQueries.js +0 -107
  184. package/lib/index.d.ts +0 -5
  185. package/lib/index.d.ts.map +0 -1
  186. package/lib/index.js +0 -7
  187. package/lib/shortestPath.d.ts +0 -10
  188. package/lib/shortestPath.d.ts.map +0 -1
  189. package/lib/shortestPath.js +0 -111
  190. package/lib/utils.d.ts +0 -3
  191. package/lib/utils.d.ts.map +0 -1
  192. package/lib/utils.js +0 -12
  193. package/tests/client/index.d.ts +0 -2
  194. package/tests/client/index.d.ts.map +0 -1
  195. package/tests/client/index.js +0 -80
  196. package/tests/client/index.js.map +0 -1
  197. package/tests/client_only_queries.d.ts +0 -4
  198. package/tests/client_only_queries.d.ts.map +0 -1
  199. package/tests/client_only_queries.js +0 -282
  200. package/tests/config_test/DBoGenerated.d.ts +0 -388
  201. package/tests/config_test/index.js +0 -174
  202. package/tests/config_test/index.js.map +0 -1
  203. package/tests/isomorphic_queries.d.ts +0 -9
  204. package/tests/isomorphic_queries.d.ts.map +0 -1
  205. package/tests/isomorphic_queries.js +0 -773
  206. package/tests/manual_test/DBoGenerated.d.ts +0 -398
  207. package/tests/manual_test/index.d.ts +0 -2
  208. package/tests/manual_test/index.d.ts.map +0 -1
  209. package/tests/manual_test/index.js +0 -65
  210. package/tests/server/dboTypeCheck.d.ts +0 -2
  211. package/tests/server/dboTypeCheck.d.ts.map +0 -1
  212. package/tests/server/dboTypeCheck.js +0 -27
  213. package/tests/server/index.d.ts +0 -2
  214. package/tests/server/index.d.ts.map +0 -1
  215. package/tests/server/index.js +0 -507
  216. package/tests/server/publishTypeCheck.d.ts +0 -2
  217. package/tests/server/publishTypeCheck.d.ts.map +0 -1
  218. package/tests/server/publishTypeCheck.js +0 -130
  219. package/tests/server_only_queries.d.ts +0 -2
  220. package/tests/server_only_queries.d.ts.map +0 -1
  221. package/tests/server_only_queries.js +0 -19
@@ -1,984 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.COMPUTED_FIELDS = exports.FUNCTIONS = exports.parseFunction = void 0;
4
- const prostgles_types_1 = require("prostgles-types");
5
- const DboBuilder_1 = require("../../DboBuilder");
6
- const ViewHandler_1 = require("../ViewHandler");
7
- const QueryBuilder_1 = require("./QueryBuilder");
8
- const parseFunction = (funcData) => {
9
- const { func, args, functions, allowedFields } = funcData;
10
- /* Function is computed column. No checks needed */
11
- if (typeof func !== "string") {
12
- const computedCol = exports.COMPUTED_FIELDS.find(c => c.name === func.name);
13
- if (!computedCol)
14
- throw `Unexpected function: computed column spec not found for ${JSON.stringify(func.name)}`;
15
- return func;
16
- }
17
- const funcName = func;
18
- const makeErr = (msg) => {
19
- return `Issue with function ${JSON.stringify({ [funcName]: args })}: \n${msg}`;
20
- };
21
- /* Find function */
22
- const funcDef = functions.find(f => f.name === funcName);
23
- if (!funcDef) {
24
- const sf = functions.filter(f => f.name.toLowerCase().slice(1).startsWith(funcName.toLowerCase())).sort((a, b) => (a.name.length - b.name.length));
25
- const hint = (sf.length ? `. \n Maybe you meant: \n | ${sf.map(s => s.name + " " + (s.description || "")).join(" \n | ")} ?` : "");
26
- throw "\n Function " + funcName + " does not exist or is not allowed " + hint;
27
- }
28
- /* Validate fields */
29
- const fields = funcDef.getFields(args);
30
- if (fields !== "*") {
31
- fields.forEach(fieldKey => {
32
- if (typeof fieldKey !== "string" || !allowedFields.includes(fieldKey)) {
33
- throw makeErr(`getFields() => field name ${JSON.stringify(fieldKey)} is invalid or disallowed`);
34
- }
35
- });
36
- if ((funcDef.minCols ?? 0) > fields.length) {
37
- throw makeErr(`Less columns provided than necessary (minCols=${funcDef.minCols})`);
38
- }
39
- }
40
- if (funcDef.numArgs && funcDef.minCols !== 0 && fields !== "*" && Array.isArray(fields) && !fields.length) {
41
- throw `\n Function "${funcDef.name}" expects at least a field name but has not been provided with one`;
42
- }
43
- return funcDef;
44
- };
45
- exports.parseFunction = parseFunction;
46
- const MAX_COL_NUM = 1600;
47
- const asValue = (v, castAs = "") => DboBuilder_1.pgp.as.format("$1" + castAs, [v]);
48
- const parseUnix = (colName, tableAlias, allColumns) => {
49
- const col = allColumns.find(c => c.name === colName);
50
- if (!col)
51
- throw `Unexpected: column ${colName} not found`;
52
- const escapedName = (0, QueryBuilder_1.asNameAlias)(colName, tableAlias);
53
- if (col.udt_name === "int8") {
54
- return `to_timestamp(${escapedName}/1000.0)`;
55
- }
56
- return escapedName;
57
- };
58
- const JSON_Funcs = [
59
- {
60
- name: "$jsonb_set",
61
- description: "[columnName: string, path: (string | number)[], new_value?: any, create_missing?: boolean ] Returns target value (columnName) with the section designated by path replaced by new_value, or with new_value added if create_missing is true (default is true) and the item designated by path does not exist",
62
- singleColArg: false,
63
- numArgs: 4,
64
- type: "function",
65
- getFields: ([column]) => column,
66
- getQuery: ({ args: [colName, path = [], new_value, create_missing = true], tableAlias, allowedFields }) => {
67
- if (!allowedFields.includes(colName)) {
68
- throw `Unexpected: column ${colName} not found`;
69
- }
70
- if (!path || !Array.isArray(path) || !path.every(v => ["number", "string"].includes(typeof v))) {
71
- throw "Expecting: [columnName: string, path: (string | number)[], new_value?: any, create_missing?: boolean ]";
72
- }
73
- const escapedName = (0, QueryBuilder_1.asNameAlias)(colName, tableAlias);
74
- return `jsonb_set(${escapedName}, ${asValue(path)}, ${asValue(new_value)}, ${create_missing})`;
75
- }
76
- },
77
- {
78
- name: "$jsonb_path_query",
79
- description: "[columnName: string, jsonPath: string, vars?: object, silent?: boolean]\n Returns all JSON items returned by the JSON path for the specified JSON value. The optional vars and silent arguments act the same as for jsonb_path_exists.",
80
- singleColArg: false,
81
- numArgs: 4,
82
- type: "function",
83
- getFields: ([column]) => column,
84
- getQuery: ({ args: [colName, jsonPath, ...otherArgs], tableAlias, allowedFields }) => {
85
- if (!allowedFields.includes(colName)) {
86
- throw `Unexpected: column ${colName} not found`;
87
- }
88
- if (!jsonPath || typeof jsonPath !== "string") {
89
- throw "Expecting: [columnName: string, jsonPath: string, vars?: object, silent?: boolean]";
90
- }
91
- const escapedName = (0, QueryBuilder_1.asNameAlias)(colName, tableAlias);
92
- return `jsonb_path_query(${escapedName}, ${[jsonPath, ...otherArgs].map(v => asValue(v)).join(", ")})`;
93
- }
94
- },
95
- ...[
96
- ["jsonb_array_length", "Returns the number of elements in the outermost JSON array"],
97
- ["jsonb_each", "Expands the outermost JSON object into a set of key/value pairs"],
98
- ["jsonb_each_text", "Expands the outermost JSON object into a set of key/value pairs. The returned values will be of type text"],
99
- ["jsonb_object_keys", "Returns set of keys in the outermost JSON object"],
100
- ["jsonb_strip_nulls", "Returns from_json with all object fields that have null values omitted. Other null values are untouched"],
101
- ["jsonb_pretty", "Returns from_json as indented JSON text "],
102
- ["jsonb_to_record", "Builds an arbitrary record from a JSON object"],
103
- ["jsonb_array_elements", "Expands a JSON array to a set of JSON values"],
104
- ["jsonb_array_elements_text", "Expands a JSON array to a set of text values "],
105
- ["jsonb_typeof", "Returns the type of the outermost JSON value as a text string. Possible types are object, array, string, number, boolean, and null "],
106
- ].map(([name, description]) => ({
107
- name: "$" + name,
108
- description,
109
- singleColArg: true,
110
- numArgs: 1,
111
- type: "function",
112
- getFields: ([col]) => col,
113
- getQuery: ({ args: [colName], tableAlias }) => {
114
- const escapedName = (0, QueryBuilder_1.asNameAlias)(colName, tableAlias);
115
- return `${name}(${escapedName})`;
116
- }
117
- }))
118
- ];
119
- const FTS_Funcs =
120
- /* Full text search
121
- https://www.postgresql.org/docs/current/textsearch-dictionaries.html#TEXTSEARCH-SIMPLE-DICTIONARY
122
- */
123
- [
124
- "simple",
125
- // "synonym", // replace word with a synonym
126
- "english",
127
- // "english_stem",
128
- // "english_hunspell",
129
- ""
130
- ].map(type => ({
131
- name: "$ts_headline" + (type ? ("_" + type) : ""),
132
- description: ` :[column_name <string>, search_term: <string | { to_tsquery: string } > ] -> sha512 hash of the of column content`,
133
- type: "function",
134
- singleColArg: true,
135
- numArgs: 2,
136
- getFields: ([column]) => [column],
137
- getQuery: ({ args }) => {
138
- const col = (0, prostgles_types_1.asName)(args[0]);
139
- let qVal = args[1], qType = "to_tsquery";
140
- const _type = type ? (asValue(type) + ",") : "";
141
- const searchTypes = prostgles_types_1.TextFilter_FullTextSearchFilterKeys;
142
- /* { to_tsquery: 'search term' } */
143
- if ((0, DboBuilder_1.isPlainObject)(qVal)) {
144
- const keys = Object.keys(qVal);
145
- if (!keys.length)
146
- throw "Bad arg";
147
- if (keys.length !== 1 || !searchTypes.includes(keys[0]))
148
- throw "Expecting a an object with a single key named one of: " + searchTypes.join(", ");
149
- qType = keys[0];
150
- qVal = asValue(qVal[qType]);
151
- /* 'search term' */
152
- }
153
- else if (typeof qVal === "string") {
154
- qVal = DboBuilder_1.pgp.as.format(qType + "($1)", [qVal]);
155
- }
156
- else
157
- throw "Bad second arg. Exepcting search string or { to_tsquery: 'search string' }";
158
- const res = `ts_headline(${_type} ${col}::text, ${qVal}, 'ShortWord=1 ' )`;
159
- // console.log(res)
160
- return res;
161
- }
162
- }));
163
- let PostGIS_Funcs = [
164
- {
165
- fname: "ST_DWithin",
166
- description: `:[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean; distance: number; }]
167
- -> Returns true if the geometries are within a given distance
168
- For geometry: The distance is specified in units defined by the spatial reference system of the geometries. For this function to make sense, the source geometries must be in the same coordinate system (have the same SRID).
169
- For geography: units are in meters and distance measurement defaults to use_spheroid=true. For faster evaluation use use_spheroid=false to measure on the sphere.
170
- `
171
- },
172
- {
173
- fname: "<->",
174
- description: `:[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }]
175
- -> The <-> operator returns the 2D distance between two geometries. Used in the "ORDER BY" clause provides index-assisted nearest-neighbor result sets. For PostgreSQL below 9.5 only gives centroid distance of bounding boxes and for PostgreSQL 9.5+, does true KNN distance search giving true distance between geometries, and distance sphere for geographies.`
176
- },
177
- {
178
- fname: "ST_Distance",
179
- description: ` :[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }]
180
- -> For geometry types returns the minimum 2D Cartesian (planar) distance between two geometries, in projected units (spatial ref units).
181
- -> For geography types defaults to return the minimum geodesic distance between two geographies in meters, compute on the spheroid determined by the SRID. If use_spheroid is false, a faster spherical calculation is used.
182
- `,
183
- }, {
184
- fname: "ST_DistanceSpheroid",
185
- description: ` :[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; spheroid?: string; }] -> Returns minimum distance in meters between two lon/lat geometries given a particular spheroid. See the explanation of spheroids given for ST_LengthSpheroid.
186
-
187
- `,
188
- }, {
189
- fname: "ST_DistanceSphere",
190
- description: ` :[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number }] -> Returns linear distance in meters between two lon/lat points. Uses a spherical earth and radius of 6370986 meters. Faster than ST_DistanceSpheroid, but less accurate. Only implemented for points.`,
191
- }
192
- ].map(({ fname, description }) => ({
193
- name: "$" + fname,
194
- description,
195
- type: "function",
196
- singleColArg: true,
197
- numArgs: 1,
198
- canBeUsedForFilter: fname === "ST_DWithin",
199
- getFields: (args) => [args[0]],
200
- getQuery: ({ allColumns, args: [columnName, arg2], tableAlias }) => {
201
- const mErr = () => { throw `${fname}: Expecting a second argument like: { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }`; };
202
- if (!(0, prostgles_types_1.isObject)(arg2)) {
203
- mErr();
204
- }
205
- const col = allColumns.find(c => c.name === columnName);
206
- if (!col) {
207
- throw new Error("Col not found: " + columnName);
208
- }
209
- const { lat, lng, srid = 4326, geojson, text, use_spheroid, distance, spheroid = 'SPHEROID["WGS 84", 6378137, 298.257223563]', unit, debug } = arg2;
210
- let geomQ = "", extraParams = "";
211
- if (typeof text === "string") {
212
- geomQ = `ST_GeomFromText(${asValue(text)})`;
213
- }
214
- else if ([lat, lng].every(v => Number.isFinite(v))) {
215
- geomQ = `ST_Point(${asValue(lng)}, ${asValue(lat)})`;
216
- }
217
- else if ((0, DboBuilder_1.isPlainObject)(geojson)) {
218
- geomQ = `ST_GeomFromGeoJSON(${geojson})`;
219
- }
220
- else
221
- mErr();
222
- if (Number.isFinite(srid)) {
223
- geomQ = `ST_SetSRID(${geomQ}, ${asValue(srid)})`;
224
- }
225
- let colCast = "";
226
- const colIsGeog = col.udt_name === "geography";
227
- let geomQCast = colIsGeog ? "::geography" : "::geometry";
228
- /**
229
- * float ST_Distance(geometry g1, geometry g2);
230
- * float ST_Distance(geography geog1, geography geog2, boolean use_spheroid=true);
231
- */
232
- if (fname === "ST_Distance") {
233
- if (typeof use_spheroid === "boolean") {
234
- extraParams = ", " + asValue(use_spheroid);
235
- }
236
- colCast = (colIsGeog || use_spheroid) ? "::geography" : "::geometry";
237
- geomQCast = (colIsGeog || use_spheroid) ? "::geography" : "::geometry";
238
- /**
239
- * boolean ST_DWithin(geometry g1, geometry g2, double precision distance_of_srid);
240
- * boolean ST_DWithin(geography gg1, geography gg2, double precision distance_meters, boolean use_spheroid = true);
241
- */
242
- }
243
- else if (fname === "ST_DWithin") {
244
- colCast = colIsGeog ? "::geography" : "::geometry";
245
- geomQCast = colIsGeog ? "::geography" : "::geometry";
246
- if (typeof distance !== "number") {
247
- throw `ST_DWithin: distance param missing or not a number`;
248
- }
249
- const allowedUnits = ["m", "km"];
250
- if (unit && !allowedUnits.includes(unit)) {
251
- throw `ST_DWithin: unit can only be one of: ${allowedUnits}`;
252
- }
253
- extraParams = ", " + asValue(distance * (unit === "km" ? 1000 : 1));
254
- /**
255
- * float ST_DistanceSpheroid(geometry geomlonlatA, geometry geomlonlatB, spheroid measurement_spheroid);
256
- */
257
- }
258
- else if (fname === "ST_DistanceSpheroid") {
259
- colCast = "::geometry";
260
- geomQCast = "::geometry";
261
- if (typeof spheroid !== "string")
262
- throw `ST_DistanceSpheroid: spheroid param must be string`;
263
- extraParams = `, ${asValue(spheroid)}`;
264
- /**
265
- * float ST_DistanceSphere(geometry geomlonlatA, geometry geomlonlatB);
266
- */
267
- }
268
- else if (fname === "ST_DistanceSphere") {
269
- colCast = "::geometry";
270
- geomQCast = "::geometry";
271
- extraParams = "";
272
- /**
273
- * double precision <->( geometry A , geometry B );
274
- * double precision <->( geography A , geography B );
275
- */
276
- }
277
- else if (fname === "<->") {
278
- colCast = colIsGeog ? "::geography" : "::geometry";
279
- geomQCast = colIsGeog ? "::geography" : "::geometry";
280
- const q = DboBuilder_1.pgp.as.format(`${(0, QueryBuilder_1.asNameAlias)(columnName, tableAlias)}${colCast} <-> ${geomQ}${geomQCast}`);
281
- if (debug)
282
- throw q;
283
- return q;
284
- }
285
- const query = DboBuilder_1.pgp.as.format(`${fname}(${(0, QueryBuilder_1.asNameAlias)(columnName, tableAlias)}${colCast} , ${geomQ}${geomQCast} ${extraParams})`);
286
- if (debug) {
287
- throw query;
288
- }
289
- return query;
290
- }
291
- }));
292
- PostGIS_Funcs = PostGIS_Funcs.concat([
293
- "ST_AsText", "ST_AsEWKT", "ST_AsEWKB", "ST_AsBinary", "ST_AsMVT", "ST_AsMVTGeom",
294
- "ST_AsGeoJSON", "ST_Simplify",
295
- "ST_SnapToGrid", "ST_Centroid",
296
- "st_aslatlontext",
297
- ]
298
- .map(fname => {
299
- const res = {
300
- name: "$" + fname,
301
- description: ` :[column_name, precision?] -> json GeoJSON output of a geometry column`,
302
- type: "function",
303
- singleColArg: true,
304
- numArgs: 1,
305
- getFields: (args) => [args[0]],
306
- getQuery: ({ args: [colName, ...otherArgs], tableAlias }) => {
307
- let secondArg = "";
308
- if (otherArgs.length)
309
- secondArg = ", " + otherArgs.map(arg => asValue(arg)).join(", ");
310
- const escTabelName = (0, QueryBuilder_1.asNameAlias)(colName, tableAlias) + "::geometry";
311
- const result = DboBuilder_1.pgp.as.format(fname + "(" + escTabelName + secondArg + (fname === "ST_AsGeoJSON" ? ")::jsonb" : ")"));
312
- if (["ST_Centroid", "ST_SnapToGrid", "ST_Simplify"].includes(fname)) {
313
- const r = `ST_AsGeoJSON(${result})::jsonb`;
314
- return r;
315
- }
316
- return result;
317
- }
318
- };
319
- return res;
320
- }));
321
- PostGIS_Funcs = PostGIS_Funcs.concat(["ST_Extent", "ST_3DExtent", "ST_XMin_Agg", "ST_XMax_Agg", "ST_YMin_Agg", "ST_YMax_Agg", "ST_ZMin_Agg", "ST_ZMax_Agg"]
322
- .map(fname => {
323
- const res = {
324
- name: "$" + fname,
325
- description: ` :[column_name] -> ST_Extent returns a bounding box that encloses a set of geometries.
326
- The ST_Extent function is an "aggregate" function in the terminology of SQL.
327
- That means that it operates on lists of data, in the same way the SUM() and AVG() functions do.`,
328
- type: "aggregation",
329
- singleColArg: true,
330
- numArgs: 1,
331
- getFields: (args) => [args[0]],
332
- getQuery: ({ args, tableAlias }) => {
333
- const escTabelName = (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + "::geometry";
334
- if (fname.includes("Extent")) {
335
- return `${fname}(${escTabelName})`;
336
- }
337
- return `${fname.endsWith("_Agg") ? fname.slice(0, -4) : fname}(ST_Collect(${escTabelName}))`;
338
- }
339
- };
340
- return res;
341
- }));
342
- PostGIS_Funcs = PostGIS_Funcs.concat(["ST_Length", "ST_X", "ST_Y", "ST_Z"].map(fname => ({
343
- name: "$" + fname,
344
- type: "function",
345
- singleColArg: true,
346
- numArgs: 1,
347
- getFields: (args) => [args[0]],
348
- getQuery: ({ allColumns, args, tableAlias }) => {
349
- const colName = args[0];
350
- const escapedColName = (0, QueryBuilder_1.asNameAlias)(colName, tableAlias);
351
- const col = allColumns.find(c => c.name === colName);
352
- if (!col)
353
- throw new Error("Col not found: " + colName);
354
- return `${fname}(${escapedColName})`;
355
- }
356
- })));
357
- /**
358
- * Each function expects a column at the very least
359
- */
360
- exports.FUNCTIONS = [
361
- // Hashing
362
- {
363
- name: "$md5_multi",
364
- description: ` :[...column_names] -> md5 hash of the column content`,
365
- type: "function",
366
- singleColArg: false,
367
- numArgs: MAX_COL_NUM,
368
- getFields: (args) => args,
369
- getQuery: ({ args, tableAlias }) => {
370
- const q = DboBuilder_1.pgp.as.format("md5(" + args.map(fname => "COALESCE( " + (0, QueryBuilder_1.asNameAlias)(fname, tableAlias) + "::text, '' )").join(" || ") + ")");
371
- return q;
372
- }
373
- },
374
- {
375
- name: "$md5_multi_agg",
376
- description: ` :[...column_names] -> md5 hash of the string aggregation of column content`,
377
- type: "aggregation",
378
- singleColArg: false,
379
- numArgs: MAX_COL_NUM,
380
- getFields: (args) => args,
381
- getQuery: ({ args, tableAlias }) => {
382
- const q = DboBuilder_1.pgp.as.format("md5(string_agg(" + args.map(fname => "COALESCE( " + (0, QueryBuilder_1.asNameAlias)(fname, tableAlias) + "::text, '' )").join(" || ") + ", ','))");
383
- return q;
384
- }
385
- },
386
- {
387
- name: "$sha256_multi",
388
- description: ` :[...column_names] -> sha256 hash of the of column content`,
389
- type: "function",
390
- singleColArg: false,
391
- numArgs: MAX_COL_NUM,
392
- getFields: (args) => args,
393
- getQuery: ({ args, tableAlias }) => {
394
- const q = DboBuilder_1.pgp.as.format("encode(sha256((" + args.map(fname => "COALESCE( " + (0, QueryBuilder_1.asNameAlias)(fname, tableAlias) + ", '' )").join(" || ") + ")::text::bytea), 'hex')");
395
- return q;
396
- }
397
- },
398
- {
399
- name: "$sha256_multi_agg",
400
- description: ` :[...column_names] -> sha256 hash of the string aggregation of column content`,
401
- type: "aggregation",
402
- singleColArg: false,
403
- numArgs: MAX_COL_NUM,
404
- getFields: (args) => args,
405
- getQuery: ({ args, tableAlias }) => {
406
- const q = DboBuilder_1.pgp.as.format("encode(sha256(string_agg(" + args.map(fname => "COALESCE( " + (0, QueryBuilder_1.asNameAlias)(fname, tableAlias) + ", '' )").join(" || ") + ", ',')::text::bytea), 'hex')");
407
- return q;
408
- }
409
- },
410
- {
411
- name: "$sha512_multi",
412
- description: ` :[...column_names] -> sha512 hash of the of column content`,
413
- type: "function",
414
- singleColArg: false,
415
- numArgs: MAX_COL_NUM,
416
- getFields: (args) => args,
417
- getQuery: ({ args, tableAlias }) => {
418
- const q = DboBuilder_1.pgp.as.format("encode(sha512((" + args.map(fname => "COALESCE( " + (0, QueryBuilder_1.asNameAlias)(fname, tableAlias) + ", '' )").join(" || ") + ")::text::bytea), 'hex')");
419
- return q;
420
- }
421
- },
422
- {
423
- name: "$sha512_multi_agg",
424
- description: ` :[...column_names] -> sha512 hash of the string aggregation of column content`,
425
- type: "aggregation",
426
- singleColArg: false,
427
- numArgs: MAX_COL_NUM,
428
- getFields: (args) => args,
429
- getQuery: ({ args, tableAlias }) => {
430
- const q = DboBuilder_1.pgp.as.format("encode(sha512(string_agg(" + args.map(fname => "COALESCE( " + (0, QueryBuilder_1.asNameAlias)(fname, tableAlias) + ", '' )").join(" || ") + ", ',')::text::bytea), 'hex')");
431
- return q;
432
- }
433
- },
434
- ...FTS_Funcs,
435
- ...JSON_Funcs,
436
- ...PostGIS_Funcs,
437
- {
438
- name: "$left",
439
- description: ` :[column_name, number] -> substring`,
440
- type: "function",
441
- numArgs: 2,
442
- singleColArg: false,
443
- getFields: (args) => [args[0]],
444
- getQuery: ({ allowedFields, args, tableAlias }) => {
445
- return DboBuilder_1.pgp.as.format("LEFT(" + (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + ", $1)", [args[1]]);
446
- }
447
- },
448
- {
449
- name: "$unnest_words",
450
- description: ` :[column_name] -> Splits string at spaces`,
451
- type: "function",
452
- numArgs: 1,
453
- singleColArg: true,
454
- getFields: (args) => [args[0]],
455
- getQuery: ({ allowedFields, args, tableAlias }) => {
456
- return DboBuilder_1.pgp.as.format("unnest(string_to_array(" + (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + "::TEXT , ' '))"); //, [args[1]]
457
- }
458
- },
459
- {
460
- name: "$right",
461
- description: ` :[column_name, number] -> substring`,
462
- type: "function",
463
- numArgs: 2,
464
- singleColArg: false,
465
- getFields: (args) => [args[0]],
466
- getQuery: ({ allowedFields, args, tableAlias }) => {
467
- return DboBuilder_1.pgp.as.format("RIGHT(" + (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + ", $1)", [args[1]]);
468
- }
469
- },
470
- {
471
- name: "$to_char",
472
- type: "function",
473
- description: ` :[column_name, format<string>] -> format dates and strings. Eg: [current_timestamp, 'HH12:MI:SS']`,
474
- singleColArg: false,
475
- numArgs: 2,
476
- getFields: (args) => [args[0]],
477
- getQuery: ({ allowedFields, args, tableAlias }) => {
478
- if (args.length === 3) {
479
- return DboBuilder_1.pgp.as.format("to_char(" + (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + ", $2, $3)", [args[0], args[1], args[2]]);
480
- }
481
- return DboBuilder_1.pgp.as.format("to_char(" + (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + ", $2)", [args[0], args[1]]);
482
- }
483
- },
484
- /**
485
- * Date trunc utils
486
- */
487
- ...[
488
- "microsecond",
489
- "millisecond",
490
- "second",
491
- "minute",
492
- "hour",
493
- "day",
494
- "week",
495
- "month",
496
- "quarter",
497
- "year",
498
- "decade",
499
- "century",
500
- "millennium"
501
- ].map(k => ({ val: 0, unit: k }))
502
- .concat([
503
- { val: 6, unit: 'month' },
504
- { val: 4, unit: 'month' },
505
- { val: 2, unit: 'month' },
506
- { val: 8, unit: 'hour' },
507
- { val: 4, unit: 'hour' },
508
- { val: 2, unit: 'hour' },
509
- { val: 30, unit: 'minute' },
510
- { val: 15, unit: 'minute' },
511
- { val: 6, unit: 'minute' },
512
- { val: 5, unit: 'minute' },
513
- { val: 4, unit: 'minute' },
514
- { val: 3, unit: 'minute' },
515
- { val: 2, unit: 'minute' },
516
- { val: 30, unit: 'second' },
517
- { val: 15, unit: 'second' },
518
- { val: 10, unit: 'second' },
519
- { val: 8, unit: 'second' },
520
- { val: 6, unit: 'second' },
521
- { val: 5, unit: 'second' },
522
- { val: 4, unit: 'second' },
523
- { val: 3, unit: 'second' },
524
- { val: 2, unit: 'second' },
525
- { val: 500, unit: 'millisecond' },
526
- { val: 250, unit: 'millisecond' },
527
- { val: 100, unit: 'millisecond' },
528
- { val: 50, unit: 'millisecond' },
529
- { val: 25, unit: 'millisecond' },
530
- { val: 10, unit: 'millisecond' },
531
- { val: 5, unit: 'millisecond' },
532
- { val: 2, unit: 'millisecond' },
533
- ]).map(({ val, unit }) => ({
534
- name: "$date_trunc_" + (val || "") + unit,
535
- type: "function",
536
- description: ` :[column_name] -> round down timestamp to closest ${val || ""} ${unit} `,
537
- singleColArg: true,
538
- numArgs: 1,
539
- getFields: (args) => [args[0]],
540
- getQuery: ({ allColumns, args, tableAlias }) => {
541
- const col = parseUnix(args[0], tableAlias, allColumns);
542
- if (!val)
543
- return `date_trunc(${asValue(unit)}, ${col})`;
544
- const PreviousUnit = {
545
- year: "decade",
546
- month: "year",
547
- hour: "day",
548
- minute: "hour",
549
- second: "minute",
550
- millisecond: "second",
551
- microsecond: "millisecond",
552
- };
553
- const prevUnit = PreviousUnit[unit];
554
- if (!prevUnit) {
555
- throw "Not supported. prevUnit not found";
556
- }
557
- let extractedUnit = `date_part(${asValue(unit, "::text")}, ${col})::int`;
558
- if (unit === "microsecond" || unit === "millisecond") {
559
- extractedUnit = `(${extractedUnit} - 1000 * floor(${extractedUnit}/1000)::int)`;
560
- }
561
- const res = `(date_trunc(${asValue(prevUnit)}, ${col}) + floor(${extractedUnit} / ${val}) * interval ${asValue(val + " " + unit)})`;
562
- // console.log(res);
563
- return res;
564
- }
565
- })),
566
- /* Date funcs date_part */
567
- ...["date_trunc", "date_part"].map(funcName => ({
568
- name: "$" + funcName,
569
- type: "function",
570
- numArgs: 2,
571
- description: ` :[unit<string>, column_name] -> ` + (funcName === "date_trunc" ? ` round down timestamp to closest unit value. ` : ` extract date unit as float8. `) + ` E.g. ['hour', col] `,
572
- singleColArg: false,
573
- getFields: (args) => [args[1]],
574
- getQuery: ({ allColumns, args, tableAlias }) => {
575
- return `${funcName}(${asValue(args[0])}, ${parseUnix(args[1], tableAlias, allColumns)})`;
576
- }
577
- })),
578
- /* Handy date funcs */
579
- ...[
580
- ["date", "YYYY-MM-DD"],
581
- ["datetime", "YYYY-MM-DD HH24:MI"],
582
- ["datetime_", "YYYY_MM_DD__HH24_MI"],
583
- ["timedate", "HH24:MI YYYY-MM-DD"],
584
- ["time", "HH24:MI"],
585
- ["time12", "HH:MI"],
586
- ["timeAM", "HH:MI AM"],
587
- ["dy", "dy"],
588
- ["Dy", "Dy"],
589
- ["day", "day"],
590
- ["Day", "Day"],
591
- ["DayNo", "DD"],
592
- ["DD", "DD"],
593
- ["dowUS", "D"],
594
- ["D", "D"],
595
- ["dow", "ID"],
596
- ["ID", "ID"],
597
- ["MonthNo", "MM"],
598
- ["MM", "MM"],
599
- ["mon", "mon"],
600
- ["Mon", "Mon"],
601
- ["month", "month"],
602
- ["Month", "Month"],
603
- ["year", "yyyy"],
604
- ["yyyy", "yyyy"],
605
- ["yy", "yy"],
606
- ["yr", "yy"],
607
- ].map(([funcName, txt]) => ({
608
- name: "$" + funcName,
609
- type: "function",
610
- description: ` :[column_name] -> get timestamp formated as ` + txt,
611
- singleColArg: true,
612
- numArgs: 1,
613
- getFields: (args) => [args[0]],
614
- getQuery: ({ allColumns, args, tableAlias }) => {
615
- return DboBuilder_1.pgp.as.format("trim(to_char(" + parseUnix(args[0], tableAlias, allColumns) + ", $2))", [args[0], txt]);
616
- }
617
- })),
618
- /* Basic 1 arg col funcs */
619
- ...[
620
- ...["TEXT"].flatMap(cast => [
621
- "upper", "lower", "length", "reverse", "trim", "initcap"
622
- ].map(funcName => ({ cast, funcName }))),
623
- ...[""].flatMap(cast => [
624
- "round", "ceil", "floor", "sign", "md5"
625
- ].map(funcName => ({ cast, funcName }))),
626
- ].map(({ funcName, cast }) => ({
627
- name: "$" + funcName,
628
- type: "function",
629
- numArgs: 1,
630
- singleColArg: true,
631
- getFields: (args) => [args[0]],
632
- getQuery: ({ args, tableAlias }) => {
633
- return `${funcName}(${(0, QueryBuilder_1.asNameAlias)(args[0], tableAlias)}${cast ? `::${cast}` : ""})`;
634
- }
635
- })),
636
- /**
637
- * Interval funcs
638
- * (col1, col2?, trunc )
639
- * */
640
- ...["age", "ageNow", "difference"].map(funcName => ({
641
- name: "$" + funcName,
642
- type: "function",
643
- numArgs: 1,
644
- singleColArg: true,
645
- getFields: (args) => args.slice(0, 2).filter(a => typeof a === "string"),
646
- getQuery: ({ allowedFields, args, tableAlias, allColumns }) => {
647
- const validColCount = args.slice(0, 2).filter(a => typeof a === "string").length;
648
- const trunc = args[2];
649
- const allowedTruncs = ["second", "minute", "hour", "day", "month", "year"];
650
- if (trunc && !allowedTruncs.includes(trunc))
651
- throw new Error("Incorrect trunc provided. Allowed values: " + allowedTruncs);
652
- if (funcName === "difference" && validColCount !== 2)
653
- throw new Error("Must have two column names");
654
- if (![1, 2].includes(validColCount))
655
- throw new Error("Must have one or two column names");
656
- const [leftField, rightField] = args;
657
- const leftQ = parseUnix(leftField, tableAlias, allColumns);
658
- let rightQ = rightField ? parseUnix(rightField, tableAlias, allColumns) : "";
659
- let query = "";
660
- if (funcName === "ageNow" && validColCount === 1) {
661
- query = `age(now(), ${leftQ})`;
662
- }
663
- else if (funcName === "age" || funcName === "ageNow") {
664
- if (rightQ)
665
- rightQ = ", " + rightQ;
666
- query = `age(${leftQ} ${rightQ})`;
667
- }
668
- else {
669
- query = `${leftQ} - ${rightQ}`;
670
- }
671
- return trunc ? `date_trunc(${asValue(trunc)}, ${query})` : query;
672
- }
673
- })),
674
- /* pgcrypto funcs */
675
- ...["crypt"].map(funcName => ({
676
- name: "$" + funcName,
677
- type: "function",
678
- numArgs: 1,
679
- singleColArg: false,
680
- getFields: (args) => [args[1]],
681
- getQuery: ({ allowedFields, args, tableAlias }) => {
682
- const value = asValue(args[0]) + "", seedColumnName = (0, QueryBuilder_1.asNameAlias)(args[1], tableAlias);
683
- return `crypt(${value}, ${seedColumnName}::text)`;
684
- }
685
- })),
686
- /* Text col and value funcs */
687
- ...["position", "position_lower"].map(funcName => ({
688
- name: "$" + funcName,
689
- type: "function",
690
- numArgs: 1,
691
- singleColArg: false,
692
- getFields: (args) => [args[1]],
693
- getQuery: ({ allowedFields, args, tableAlias }) => {
694
- let a1 = asValue(args[0]), a2 = (0, QueryBuilder_1.asNameAlias)(args[1], tableAlias);
695
- if (funcName === "position_lower") {
696
- a1 = `LOWER(${a1}::text)`;
697
- a2 = `LOWER(${a2}::text)`;
698
- }
699
- return `position( ${a1} IN ${a2} )`;
700
- }
701
- })),
702
- ...["template_string"].map(funcName => ({
703
- name: "$" + funcName,
704
- type: "function",
705
- numArgs: 1,
706
- minCols: 0,
707
- singleColArg: false,
708
- getFields: (args) => [],
709
- getQuery: ({ allowedFields, args, tableAlias }) => {
710
- if (typeof args[0] !== "string")
711
- throw "First argument must be a string. E.g.: '{col1} ..text {col2} ...' ";
712
- const rawValue = args[0];
713
- let finalValue = rawValue;
714
- const usedColumns = allowedFields.filter(fName => rawValue.includes(`{${fName}}`));
715
- usedColumns.forEach((colName, idx) => {
716
- finalValue = finalValue.split(`{${colName}}`).join(`%${idx + 1}$s`);
717
- });
718
- finalValue = asValue(finalValue);
719
- if (usedColumns.length) {
720
- return `format(${finalValue}, ${usedColumns.map(c => `${(0, QueryBuilder_1.asNameAlias)(c, tableAlias)}::TEXT`).join(", ")})`;
721
- }
722
- return `format(${finalValue})`;
723
- }
724
- })),
725
- /** Custom highlight -> myterm => ['some text and', ['myterm'], ' and some other text']
726
- * (fields: "*" | string[], term: string, { edgeTruncate: number = -1; noFields: boolean = false }) => string | (string | [string])[]
727
- * edgeTruncate = maximum extra characters left and right of matches
728
- * noFields = exclude field names in search
729
- * */
730
- {
731
- name: "$term_highlight",
732
- description: ` :[column_names<string[] | "*">, search_term<string>, opts?<{ returnIndex?: number; edgeTruncate?: number; noFields?: boolean }>] -> get case-insensitive text match highlight`,
733
- type: "function",
734
- numArgs: 1,
735
- singleColArg: true,
736
- canBeUsedForFilter: true,
737
- getFields: (args) => args[0],
738
- getQuery: ({ allowedFields, args, tableAlias, allColumns }) => {
739
- const cols = ViewHandler_1.ViewHandler._parseFieldFilter(args[0], false, allowedFields);
740
- let term = args[1];
741
- const rawTerm = args[1];
742
- const { edgeTruncate, noFields = false, returnType, matchCase = false } = args[2] || {};
743
- if (!(0, prostgles_types_1.isEmpty)(args[2])) {
744
- const keys = Object.keys(args[2]);
745
- const validKeys = ["edgeTruncate", "noFields", "returnType", "matchCase"];
746
- const bad_keys = keys.filter(k => !validKeys.includes(k));
747
- if (bad_keys.length)
748
- throw "Invalid options provided for $term_highlight. Expecting one of: " + validKeys.join(", ");
749
- }
750
- if (!cols.length)
751
- throw "Cols are empty/invalid";
752
- if (typeof term !== "string")
753
- throw "Non string term provided: " + term;
754
- if (edgeTruncate !== undefined && (!Number.isInteger(edgeTruncate) || edgeTruncate < -1))
755
- throw "Invalid edgeTruncate. expecting a positive integer";
756
- if (typeof noFields !== "boolean")
757
- throw "Invalid noFields. expecting boolean";
758
- const RETURN_TYPES = ["index", "boolean", "object"];
759
- if (returnType && !RETURN_TYPES.includes(returnType)) {
760
- throw `returnType can only be one of: ${RETURN_TYPES}`;
761
- }
762
- const makeTextMatcherArray = (rawText, _term) => {
763
- let matchText = rawText, term = _term;
764
- if (!matchCase) {
765
- matchText = `LOWER(${rawText})`;
766
- term = `LOWER(${term})`;
767
- }
768
- let leftStr = `substr(${rawText}, 1, position(${term} IN ${matchText}) - 1 )`, rightStr = `substr(${rawText}, position(${term} IN ${matchText}) + length(${term}) )`;
769
- if (edgeTruncate) {
770
- leftStr = `RIGHT(${leftStr}, ${asValue(edgeTruncate)})`;
771
- rightStr = `LEFT(${rightStr}, ${asValue(edgeTruncate)})`;
772
- }
773
- return `
774
- CASE WHEN position(${term} IN ${matchText}) > 0 AND ${term} <> ''
775
- THEN array_to_json(ARRAY[
776
- to_json( ${leftStr}::TEXT ),
777
- array_to_json(
778
- ARRAY[substr(${rawText}, position(${term} IN ${matchText}), length(${term}) )::TEXT ]
779
- ),
780
- to_json(${rightStr}::TEXT )
781
- ])
782
- ELSE
783
- array_to_json(ARRAY[(${rawText})::TEXT])
784
- END
785
- `;
786
- };
787
- const colRaw = "( " + cols.map(c => `${noFields ? "" : (asValue(c + ": ") + " || ")} COALESCE(${(0, QueryBuilder_1.asNameAlias)(c, tableAlias)}::TEXT, '')`).join(" || ', ' || ") + " )";
788
- let col = colRaw;
789
- term = asValue(term);
790
- if (!matchCase) {
791
- col = "LOWER" + col;
792
- term = `LOWER(${term})`;
793
- }
794
- let leftStr = `substr(${colRaw}, 1, position(${term} IN ${col}) - 1 )`, rightStr = `substr(${colRaw}, position(${term} IN ${col}) + length(${term}) )`;
795
- if (edgeTruncate) {
796
- leftStr = `RIGHT(${leftStr}, ${asValue(edgeTruncate)})`;
797
- rightStr = `LEFT(${rightStr}, ${asValue(edgeTruncate)})`;
798
- }
799
- // console.log(col);
800
- let res = "";
801
- if (returnType === "index") {
802
- res = `CASE WHEN position(${term} IN ${col}) > 0 THEN position(${term} IN ${col}) - 1 ELSE -1 END`;
803
- // } else if(returnType === "boolean"){
804
- // res = `CASE WHEN position(${term} IN ${col}) > 0 THEN TRUE ELSE FALSE END`;
805
- }
806
- else if (returnType === "object" || returnType === "boolean") {
807
- const hasChars = Boolean(rawTerm && /[a-z]/i.test(rawTerm));
808
- const validCols = cols.map(c => {
809
- const colInfo = allColumns.find(ac => ac.name === c);
810
- return {
811
- key: c,
812
- colInfo
813
- };
814
- })
815
- .filter(c => c.colInfo && c.colInfo.udt_name !== "bytea");
816
- const _cols = validCols.filter(c =>
817
- /** Exclude numeric columns when the search tern contains a character */
818
- !hasChars ||
819
- (0, DboBuilder_1.postgresToTsType)(c.colInfo.udt_name) !== "number");
820
- /** This will break GROUP BY (non-integer constant in GROUP BY) */
821
- if (!_cols.length) {
822
- if (validCols.length && hasChars)
823
- throw `You're searching the impossible: characters in numeric fields. Use this to prevent making such a request in future: /[a-z]/i.test(your_term) `;
824
- return (returnType === "boolean") ? "FALSE" : "NULL";
825
- }
826
- res = `CASE
827
- ${_cols
828
- .map(c => {
829
- const colNameEscaped = (0, QueryBuilder_1.asNameAlias)(c.key, tableAlias);
830
- let colSelect = `${colNameEscaped}::TEXT`;
831
- const isTstamp = c.colInfo?.udt_name.startsWith("timestamp");
832
- if (isTstamp || c.colInfo?.udt_name === "date") {
833
- colSelect = `( CASE WHEN ${colNameEscaped} IS NULL THEN ''
834
- ELSE concat_ws(' ',
835
- trim(to_char(${colNameEscaped}, 'YYYY-MM-DD HH24:MI:SS')),
836
- trim(to_char(${colNameEscaped}, 'Day Month')),
837
- 'Q' || trim(to_char(${colNameEscaped}, 'Q')),
838
- 'WK' || trim(to_char(${colNameEscaped}, 'WW'))
839
- ) END)`;
840
- }
841
- const colTxt = `COALESCE(${colSelect}, '')`; // position(${term} IN ${colTxt}) > 0
842
- if (returnType === "boolean") {
843
- return `
844
- WHEN ${colTxt} ${matchCase ? "LIKE" : "ILIKE"} ${asValue('%' + rawTerm + '%')}
845
- THEN TRUE
846
- `;
847
- }
848
- return `
849
- WHEN ${colTxt} ${matchCase ? "LIKE" : "ILIKE"} ${asValue('%' + rawTerm + '%')}
850
- THEN json_build_object(
851
- ${asValue(c.key)},
852
- ${makeTextMatcherArray(colTxt, term)}
853
- )::jsonb
854
- `;
855
- }).join(" ")}
856
- ELSE ${(returnType === "boolean") ? "FALSE" : "NULL"}
857
-
858
- END`;
859
- // console.log(res)
860
- }
861
- else {
862
- /* If no match or empty search THEN return full row as string within first array element */
863
- res = `CASE WHEN position(${term} IN ${col}) > 0 AND ${term} <> '' THEN array_to_json(ARRAY[
864
- to_json( ${leftStr}::TEXT ),
865
- array_to_json(
866
- ARRAY[substr(${colRaw}, position(${term} IN ${col}), length(${term}) )::TEXT ]
867
- ),
868
- to_json(${rightStr}::TEXT )
869
- ]) ELSE array_to_json(ARRAY[(${colRaw})::TEXT]) END`;
870
- }
871
- return res;
872
- }
873
- },
874
- /* Aggs */
875
- ...["max", "min", "count", "avg", "json_agg", "jsonb_agg", "string_agg", "array_agg", "sum"].map(aggName => ({
876
- name: "$" + aggName,
877
- type: "aggregation",
878
- numArgs: 1,
879
- singleColArg: true,
880
- getFields: (args) => [args[0]],
881
- getQuery: ({ allowedFields, args, tableAlias }) => {
882
- let extraArgs = "";
883
- if (args.length > 1) {
884
- extraArgs = DboBuilder_1.pgp.as.format(", $1:csv", args.slice(1));
885
- }
886
- return aggName + "(" + (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias) + `${extraArgs})`;
887
- }
888
- })),
889
- /* More aggs */
890
- {
891
- name: "$countAll",
892
- type: "aggregation",
893
- description: `agg :[] COUNT of all rows `,
894
- singleColArg: true,
895
- numArgs: 0,
896
- getFields: (args) => [],
897
- getQuery: ({ allowedFields, args, tableAlias }) => {
898
- return "COUNT(*)";
899
- }
900
- },
901
- {
902
- name: "$diff_perc",
903
- type: "aggregation",
904
- numArgs: 1,
905
- singleColArg: true,
906
- getFields: (args) => [args[0]],
907
- getQuery: ({ allowedFields, args, tableAlias }) => {
908
- const col = (0, QueryBuilder_1.asNameAlias)(args[0], tableAlias);
909
- return `round( ( ( MAX(${col}) - MIN(${col}) )::float/MIN(${col}) ) * 100, 2)`;
910
- }
911
- }
912
- ];
913
- /* The difference between a function and computed field is that the computed field does not require any arguments */
914
- exports.COMPUTED_FIELDS = [
915
- /**
916
- * Used instead of row id. Must be used as a last resort. Use all non pseudo or domain data type columns first!
917
- */
918
- {
919
- name: "$rowhash",
920
- type: "computed",
921
- // description: ` order hash of row content `,
922
- getQuery: ({ allowedFields, tableAlias, ctidField }) => {
923
- return "md5(" +
924
- allowedFields
925
- /* CTID not available in AFTER trigger */
926
- // .concat(ctidField? [ctidField] : [])
927
- .sort()
928
- .map(f => (0, QueryBuilder_1.asNameAlias)(f, tableAlias))
929
- .map(f => `md5(coalesce(${f}::text, 'dd'))`)
930
- .join(" || ") +
931
- `)`;
932
- }
933
- }
934
- // ,{
935
- // name: "ctid",
936
- // type: "computed",
937
- // // description: ` order hash of row content `,
938
- // getQuery: ({ allowedFields, tableAlias, ctidField }) => {
939
- // return asNameAlias("ctid", tableAlias);
940
- // }
941
- // }
942
- ];
943
- /*
944
-
945
-
946
- get key val pairs:
947
- obj.key.path value
948
-
949
-
950
- WITH RECURSIVE extract_all AS (
951
- select
952
- key as path,
953
- jsonb_typeof(value) as type,
954
- CASE WHEN trim(jsonb_typeof(value)) = 'array' THEN jsonb_typeof(value->0) END as elem_type,
955
- value
956
- from (SELECT * FROM mytable LIMIT 1) zzzzz
957
- cross join lateral jsonb_each(jdata)
958
- union all
959
- select
960
- path || '.' || coalesce(obj_key, (arr_key- 1)::text),
961
- jsonb_typeof(coalesce(obj_value, arr_value)) as type,
962
- CASE WHEN jsonb_typeof(coalesce(obj_value, arr_value)) = 'array' THEN jsonb_typeof(coalesce(obj_value, arr_value)->0) END as elem_type,
963
- coalesce(obj_value, arr_value)
964
- from extract_all
965
- left join lateral
966
- jsonb_each(case jsonb_typeof(value) when 'object' then value end)
967
- as o(obj_key, obj_value)
968
- on jsonb_typeof(value) = 'object'
969
- left join lateral
970
- jsonb_array_elements(case jsonb_typeof(value) when 'array' then value end)
971
- with ordinality as a(arr_value, arr_key)
972
- on jsonb_typeof(value) = 'array'
973
- where obj_key is not null or arr_key is not null
974
- )
975
- SELECT *, array_length(string_to_array(path, '.'), 1) - 1 as depth
976
- FROM extract_all t1
977
- WHERE NOT EXISTS ( --Keep only leaf values
978
- SELECT 1
979
- FROM extract_all t2
980
- WHERE length(t1.path) < length(t2.path)
981
- AND starts_with(t2.path, t1.path)
982
- );
983
-
984
- */