prostgles-server 4.2.183 → 4.2.184

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 (430) hide show
  1. package/.github/workflows/main.yml +15 -15
  2. package/.prettierignore +2 -0
  3. package/README.md +1 -1
  4. package/dist/Auth/AuthHandler.d.ts.map +1 -1
  5. package/dist/Auth/AuthHandler.js +71 -33
  6. package/dist/Auth/AuthHandler.js.map +1 -1
  7. package/dist/Auth/AuthTypes.d.ts.map +1 -1
  8. package/dist/Auth/getSafeReturnURL.d.ts.map +1 -1
  9. package/dist/Auth/getSafeReturnURL.js.map +1 -1
  10. package/dist/Auth/sendEmail.d.ts.map +1 -1
  11. package/dist/Auth/sendEmail.js +6 -6
  12. package/dist/Auth/sendEmail.js.map +1 -1
  13. package/dist/Auth/setAuthProviders.d.ts +1 -1
  14. package/dist/Auth/setAuthProviders.d.ts.map +1 -1
  15. package/dist/Auth/setAuthProviders.js +15 -8
  16. package/dist/Auth/setAuthProviders.js.map +1 -1
  17. package/dist/Auth/setEmailProvider.d.ts.map +1 -1
  18. package/dist/Auth/setEmailProvider.js +21 -6
  19. package/dist/Auth/setEmailProvider.js.map +1 -1
  20. package/dist/Auth/setupAuthRoutes.d.ts.map +1 -1
  21. package/dist/Auth/setupAuthRoutes.js +27 -9
  22. package/dist/Auth/setupAuthRoutes.js.map +1 -1
  23. package/dist/DBEventsManager.d.ts.map +1 -1
  24. package/dist/DBEventsManager.js +24 -19
  25. package/dist/DBEventsManager.js.map +1 -1
  26. package/dist/DBSchemaBuilder.d.ts.map +1 -1
  27. package/dist/DBSchemaBuilder.js +18 -5
  28. package/dist/DBSchemaBuilder.js.map +1 -1
  29. package/dist/DboBuilder/DboBuilder.d.ts.map +1 -1
  30. package/dist/DboBuilder/DboBuilder.js +7 -2
  31. package/dist/DboBuilder/DboBuilder.js.map +1 -1
  32. package/dist/DboBuilder/DboBuilderTypes.d.ts +4 -4
  33. package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
  34. package/dist/DboBuilder/DboBuilderTypes.js.map +1 -1
  35. package/dist/DboBuilder/QueryBuilder/Functions.d.ts +2 -2
  36. package/dist/DboBuilder/QueryBuilder/Functions.d.ts.map +1 -1
  37. package/dist/DboBuilder/QueryBuilder/Functions.js +293 -173
  38. package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
  39. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts +2 -2
  40. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
  41. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +52 -29
  42. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
  43. package/dist/DboBuilder/QueryBuilder/getJoinQuery.d.ts.map +1 -1
  44. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js +51 -32
  45. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
  46. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts.map +1 -1
  47. package/dist/DboBuilder/QueryBuilder/getNewQuery.js +48 -25
  48. package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
  49. package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts +1 -1
  50. package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts.map +1 -1
  51. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js +32 -23
  52. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js.map +1 -1
  53. package/dist/DboBuilder/QueryStreamer.d.ts +2 -2
  54. package/dist/DboBuilder/QueryStreamer.d.ts.map +1 -1
  55. package/dist/DboBuilder/QueryStreamer.js +68 -23
  56. package/dist/DboBuilder/QueryStreamer.js.map +1 -1
  57. package/dist/DboBuilder/TableHandler/DataValidator.d.ts +1 -1
  58. package/dist/DboBuilder/TableHandler/DataValidator.d.ts.map +1 -1
  59. package/dist/DboBuilder/TableHandler/DataValidator.js +79 -43
  60. package/dist/DboBuilder/TableHandler/DataValidator.js.map +1 -1
  61. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  62. package/dist/DboBuilder/TableHandler/TableHandler.js +39 -15
  63. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  64. package/dist/DboBuilder/TableHandler/delete.d.ts.map +1 -1
  65. package/dist/DboBuilder/TableHandler/delete.js +44 -13
  66. package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
  67. package/dist/DboBuilder/TableHandler/insert.d.ts.map +1 -1
  68. package/dist/DboBuilder/TableHandler/insert.js +81 -22
  69. package/dist/DboBuilder/TableHandler/insert.js.map +1 -1
  70. package/dist/DboBuilder/TableHandler/insertTest.d.ts.map +1 -1
  71. package/dist/DboBuilder/TableHandler/insertTest.js.map +1 -1
  72. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts +1 -1
  73. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts.map +1 -1
  74. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js +7 -4
  75. package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js.map +1 -1
  76. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts.map +1 -1
  77. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js +24 -5
  78. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js.map +1 -1
  79. package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
  80. package/dist/DboBuilder/TableHandler/update.js +16 -4
  81. package/dist/DboBuilder/TableHandler/update.js.map +1 -1
  82. package/dist/DboBuilder/TableHandler/updateBatch.d.ts.map +1 -1
  83. package/dist/DboBuilder/TableHandler/updateBatch.js +33 -10
  84. package/dist/DboBuilder/TableHandler/updateBatch.js.map +1 -1
  85. package/dist/DboBuilder/TableHandler/updateFile.d.ts.map +1 -1
  86. package/dist/DboBuilder/TableHandler/updateFile.js +24 -6
  87. package/dist/DboBuilder/TableHandler/updateFile.js.map +1 -1
  88. package/dist/DboBuilder/TableHandler/upsert.d.ts.map +1 -1
  89. package/dist/DboBuilder/TableHandler/upsert.js +22 -6
  90. package/dist/DboBuilder/TableHandler/upsert.js.map +1 -1
  91. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +5 -5
  92. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  93. package/dist/DboBuilder/ViewHandler/ViewHandler.js +64 -36
  94. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  95. package/dist/DboBuilder/ViewHandler/count.d.ts.map +1 -1
  96. package/dist/DboBuilder/ViewHandler/count.js +21 -7
  97. package/dist/DboBuilder/ViewHandler/count.js.map +1 -1
  98. package/dist/DboBuilder/ViewHandler/find.d.ts.map +1 -1
  99. package/dist/DboBuilder/ViewHandler/find.js +76 -22
  100. package/dist/DboBuilder/ViewHandler/find.js.map +1 -1
  101. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts.map +1 -1
  102. package/dist/DboBuilder/ViewHandler/getExistsCondition.js +19 -10
  103. package/dist/DboBuilder/ViewHandler/getExistsCondition.js.map +1 -1
  104. package/dist/DboBuilder/ViewHandler/getExistsFilters.d.ts.map +1 -1
  105. package/dist/DboBuilder/ViewHandler/getExistsFilters.js +12 -5
  106. package/dist/DboBuilder/ViewHandler/getExistsFilters.js.map +1 -1
  107. package/dist/DboBuilder/ViewHandler/getInfo.d.ts.map +1 -1
  108. package/dist/DboBuilder/ViewHandler/getInfo.js +27 -9
  109. package/dist/DboBuilder/ViewHandler/getInfo.js.map +1 -1
  110. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts +2 -2
  111. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts.map +1 -1
  112. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js +42 -23
  113. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js.map +1 -1
  114. package/dist/DboBuilder/ViewHandler/parseComplexFilter.d.ts.map +1 -1
  115. package/dist/DboBuilder/ViewHandler/parseComplexFilter.js +22 -9
  116. package/dist/DboBuilder/ViewHandler/parseComplexFilter.js.map +1 -1
  117. package/dist/DboBuilder/ViewHandler/parseFieldFilter.d.ts +4 -4
  118. package/dist/DboBuilder/ViewHandler/parseFieldFilter.d.ts.map +1 -1
  119. package/dist/DboBuilder/ViewHandler/parseFieldFilter.js +13 -11
  120. package/dist/DboBuilder/ViewHandler/parseFieldFilter.js.map +1 -1
  121. package/dist/DboBuilder/ViewHandler/parseJoinPath.d.ts +1 -1
  122. package/dist/DboBuilder/ViewHandler/parseJoinPath.d.ts.map +1 -1
  123. package/dist/DboBuilder/ViewHandler/parseJoinPath.js +44 -29
  124. package/dist/DboBuilder/ViewHandler/parseJoinPath.js.map +1 -1
  125. package/dist/DboBuilder/ViewHandler/prepareSortItems.d.ts.map +1 -1
  126. package/dist/DboBuilder/ViewHandler/prepareSortItems.js +36 -27
  127. package/dist/DboBuilder/ViewHandler/prepareSortItems.js.map +1 -1
  128. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts.map +1 -1
  129. package/dist/DboBuilder/ViewHandler/prepareWhere.js +16 -12
  130. package/dist/DboBuilder/ViewHandler/prepareWhere.js.map +1 -1
  131. package/dist/DboBuilder/ViewHandler/size.d.ts.map +1 -1
  132. package/dist/DboBuilder/ViewHandler/size.js +24 -7
  133. package/dist/DboBuilder/ViewHandler/size.js.map +1 -1
  134. package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
  135. package/dist/DboBuilder/ViewHandler/subscribe.js +40 -12
  136. package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
  137. package/dist/DboBuilder/ViewHandler/validateViewRules.d.ts.map +1 -1
  138. package/dist/DboBuilder/ViewHandler/validateViewRules.js +20 -5
  139. package/dist/DboBuilder/ViewHandler/validateViewRules.js.map +1 -1
  140. package/dist/DboBuilder/dboBuilderUtils.d.ts.map +1 -1
  141. package/dist/DboBuilder/dboBuilderUtils.js +18 -7
  142. package/dist/DboBuilder/dboBuilderUtils.js.map +1 -1
  143. package/dist/DboBuilder/getColumns.d.ts.map +1 -1
  144. package/dist/DboBuilder/getColumns.js +22 -7
  145. package/dist/DboBuilder/getColumns.js.map +1 -1
  146. package/dist/DboBuilder/getCondition.d.ts.map +1 -1
  147. package/dist/DboBuilder/getCondition.js +43 -30
  148. package/dist/DboBuilder/getCondition.js.map +1 -1
  149. package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
  150. package/dist/DboBuilder/getSubscribeRelatedTables.js +38 -27
  151. package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
  152. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
  153. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js +9 -9
  154. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js.map +1 -1
  155. package/dist/DboBuilder/insertNestedRecords.d.ts +3 -3
  156. package/dist/DboBuilder/insertNestedRecords.d.ts.map +1 -1
  157. package/dist/DboBuilder/insertNestedRecords.js +79 -44
  158. package/dist/DboBuilder/insertNestedRecords.js.map +1 -1
  159. package/dist/DboBuilder/parseUpdateRules.d.ts.map +1 -1
  160. package/dist/DboBuilder/parseUpdateRules.js +38 -14
  161. package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
  162. package/dist/DboBuilder/prepareShortestJoinPaths.d.ts.map +1 -1
  163. package/dist/DboBuilder/prepareShortestJoinPaths.js +56 -31
  164. package/dist/DboBuilder/prepareShortestJoinPaths.js.map +1 -1
  165. package/dist/DboBuilder/runSQL.d.ts.map +1 -1
  166. package/dist/DboBuilder/runSQL.js +41 -21
  167. package/dist/DboBuilder/runSQL.js.map +1 -1
  168. package/dist/DboBuilder/runTransaction.d.ts +1 -1
  169. package/dist/DboBuilder/runTransaction.d.ts.map +1 -1
  170. package/dist/DboBuilder/runTransaction.js +2 -2
  171. package/dist/DboBuilder/runTransaction.js.map +1 -1
  172. package/dist/DboBuilder/sqlErrCodeToMsg.d.ts.map +1 -1
  173. package/dist/DboBuilder/sqlErrCodeToMsg.js +297 -38
  174. package/dist/DboBuilder/sqlErrCodeToMsg.js.map +1 -1
  175. package/dist/DboBuilder/uploadFile.d.ts.map +1 -1
  176. package/dist/DboBuilder/uploadFile.js +33 -9
  177. package/dist/DboBuilder/uploadFile.js.map +1 -1
  178. package/dist/Event_Trigger_Tags.d.ts +1 -1
  179. package/dist/Event_Trigger_Tags.d.ts.map +1 -1
  180. package/dist/Event_Trigger_Tags.js +1 -1
  181. package/dist/Event_Trigger_Tags.js.map +1 -1
  182. package/dist/FileManager/FileManager.d.ts.map +1 -1
  183. package/dist/FileManager/FileManager.js +6 -3
  184. package/dist/FileManager/FileManager.js.map +1 -1
  185. package/dist/FileManager/getValidatedFileType.d.ts.map +1 -1
  186. package/dist/FileManager/getValidatedFileType.js +18 -16
  187. package/dist/FileManager/getValidatedFileType.js.map +1 -1
  188. package/dist/FileManager/initFileManager.d.ts.map +1 -1
  189. package/dist/FileManager/initFileManager.js +7 -1
  190. package/dist/FileManager/initFileManager.js.map +1 -1
  191. package/dist/FileManager/upload.d.ts +1 -1
  192. package/dist/FileManager/upload.d.ts.map +1 -1
  193. package/dist/FileManager/upload.js +3 -3
  194. package/dist/FileManager/upload.js.map +1 -1
  195. package/dist/FileManager/uploadStream.d.ts +1 -1
  196. package/dist/FileManager/uploadStream.d.ts.map +1 -1
  197. package/dist/FileManager/uploadStream.js +6 -7
  198. package/dist/FileManager/uploadStream.js.map +1 -1
  199. package/dist/Filtering.d.ts +3 -3
  200. package/dist/Filtering.d.ts.map +1 -1
  201. package/dist/Filtering.js +70 -37
  202. package/dist/Filtering.js.map +1 -1
  203. package/dist/JSONBValidation/validate_jsonb_schema_sql.d.ts.map +1 -1
  204. package/dist/JSONBValidation/validate_jsonb_schema_sql.js +1 -4
  205. package/dist/JSONBValidation/validate_jsonb_schema_sql.js.map +1 -1
  206. package/dist/JSONBValidation/validation.d.ts.map +1 -1
  207. package/dist/JSONBValidation/validation.js +46 -24
  208. package/dist/JSONBValidation/validation.js.map +1 -1
  209. package/dist/Logging.d.ts +2 -2
  210. package/dist/Logging.d.ts.map +1 -1
  211. package/dist/PostgresNotifListenManager.d.ts.map +1 -1
  212. package/dist/PostgresNotifListenManager.js +20 -22
  213. package/dist/PostgresNotifListenManager.js.map +1 -1
  214. package/dist/Prostgles.d.ts +1 -1
  215. package/dist/Prostgles.d.ts.map +1 -1
  216. package/dist/Prostgles.js +37 -11
  217. package/dist/Prostgles.js.map +1 -1
  218. package/dist/ProstglesTypes.d.ts.map +1 -1
  219. package/dist/ProstglesTypes.js +6 -1
  220. package/dist/ProstglesTypes.js.map +1 -1
  221. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  222. package/dist/PubSubManager/PubSubManager.js +10 -5
  223. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  224. package/dist/PubSubManager/addSub.d.ts.map +1 -1
  225. package/dist/PubSubManager/addSub.js +4 -6
  226. package/dist/PubSubManager/addSub.js.map +1 -1
  227. package/dist/PubSubManager/addSync.d.ts.map +1 -1
  228. package/dist/PubSubManager/addSync.js +10 -6
  229. package/dist/PubSubManager/addSync.js.map +1 -1
  230. package/dist/PubSubManager/getCreatePubSubManagerError.d.ts.map +1 -1
  231. package/dist/PubSubManager/getCreatePubSubManagerError.js +3 -1
  232. package/dist/PubSubManager/getCreatePubSubManagerError.js.map +1 -1
  233. package/dist/PubSubManager/getPubSubManagerInitQuery.d.ts.map +1 -1
  234. package/dist/PubSubManager/getPubSubManagerInitQuery.js +8 -8
  235. package/dist/PubSubManager/getPubSubManagerInitQuery.js.map +1 -1
  236. package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
  237. package/dist/PubSubManager/initPubSubManager.js +7 -9
  238. package/dist/PubSubManager/initPubSubManager.js.map +1 -1
  239. package/dist/PubSubManager/notifListener.d.ts.map +1 -1
  240. package/dist/PubSubManager/notifListener.js +23 -12
  241. package/dist/PubSubManager/notifListener.js.map +1 -1
  242. package/dist/PubSubManager/orphanTriggerCheck.d.ts.map +1 -1
  243. package/dist/PubSubManager/orphanTriggerCheck.js.map +1 -1
  244. package/dist/PubSubManager/pushSubData.d.ts.map +1 -1
  245. package/dist/PubSubManager/pushSubData.js +1 -1
  246. package/dist/PubSubManager/pushSubData.js.map +1 -1
  247. package/dist/PublishParser/PublishParser.d.ts +1 -1
  248. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  249. package/dist/PublishParser/PublishParser.js +25 -14
  250. package/dist/PublishParser/PublishParser.js.map +1 -1
  251. package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
  252. package/dist/PublishParser/getFileTableRules.js +23 -16
  253. package/dist/PublishParser/getFileTableRules.js.map +1 -1
  254. package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
  255. package/dist/PublishParser/getSchemaFromPublish.js +39 -16
  256. package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
  257. package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +1 -1
  258. package/dist/PublishParser/getTableRulesWithoutFileTable.js +42 -22
  259. package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
  260. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  261. package/dist/PublishParser/publishTypesAndUtils.js +5 -1
  262. package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
  263. package/dist/RestApi.d.ts +1 -1
  264. package/dist/RestApi.d.ts.map +1 -1
  265. package/dist/RestApi.js +1 -1
  266. package/dist/RestApi.js.map +1 -1
  267. package/dist/SchemaWatch/SchemaWatch.d.ts +2 -2
  268. package/dist/SchemaWatch/SchemaWatch.d.ts.map +1 -1
  269. package/dist/SchemaWatch/SchemaWatch.js +11 -9
  270. package/dist/SchemaWatch/SchemaWatch.js.map +1 -1
  271. package/dist/SchemaWatch/getValidatedWatchSchemaType.d.ts.map +1 -1
  272. package/dist/SchemaWatch/getValidatedWatchSchemaType.js +3 -3
  273. package/dist/SchemaWatch/getValidatedWatchSchemaType.js.map +1 -1
  274. package/dist/SchemaWatch/getWatchSchemaTagList.d.ts.map +1 -1
  275. package/dist/SchemaWatch/getWatchSchemaTagList.js +12 -6
  276. package/dist/SchemaWatch/getWatchSchemaTagList.js.map +1 -1
  277. package/dist/SyncReplication.d.ts.map +1 -1
  278. package/dist/SyncReplication.js +84 -42
  279. package/dist/SyncReplication.js.map +1 -1
  280. package/dist/TableConfig/TableConfig.d.ts +5 -5
  281. package/dist/TableConfig/TableConfig.d.ts.map +1 -1
  282. package/dist/TableConfig/TableConfig.js +18 -5
  283. package/dist/TableConfig/TableConfig.js.map +1 -1
  284. package/dist/TableConfig/getColumnDefinitionQuery.d.ts +2 -2
  285. package/dist/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
  286. package/dist/TableConfig/getColumnDefinitionQuery.js +20 -9
  287. package/dist/TableConfig/getColumnDefinitionQuery.js.map +1 -1
  288. package/dist/TableConfig/getConstraintDefinitionQueries.d.ts +3 -3
  289. package/dist/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -1
  290. package/dist/TableConfig/getConstraintDefinitionQueries.js +12 -7
  291. package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
  292. package/dist/TableConfig/getFutureTableSchema.d.ts +1 -1
  293. package/dist/TableConfig/getFutureTableSchema.d.ts.map +1 -1
  294. package/dist/TableConfig/getFutureTableSchema.js +6 -4
  295. package/dist/TableConfig/getFutureTableSchema.js.map +1 -1
  296. package/dist/TableConfig/getPGIndexes.d.ts.map +1 -1
  297. package/dist/TableConfig/getPGIndexes.js.map +1 -1
  298. package/dist/TableConfig/getTableColumnQueries.d.ts +1 -1
  299. package/dist/TableConfig/getTableColumnQueries.d.ts.map +1 -1
  300. package/dist/TableConfig/getTableColumnQueries.js +38 -19
  301. package/dist/TableConfig/getTableColumnQueries.js.map +1 -1
  302. package/dist/TableConfig/initTableConfig.d.ts.map +1 -1
  303. package/dist/TableConfig/initTableConfig.js +91 -43
  304. package/dist/TableConfig/initTableConfig.js.map +1 -1
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js.map +1 -1
  307. package/dist/initProstgles.d.ts.map +1 -1
  308. package/dist/initProstgles.js +14 -10
  309. package/dist/initProstgles.js.map +1 -1
  310. package/dist/onSocketConnected.d.ts.map +1 -1
  311. package/dist/onSocketConnected.js +38 -16
  312. package/dist/onSocketConnected.js.map +1 -1
  313. package/dist/runClientRequest.d.ts.map +1 -1
  314. package/dist/runClientRequest.js +33 -14
  315. package/dist/runClientRequest.js.map +1 -1
  316. package/dist/shortestPath.d.ts.map +1 -1
  317. package/dist/shortestPath.js +1 -1
  318. package/dist/shortestPath.js.map +1 -1
  319. package/dist/typeTests/dboTypeCheck.js.map +1 -1
  320. package/examples/full-example-typescript/DBoGenerated.d.ts +112 -54
  321. package/examples/full-example-typescript/DBoGenerated.js +3 -3
  322. package/examples/full-example-typescript/home.html +28 -26
  323. package/examples/full-example-typescript/index.d.ts +1 -1
  324. package/examples/full-example-typescript/index.js +80 -53
  325. package/examples/full-example-vanilla/home.html +151 -125
  326. package/examples/server/javascript/index.js +17 -19
  327. package/lib/Auth/AuthHandler.ts +285 -167
  328. package/lib/Auth/AuthTypes.ts +43 -12
  329. package/lib/Auth/getSafeReturnURL.ts +35 -21
  330. package/lib/Auth/sendEmail.ts +34 -31
  331. package/lib/Auth/setAuthProviders.ts +94 -71
  332. package/lib/Auth/setEmailProvider.ts +53 -36
  333. package/lib/Auth/setupAuthRoutes.ts +164 -100
  334. package/lib/DBEventsManager.ts +87 -65
  335. package/lib/DBSchemaBuilder.ts +62 -28
  336. package/lib/DboBuilder/DboBuilder.ts +45 -21
  337. package/lib/DboBuilder/DboBuilderTypes.ts +99 -95
  338. package/lib/DboBuilder/QueryBuilder/Functions.ts +862 -580
  339. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +202 -141
  340. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +199 -124
  341. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +209 -148
  342. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +101 -75
  343. package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +10 -5
  344. package/lib/DboBuilder/QueryStreamer.ts +207 -100
  345. package/lib/DboBuilder/TableHandler/DataValidator.ts +253 -148
  346. package/lib/DboBuilder/TableHandler/TableHandler.ts +155 -60
  347. package/lib/DboBuilder/TableHandler/delete.ts +82 -29
  348. package/lib/DboBuilder/TableHandler/insert.ts +177 -81
  349. package/lib/DboBuilder/TableHandler/insertTest.ts +13 -7
  350. package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +35 -21
  351. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +95 -45
  352. package/lib/DboBuilder/TableHandler/update.ts +54 -14
  353. package/lib/DboBuilder/TableHandler/updateBatch.ts +59 -21
  354. package/lib/DboBuilder/TableHandler/updateFile.ts +57 -26
  355. package/lib/DboBuilder/TableHandler/upsert.ts +58 -13
  356. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +264 -121
  357. package/lib/DboBuilder/ViewHandler/count.ts +56 -25
  358. package/lib/DboBuilder/ViewHandler/find.ts +153 -68
  359. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +59 -32
  360. package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +31 -19
  361. package/lib/DboBuilder/ViewHandler/getInfo.ts +47 -16
  362. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +91 -57
  363. package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +51 -29
  364. package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +35 -29
  365. package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +130 -76
  366. package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +140 -92
  367. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +66 -26
  368. package/lib/DboBuilder/ViewHandler/size.ts +56 -22
  369. package/lib/DboBuilder/ViewHandler/subscribe.ts +122 -46
  370. package/lib/DboBuilder/ViewHandler/validateViewRules.ts +39 -14
  371. package/lib/DboBuilder/dboBuilderUtils.ts +41 -18
  372. package/lib/DboBuilder/getColumns.ts +44 -12
  373. package/lib/DboBuilder/getCondition.ts +120 -79
  374. package/lib/DboBuilder/getSubscribeRelatedTables.ts +144 -83
  375. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +61 -44
  376. package/lib/DboBuilder/insertNestedRecords.ts +370 -235
  377. package/lib/DboBuilder/parseUpdateRules.ts +117 -61
  378. package/lib/DboBuilder/prepareShortestJoinPaths.ts +115 -56
  379. package/lib/DboBuilder/runSQL.ts +135 -74
  380. package/lib/DboBuilder/runTransaction.ts +27 -16
  381. package/lib/DboBuilder/sqlErrCodeToMsg.ts +502 -244
  382. package/lib/DboBuilder/uploadFile.ts +67 -31
  383. package/lib/Event_Trigger_Tags.ts +6 -4
  384. package/lib/FileManager/FileManager.ts +53 -21
  385. package/lib/FileManager/getValidatedFileType.ts +79 -35
  386. package/lib/FileManager/initFileManager.ts +21 -9
  387. package/lib/FileManager/upload.ts +21 -19
  388. package/lib/FileManager/uploadStream.ts +33 -34
  389. package/lib/Filtering.ts +249 -197
  390. package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +2 -7
  391. package/lib/JSONBValidation/validation.ts +147 -82
  392. package/lib/Logging.ts +107 -97
  393. package/lib/PostgresNotifListenManager.ts +96 -63
  394. package/lib/Prostgles.ts +106 -35
  395. package/lib/ProstglesTypes.ts +31 -9
  396. package/lib/PubSubManager/PubSubManager.ts +62 -27
  397. package/lib/PubSubManager/addSub.ts +56 -37
  398. package/lib/PubSubManager/addSync.ts +50 -33
  399. package/lib/PubSubManager/getCreatePubSubManagerError.ts +29 -21
  400. package/lib/PubSubManager/getPubSubManagerInitQuery.ts +45 -27
  401. package/lib/PubSubManager/initPubSubManager.ts +27 -18
  402. package/lib/PubSubManager/notifListener.ts +77 -59
  403. package/lib/PubSubManager/orphanTriggerCheck.ts +5 -4
  404. package/lib/PubSubManager/pushSubData.ts +11 -9
  405. package/lib/PublishParser/PublishParser.ts +102 -44
  406. package/lib/PublishParser/getFileTableRules.ts +97 -54
  407. package/lib/PublishParser/getSchemaFromPublish.ts +146 -74
  408. package/lib/PublishParser/getTableRulesWithoutFileTable.ts +101 -51
  409. package/lib/PublishParser/publishTypesAndUtils.ts +74 -23
  410. package/lib/RestApi.ts +10 -2
  411. package/lib/SchemaWatch/SchemaWatch.ts +52 -34
  412. package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +1 -1
  413. package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +32 -22
  414. package/lib/SchemaWatch/getWatchSchemaTagList.ts +24 -16
  415. package/lib/SyncReplication.ts +376 -190
  416. package/lib/TableConfig/TableConfig.ts +200 -136
  417. package/lib/TableConfig/getColumnDefinitionQuery.ts +65 -44
  418. package/lib/TableConfig/getConstraintDefinitionQueries.ts +41 -25
  419. package/lib/TableConfig/getFutureTableSchema.ts +31 -21
  420. package/lib/TableConfig/getPGIndexes.ts +7 -4
  421. package/lib/TableConfig/getTableColumnQueries.ts +101 -54
  422. package/lib/TableConfig/initTableConfig.ts +192 -101
  423. package/lib/index.ts +6 -5
  424. package/lib/initProstgles.ts +57 -51
  425. package/lib/onSocketConnected.ts +75 -40
  426. package/lib/runClientRequest.ts +148 -79
  427. package/lib/shortestPath.ts +80 -76
  428. package/lib/typeTests/DBoGenerated.d.ts +5 -1
  429. package/lib/typeTests/dboTypeCheck.ts +8 -8
  430. package/package.json +1 -1
@@ -1,54 +1,84 @@
1
- import { asName, ColumnInfo, isEmpty, isObject, PG_COLUMN_UDT_DATA_TYPE, TextFilter_FullTextSearchFilterKeys } from "prostgles-types";
1
+ import {
2
+ asName,
3
+ ColumnInfo,
4
+ isEmpty,
5
+ isObject,
6
+ PG_COLUMN_UDT_DATA_TYPE,
7
+ TextFilter_FullTextSearchFilterKeys,
8
+ } from "prostgles-types";
2
9
  import { isPlainObject, pgp, postgresToTsType } from "../DboBuilder";
3
10
  import { parseFieldFilter } from "../ViewHandler/parseFieldFilter";
4
11
  import { asNameAlias } from "./QueryBuilder";
5
12
 
6
- export const parseFunction = (funcData: { func: string | FunctionSpec, args: any[], functions: FunctionSpec[]; allowedFields: string[]; }): FunctionSpec => {
13
+ export const parseFunction = (funcData: {
14
+ func: string | FunctionSpec;
15
+ args: any[];
16
+ functions: FunctionSpec[];
17
+ allowedFields: string[];
18
+ }): FunctionSpec => {
7
19
  const { func, args, functions, allowedFields } = funcData;
8
20
 
9
21
  /* Function is computed column. No checks needed */
10
- if(typeof func !== "string"){
11
- const computedCol = COMPUTED_FIELDS.find(c => c.name === func.name);
12
- if(!computedCol) throw `Unexpected function: computed column spec not found for ${JSON.stringify(func.name)}`;
22
+ if (typeof func !== "string") {
23
+ const computedCol = COMPUTED_FIELDS.find((c) => c.name === func.name);
24
+ if (!computedCol)
25
+ throw `Unexpected function: computed column spec not found for ${JSON.stringify(func.name)}`;
13
26
  return func;
14
27
  }
15
28
 
16
29
  const funcName = func;
17
30
  const makeErr = (msg: string): string => {
18
- return `Issue with function ${JSON.stringify({ [funcName]: args })}: \n${msg}`
19
- }
31
+ return `Issue with function ${JSON.stringify({ [funcName]: args })}: \n${msg}`;
32
+ };
20
33
 
21
34
  /* Find function */
22
- const funcDef = functions.find(f => f.name === funcName);
23
-
24
- if(!funcDef) {
25
- const sf = functions.filter(f => f.name.toLowerCase().slice(1).startsWith(funcName.toLowerCase())).sort((a, b) => (a.name.length - b.name.length));
26
- const hint = (sf.length? `. \n Maybe you meant: \n | ${sf.map(s => s.name + " " + (s.description || "")).join(" \n | ")} ?` : "");
27
- throw "\n Function " + funcName + " does not exist or is not allowed " + hint;
35
+ const funcDef = functions.find((f) => f.name === funcName);
36
+
37
+ if (!funcDef) {
38
+ const sf = functions
39
+ .filter((f) =>
40
+ f.name.toLowerCase().slice(1).startsWith(funcName.toLowerCase()),
41
+ )
42
+ .sort((a, b) => a.name.length - b.name.length);
43
+ const hint = sf.length
44
+ ? `. \n Maybe you meant: \n | ${sf.map((s) => s.name + " " + (s.description || "")).join(" \n | ")} ?`
45
+ : "";
46
+ throw (
47
+ "\n Function " + funcName + " does not exist or is not allowed " + hint
48
+ );
28
49
  }
29
-
50
+
30
51
  /* Validate fields */
31
52
  const fields = funcDef.getFields(args);
32
- if(fields !== "*"){
33
- fields.forEach(fieldKey => {
34
- if(typeof fieldKey !== "string" || !allowedFields.includes(fieldKey)) {
35
- throw makeErr(`getFields() => field name ${JSON.stringify(fieldKey)} is invalid or disallowed`)
53
+ if (fields !== "*") {
54
+ fields.forEach((fieldKey) => {
55
+ if (typeof fieldKey !== "string" || !allowedFields.includes(fieldKey)) {
56
+ throw makeErr(
57
+ `getFields() => field name ${JSON.stringify(fieldKey)} is invalid or disallowed`,
58
+ );
36
59
  }
37
60
  });
38
- if((funcDef.minCols ?? 0) > fields.length){
39
- throw makeErr(`Less columns provided than necessary (minCols=${funcDef.minCols})`)
61
+ if ((funcDef.minCols ?? 0) > fields.length) {
62
+ throw makeErr(
63
+ `Less columns provided than necessary (minCols=${funcDef.minCols})`,
64
+ );
40
65
  }
41
66
  }
42
67
 
43
- if(funcDef.numArgs && funcDef.minCols !== 0 && fields !== "*" && Array.isArray(fields) && !fields.length) {
68
+ if (
69
+ funcDef.numArgs &&
70
+ funcDef.minCols !== 0 &&
71
+ fields !== "*" &&
72
+ Array.isArray(fields) &&
73
+ !fields.length
74
+ ) {
44
75
  throw `\n Function "${funcDef.name}" expects at least a field name but has not been provided with one`;
45
76
  }
46
77
 
47
78
  return funcDef;
48
- }
49
-
79
+ };
50
80
 
51
- type GetQueryArgs = {
81
+ type GetQueryArgs = {
52
82
  allColumns: ColumnInfo[];
53
83
  allowedFields: string[];
54
84
  args: any[];
@@ -113,102 +143,142 @@ export type FunctionSpec = {
113
143
  const MAX_COL_NUM = 1600;
114
144
  const asValue = (v: any, castAs = "") => pgp.as.format("$1" + castAs, [v]);
115
145
 
116
- const parseUnix = (colName: string, tableAlias: string | undefined, allColumns: ColumnInfo[], opts: { timeZone: boolean | string } | undefined) => {
146
+ const parseUnix = (
147
+ colName: string,
148
+ tableAlias: string | undefined,
149
+ allColumns: ColumnInfo[],
150
+ opts: { timeZone: boolean | string } | undefined,
151
+ ) => {
117
152
  let tz = "";
118
- if(opts){
153
+ if (opts) {
119
154
  const { timeZone } = opts ?? {};
120
- if(timeZone && typeof timeZone !== "string" && typeof timeZone !== "boolean"){
155
+ if (
156
+ timeZone &&
157
+ typeof timeZone !== "string" &&
158
+ typeof timeZone !== "boolean"
159
+ ) {
121
160
  throw `Bad timeZone value. timeZone can be boolean or string`;
122
161
  }
123
- if(timeZone === true){
162
+ if (timeZone === true) {
124
163
  tz = "::TIMESTAMPTZ";
125
- } else if(typeof timeZone === "string"){
164
+ } else if (typeof timeZone === "string") {
126
165
  tz = ` AT TIME ZONE ${asValue(timeZone)}`;
127
166
  }
128
167
  }
129
- const col = allColumns.find(c => c.name === colName);
130
- if(!col) throw `Unexpected: column ${colName} not found`;
131
- const escapedName = asNameAlias(colName, tableAlias);
132
- if(col.udt_name === "int8"){
133
- return `to_timestamp(${escapedName}/1000.0)${tz}`
168
+ const col = allColumns.find((c) => c.name === colName);
169
+ if (!col) throw `Unexpected: column ${colName} not found`;
170
+ const escapedName = asNameAlias(colName, tableAlias);
171
+ if (col.udt_name === "int8") {
172
+ return `to_timestamp(${escapedName}/1000.0)${tz}`;
134
173
  }
135
174
 
136
175
  return `${escapedName}${tz}`;
137
- }
176
+ };
138
177
 
139
178
  const JSON_Funcs: FunctionSpec[] = [
140
179
  {
141
180
  name: "$jsonb_set",
142
- 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",
181
+ description:
182
+ "[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",
143
183
  singleColArg: false,
144
184
  numArgs: 4,
145
185
  type: "function",
146
186
  getFields: ([column]) => column,
147
- getQuery: ({
187
+ getQuery: ({
148
188
  args: [colName, path = [], new_value, create_missing = true],
149
- tableAlias, allowedFields
189
+ tableAlias,
190
+ allowedFields,
150
191
  }) => {
151
- if(!allowedFields.includes(colName)) {
192
+ if (!allowedFields.includes(colName)) {
152
193
  throw `Unexpected: column ${colName} not found`;
153
194
  }
154
- if(!path || !Array.isArray(path) || !path.every(v => ["number", "string"].includes(typeof v))){
155
- throw "Expecting: [columnName: string, path: (string | number)[], new_value?: any, create_missing?: boolean ]"
195
+ if (
196
+ !path ||
197
+ !Array.isArray(path) ||
198
+ !path.every((v) => ["number", "string"].includes(typeof v))
199
+ ) {
200
+ throw "Expecting: [columnName: string, path: (string | number)[], new_value?: any, create_missing?: boolean ]";
156
201
  }
157
- const escapedName = asNameAlias(colName, tableAlias);
202
+ const escapedName = asNameAlias(colName, tableAlias);
158
203
 
159
204
  return `jsonb_set(${escapedName}, ${asValue(path)}, ${asValue(new_value)}, ${create_missing})`;
160
- }
205
+ },
161
206
  },
162
207
 
163
208
  {
164
209
  name: "$jsonb_path_query",
165
- 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.",
210
+ description:
211
+ "[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.",
166
212
  singleColArg: false,
167
213
  numArgs: 4,
168
214
  type: "function",
169
215
  getFields: ([column]) => column,
170
- getQuery: ({
216
+ getQuery: ({
171
217
  args: [colName, jsonPath, ...otherArgs],
172
- tableAlias, allowedFields
218
+ tableAlias,
219
+ allowedFields,
173
220
  }) => {
174
- if(!allowedFields.includes(colName)) {
221
+ if (!allowedFields.includes(colName)) {
175
222
  throw `Unexpected: column ${colName} not found`;
176
223
  }
177
- if(!jsonPath || typeof jsonPath !== "string"){
178
- throw "Expecting: [columnName: string, jsonPath: string, vars?: object, silent?: boolean]"
224
+ if (!jsonPath || typeof jsonPath !== "string") {
225
+ throw "Expecting: [columnName: string, jsonPath: string, vars?: object, silent?: boolean]";
179
226
  }
180
- const escapedName = asNameAlias(colName, tableAlias);
227
+ const escapedName = asNameAlias(colName, tableAlias);
181
228
 
182
- return `jsonb_path_query(${escapedName}, ${[jsonPath, ...otherArgs].map(v => asValue(v)).join(", ")})`;
183
- }
229
+ return `jsonb_path_query(${escapedName}, ${[jsonPath, ...otherArgs].map((v) => asValue(v)).join(", ")})`;
230
+ },
184
231
  },
185
232
 
186
- ...([
187
- ["jsonb_array_length", "Returns the number of elements in the outermost JSON array"],
188
- ["jsonb_each", "Expands the outermost JSON object into a set of key/value pairs"],
189
- ["jsonb_each_text", "Expands the outermost JSON object into a set of key/value pairs. The returned values will be of type text"],
190
- ["jsonb_object_keys", "Returns set of keys in the outermost JSON object"],
191
- ["jsonb_strip_nulls", "Returns from_json with all object fields that have null values omitted. Other null values are untouched"],
192
- ["jsonb_pretty", "Returns from_json as indented JSON text "],
193
- ["jsonb_to_record", "Builds an arbitrary record from a JSON object"],
194
- ["jsonb_array_elements", "Expands a JSON array to a set of JSON values"],
195
- ["jsonb_array_elements_text", "Expands a JSON array to a set of text values "],
196
- ["jsonb_typeof", "Returns the type of the outermost JSON value as a text string. Possible types are object, array, string, number, boolean, and null "],
197
- ] as const).map(([ name, description]) => ({
198
- name: "$" + name,
199
- description,
200
- singleColArg: true,
201
- numArgs: 1,
202
- type: "function",
203
- getFields: ([col]) => col,
204
- getQuery: ({ args: [colName], tableAlias }) => {
205
- const escapedName = asNameAlias(colName, tableAlias);
206
- return `${name}(${escapedName})`;
207
- }
208
- } as FunctionSpec))
233
+ ...(
234
+ [
235
+ [
236
+ "jsonb_array_length",
237
+ "Returns the number of elements in the outermost JSON array",
238
+ ],
239
+ [
240
+ "jsonb_each",
241
+ "Expands the outermost JSON object into a set of key/value pairs",
242
+ ],
243
+ [
244
+ "jsonb_each_text",
245
+ "Expands the outermost JSON object into a set of key/value pairs. The returned values will be of type text",
246
+ ],
247
+ ["jsonb_object_keys", "Returns set of keys in the outermost JSON object"],
248
+ [
249
+ "jsonb_strip_nulls",
250
+ "Returns from_json with all object fields that have null values omitted. Other null values are untouched",
251
+ ],
252
+ ["jsonb_pretty", "Returns from_json as indented JSON text "],
253
+ ["jsonb_to_record", "Builds an arbitrary record from a JSON object"],
254
+ ["jsonb_array_elements", "Expands a JSON array to a set of JSON values"],
255
+ [
256
+ "jsonb_array_elements_text",
257
+ "Expands a JSON array to a set of text values ",
258
+ ],
259
+ [
260
+ "jsonb_typeof",
261
+ "Returns the type of the outermost JSON value as a text string. Possible types are object, array, string, number, boolean, and null ",
262
+ ],
263
+ ] as const
264
+ ).map(
265
+ ([name, description]) =>
266
+ ({
267
+ name: "$" + name,
268
+ description,
269
+ singleColArg: true,
270
+ numArgs: 1,
271
+ type: "function",
272
+ getFields: ([col]) => col,
273
+ getQuery: ({ args: [colName], tableAlias }) => {
274
+ const escapedName = asNameAlias(colName, tableAlias);
275
+ return `${name}(${escapedName})`;
276
+ },
277
+ }) as FunctionSpec,
278
+ ),
209
279
  ];
210
280
 
211
- const FTS_Funcs: FunctionSpec[] =
281
+ const FTS_Funcs: FunctionSpec[] =
212
282
  /* Full text search
213
283
  https://www.postgresql.org/docs/current/textsearch-dictionaries.html#TEXTSEARCH-SIMPLE-DICTIONARY
214
284
  */
@@ -217,10 +287,10 @@ const FTS_Funcs: FunctionSpec[] =
217
287
  // "synonym", // replace word with a synonym
218
288
  "english",
219
289
  // "english_stem",
220
- // "english_hunspell",
221
- ""
222
- ].map(type => ({
223
- name: "$ts_headline" + (type? ("_" + type) : ""),
290
+ // "english_hunspell",
291
+ "",
292
+ ].map((type) => ({
293
+ name: "$ts_headline" + (type ? "_" + type : ""),
224
294
  description: ` :[column_name <string>, search_term: <string | { to_tsquery: string } > ] -> sha512 hash of the of column content`,
225
295
  type: "function" as const,
226
296
  singleColArg: true,
@@ -228,253 +298,291 @@ const FTS_Funcs: FunctionSpec[] =
228
298
  getFields: ([column]) => [column],
229
299
  getQuery: ({ args }) => {
230
300
  const col = asName(args[0]);
231
- let qVal = args[1], qType = "to_tsquery";
232
- const _type = type? (asValue(type) + ",") : "";
301
+ let qVal = args[1],
302
+ qType = "to_tsquery";
303
+ const _type = type ? asValue(type) + "," : "";
233
304
 
234
305
  const searchTypes = TextFilter_FullTextSearchFilterKeys;
235
-
306
+
236
307
  /* { to_tsquery: 'search term' } */
237
- if(isPlainObject(qVal)){
308
+ if (isPlainObject(qVal)) {
238
309
  const keys = Object.keys(qVal);
239
- if(!keys.length) throw "Bad arg";
240
- if(keys.length !==1 || !searchTypes.includes(keys[0] as any)) throw "Expecting a an object with a single key named one of: " + searchTypes.join(", ");
310
+ if (!keys.length) throw "Bad arg";
311
+ if (keys.length !== 1 || !searchTypes.includes(keys[0] as any))
312
+ throw (
313
+ "Expecting a an object with a single key named one of: " +
314
+ searchTypes.join(", ")
315
+ );
241
316
  qType = keys[0]!;
242
317
  qVal = asValue(qVal[qType]);
243
318
 
244
- /* 'search term' */
245
- } else if(typeof qVal === "string") {
246
- qVal = pgp.as.format(qType + "($1)", [qVal])
247
- } else throw "Bad second arg. Exepcting search string or { to_tsquery: 'search string' }";
319
+ /* 'search term' */
320
+ } else if (typeof qVal === "string") {
321
+ qVal = pgp.as.format(qType + "($1)", [qVal]);
322
+ } else
323
+ throw "Bad second arg. Exepcting search string or { to_tsquery: 'search string' }";
248
324
 
249
- const res = `ts_headline(${_type} ${col}::text, ${qVal}, 'ShortWord=1 ' )`
325
+ const res = `ts_headline(${_type} ${col}::text, ${qVal}, 'ShortWord=1 ' )`;
250
326
  // console.log(res)
251
-
252
- return res
253
- }
327
+
328
+ return res;
329
+ },
254
330
  }));
255
331
 
256
- let PostGIS_Funcs: FunctionSpec[] = ([
332
+ let PostGIS_Funcs: FunctionSpec[] = (
333
+ [
257
334
  {
258
335
  fname: "ST_DWithin",
259
336
  description: `:[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean; distance: number; }]
260
337
  -> Returns true if the geometries are within a given distance
261
338
  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).
262
339
  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.
263
- `
340
+ `,
264
341
  },
265
342
  {
266
343
  fname: "<->",
267
344
  description: `:[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }]
268
- -> 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.`
345
+ -> 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.`,
269
346
  },
270
- {
347
+ {
271
348
  fname: "ST_Distance",
272
349
  description: ` :[column_name, { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }]
273
350
  -> For geometry types returns the minimum 2D Cartesian (planar) distance between two geometries, in projected units (spatial ref units).
274
351
  -> 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.
275
352
  `,
276
- },{
353
+ },
354
+ {
277
355
  fname: "ST_DistanceSpheroid",
278
356
  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.
279
357
 
280
358
  `,
281
- },{
359
+ },
360
+ {
282
361
  fname: "ST_DistanceSphere",
283
362
  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.`,
363
+ },
364
+ ] as const
365
+ ).map(({ fname, description }) => ({
366
+ name: "$" + fname,
367
+ description,
368
+ type: "function" as const,
369
+ singleColArg: true,
370
+ numArgs: 1,
371
+ canBeUsedForFilter: fname === "ST_DWithin",
372
+ getFields: (args: any[]) => [args[0]],
373
+ getQuery: ({ allColumns, args: [columnName, arg2], tableAlias }) => {
374
+ const mErr = () => {
375
+ throw `${fname}: Expecting a second argument like: { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }`;
376
+ };
377
+
378
+ if (!isObject(arg2)) {
379
+ mErr();
380
+ }
381
+ const col = allColumns.find((c) => c.name === columnName);
382
+ if (!col) {
383
+ throw new Error("Col not found: " + columnName);
284
384
  }
285
- ] as const).map(({ fname, description }) => ({
286
- name: "$" + fname,
287
- description,
288
- type: "function" as const,
289
- singleColArg: true,
290
- numArgs: 1,
291
- canBeUsedForFilter: fname === "ST_DWithin",
292
- getFields: (args: any[]) => [args[0]],
293
- getQuery: ({ allColumns, args: [columnName, arg2], tableAlias }) => {
294
- const mErr = () => { throw `${fname}: Expecting a second argument like: { lat?: number; lng?: number; geojson?: object; srid?: number; use_spheroid?: boolean }` };
295
-
296
- if(!isObject(arg2)) {
297
- mErr();
298
- }
299
- const col = allColumns.find(c => c.name === columnName);
300
- if(!col) {
301
- throw new Error("Col not found: " + columnName)
302
- }
303
-
304
- const {
305
- lat, lng, srid = 4326,
306
- geojson, text, use_spheroid,
307
- distance, spheroid = 'SPHEROID["WGS 84", 6378137, 298.257223563]',
308
- unit,
309
- debug
310
- } = arg2;
311
- let geomQ = "", extraParams = "";
312
-
313
- if(typeof text === "string"){
314
- geomQ = `ST_GeomFromText(${asValue(text)})`;
315
- } else if([lat, lng].every(v => Number.isFinite(v))){
316
- geomQ = `ST_Point(${asValue(lng)}, ${asValue(lat)})`;
317
- } else if(isPlainObject(geojson)){
318
- geomQ = `ST_GeomFromGeoJSON(${geojson})`;
319
- } else mErr();
320
-
321
- if(Number.isFinite(srid)){
322
- geomQ = `ST_SetSRID(${geomQ}, ${asValue(srid)})`;
323
- }
324
-
325
- let colCast = "";
326
- const colIsGeog = col.udt_name === "geography";
327
- let geomQCast = colIsGeog? "::geography" : "::geometry";
328
385
 
329
- /**
330
- * float ST_Distance(geometry g1, geometry g2);
331
- * float ST_Distance(geography geog1, geography geog2, boolean use_spheroid=true);
332
- */
333
- if(fname === "ST_Distance"){
386
+ const {
387
+ lat,
388
+ lng,
389
+ srid = 4326,
390
+ geojson,
391
+ text,
392
+ use_spheroid,
393
+ distance,
394
+ spheroid = 'SPHEROID["WGS 84", 6378137, 298.257223563]',
395
+ unit,
396
+ debug,
397
+ } = arg2;
398
+ let geomQ = "",
399
+ extraParams = "";
400
+
401
+ if (typeof text === "string") {
402
+ geomQ = `ST_GeomFromText(${asValue(text)})`;
403
+ } else if ([lat, lng].every((v) => Number.isFinite(v))) {
404
+ geomQ = `ST_Point(${asValue(lng)}, ${asValue(lat)})`;
405
+ } else if (isPlainObject(geojson)) {
406
+ geomQ = `ST_GeomFromGeoJSON(${geojson})`;
407
+ } else mErr();
408
+
409
+ if (Number.isFinite(srid)) {
410
+ geomQ = `ST_SetSRID(${geomQ}, ${asValue(srid)})`;
411
+ }
334
412
 
335
- if(typeof use_spheroid === "boolean"){
336
- extraParams = ", " + asValue(use_spheroid);
337
- }
413
+ let colCast = "";
414
+ const colIsGeog = col.udt_name === "geography";
415
+ let geomQCast = colIsGeog ? "::geography" : "::geometry";
416
+
417
+ /**
418
+ * float ST_Distance(geometry g1, geometry g2);
419
+ * float ST_Distance(geography geog1, geography geog2, boolean use_spheroid=true);
420
+ */
421
+ if (fname === "ST_Distance") {
422
+ if (typeof use_spheroid === "boolean") {
423
+ extraParams = ", " + asValue(use_spheroid);
424
+ }
338
425
 
339
- colCast = (colIsGeog || use_spheroid)? "::geography" : "::geometry";
340
- geomQCast = (colIsGeog || use_spheroid)? "::geography" : "::geometry";
426
+ colCast = colIsGeog || use_spheroid ? "::geography" : "::geometry";
427
+ geomQCast = colIsGeog || use_spheroid ? "::geography" : "::geometry";
341
428
 
342
429
  /**
343
430
  * boolean ST_DWithin(geometry g1, geometry g2, double precision distance_of_srid);
344
431
  * boolean ST_DWithin(geography gg1, geography gg2, double precision distance_meters, boolean use_spheroid = true);
345
432
  */
346
- } else if(fname === "ST_DWithin"){
347
- colCast = colIsGeog? "::geography" : "::geometry";
348
- geomQCast = colIsGeog? "::geography" : "::geometry";
349
-
350
- if(typeof distance !== "number") {
351
- throw `ST_DWithin: distance param missing or not a number`;
352
- }
353
- const allowedUnits = ["m", "km"];
354
- if(unit && !allowedUnits.includes(unit)){
355
- throw `ST_DWithin: unit can only be one of: ${allowedUnits}`;
356
- }
357
- extraParams = ", " + asValue(distance * (unit === "km"? 1000 : 1));
433
+ } else if (fname === "ST_DWithin") {
434
+ colCast = colIsGeog ? "::geography" : "::geometry";
435
+ geomQCast = colIsGeog ? "::geography" : "::geometry";
358
436
 
437
+ if (typeof distance !== "number") {
438
+ throw `ST_DWithin: distance param missing or not a number`;
439
+ }
440
+ const allowedUnits = ["m", "km"];
441
+ if (unit && !allowedUnits.includes(unit)) {
442
+ throw `ST_DWithin: unit can only be one of: ${allowedUnits}`;
443
+ }
444
+ extraParams = ", " + asValue(distance * (unit === "km" ? 1000 : 1));
359
445
 
360
446
  /**
361
447
  * float ST_DistanceSpheroid(geometry geomlonlatA, geometry geomlonlatB, spheroid measurement_spheroid);
362
448
  */
363
- } else if(fname === "ST_DistanceSpheroid"){
364
- colCast = "::geometry";
365
- geomQCast = "::geometry";
366
- if(typeof spheroid !== "string") throw `ST_DistanceSpheroid: spheroid param must be string`;
367
- extraParams = `, ${asValue(spheroid)}`
368
-
369
-
449
+ } else if (fname === "ST_DistanceSpheroid") {
450
+ colCast = "::geometry";
451
+ geomQCast = "::geometry";
452
+ if (typeof spheroid !== "string")
453
+ throw `ST_DistanceSpheroid: spheroid param must be string`;
454
+ extraParams = `, ${asValue(spheroid)}`;
370
455
 
371
456
  /**
372
457
  * float ST_DistanceSphere(geometry geomlonlatA, geometry geomlonlatB);
373
458
  */
374
- } else if(fname === "ST_DistanceSphere"){
375
- colCast = "::geometry";
376
- geomQCast = "::geometry";
377
- extraParams = "";
459
+ } else if (fname === "ST_DistanceSphere") {
460
+ colCast = "::geometry";
461
+ geomQCast = "::geometry";
462
+ extraParams = "";
378
463
 
379
464
  /**
380
465
  * double precision <->( geometry A , geometry B );
381
466
  * double precision <->( geography A , geography B );
382
467
  */
383
- } else if(fname === "<->"){
384
- colCast = colIsGeog? "::geography" : "::geometry";
385
- geomQCast = colIsGeog? "::geography" : "::geometry";
386
- const q = pgp.as.format(`${asNameAlias(columnName, tableAlias)}${colCast} <-> ${geomQ}${geomQCast}`);
387
- if(debug) throw q;
388
- return q;
389
- }
468
+ } else if (fname === "<->") {
469
+ colCast = colIsGeog ? "::geography" : "::geometry";
470
+ geomQCast = colIsGeog ? "::geography" : "::geometry";
471
+ const q = pgp.as.format(
472
+ `${asNameAlias(columnName, tableAlias)}${colCast} <-> ${geomQ}${geomQCast}`,
473
+ );
474
+ if (debug) throw q;
475
+ return q;
476
+ }
390
477
 
391
- const query = pgp.as.format(`${fname}(${asNameAlias(columnName, tableAlias)}${colCast} , ${geomQ}${geomQCast} ${extraParams})`);
392
- if(debug) {
393
- throw query;
394
- }
395
- return query;
478
+ const query = pgp.as.format(
479
+ `${fname}(${asNameAlias(columnName, tableAlias)}${colCast} , ${geomQ}${geomQCast} ${extraParams})`,
480
+ );
481
+ if (debug) {
482
+ throw query;
396
483
  }
397
- }));
484
+ return query;
485
+ },
486
+ }));
398
487
 
399
- PostGIS_Funcs = PostGIS_Funcs.concat(
400
- [
401
- "ST_AsText", "ST_AsEWKT", "ST_AsEWKB", "ST_AsBinary", "ST_AsMVT", "ST_AsMVTGeom",
402
- "ST_AsGeoJSON", "ST_Simplify",
403
- "ST_SnapToGrid", "ST_Centroid",
404
- "st_aslatlontext",
405
- ]
406
- .map(fname => {
407
- const res: FunctionSpec = {
408
- name: "$" + fname,
409
- description: ` :[column_name, precision?] -> json GeoJSON output of a geometry column`,
410
- type: "function",
411
- singleColArg: true,
412
- numArgs: 1,
413
- getFields: (args: any[]) => [args[0]],
414
- getQuery: ({ args: [colName, ...otherArgs], tableAlias }) => {
415
- let secondArg = "";
416
- if(otherArgs.length) secondArg = ", " + otherArgs.map(arg => asValue(arg)).join(", ");
417
- const escTabelName = asNameAlias(colName, tableAlias) + "::geometry";
418
- const result = pgp.as.format(fname + "(" + escTabelName + secondArg + ( fname === "ST_AsGeoJSON"? ")::jsonb" : ")" ));
419
- if(["ST_Centroid", "ST_SnapToGrid", "ST_Simplify"].includes(fname)){
420
- const r = `ST_AsGeoJSON(${result})::jsonb`;
421
- return r;
422
- }
423
- return result;
488
+ PostGIS_Funcs = PostGIS_Funcs.concat(
489
+ [
490
+ "ST_AsText",
491
+ "ST_AsEWKT",
492
+ "ST_AsEWKB",
493
+ "ST_AsBinary",
494
+ "ST_AsMVT",
495
+ "ST_AsMVTGeom",
496
+ "ST_AsGeoJSON",
497
+ "ST_Simplify",
498
+ "ST_SnapToGrid",
499
+ "ST_Centroid",
500
+ "st_aslatlontext",
501
+ ].map((fname) => {
502
+ const res: FunctionSpec = {
503
+ name: "$" + fname,
504
+ description: ` :[column_name, precision?] -> json GeoJSON output of a geometry column`,
505
+ type: "function",
506
+ singleColArg: true,
507
+ numArgs: 1,
508
+ getFields: (args: any[]) => [args[0]],
509
+ getQuery: ({ args: [colName, ...otherArgs], tableAlias }) => {
510
+ let secondArg = "";
511
+ if (otherArgs.length)
512
+ secondArg = ", " + otherArgs.map((arg) => asValue(arg)).join(", ");
513
+ const escTabelName = asNameAlias(colName, tableAlias) + "::geometry";
514
+ const result = pgp.as.format(
515
+ fname +
516
+ "(" +
517
+ escTabelName +
518
+ secondArg +
519
+ (fname === "ST_AsGeoJSON" ? ")::jsonb" : ")"),
520
+ );
521
+ if (["ST_Centroid", "ST_SnapToGrid", "ST_Simplify"].includes(fname)) {
522
+ const r = `ST_AsGeoJSON(${result})::jsonb`;
523
+ return r;
424
524
  }
425
- }
426
- return res;
427
- }),
428
- );
429
-
525
+ return result;
526
+ },
527
+ };
528
+ return res;
529
+ }),
530
+ );
430
531
 
431
- PostGIS_Funcs = PostGIS_Funcs.concat(
432
- ["ST_Extent", "ST_3DExtent", "ST_XMin_Agg", "ST_XMax_Agg", "ST_YMin_Agg", "ST_YMax_Agg", "ST_ZMin_Agg", "ST_ZMax_Agg"]
433
- .map(fname => {
434
- const res: FunctionSpec = {
435
- name: "$" + fname,
436
- description: ` :[column_name] -> ST_Extent returns a bounding box that encloses a set of geometries.
532
+ PostGIS_Funcs = PostGIS_Funcs.concat(
533
+ [
534
+ "ST_Extent",
535
+ "ST_3DExtent",
536
+ "ST_XMin_Agg",
537
+ "ST_XMax_Agg",
538
+ "ST_YMin_Agg",
539
+ "ST_YMax_Agg",
540
+ "ST_ZMin_Agg",
541
+ "ST_ZMax_Agg",
542
+ ].map((fname) => {
543
+ const res: FunctionSpec = {
544
+ name: "$" + fname,
545
+ description: ` :[column_name] -> ST_Extent returns a bounding box that encloses a set of geometries.
437
546
  The ST_Extent function is an "aggregate" function in the terminology of SQL.
438
547
  That means that it operates on lists of data, in the same way the SUM() and AVG() functions do.`,
439
- type: "aggregation",
440
- singleColArg: true,
441
- numArgs: 1,
442
- getFields: (args: any[]) => [args[0]],
443
- getQuery: ({ args, tableAlias }) => {
444
- const escTabelName = asNameAlias(args[0], tableAlias) + "::geometry";
445
- if(fname.includes("Extent")){
446
- return `${fname}(${escTabelName})`;
447
- }
448
- return `${fname.endsWith("_Agg")? fname.slice(0, -4) : fname}(ST_Collect(${escTabelName}))`;
449
- }
450
- }
451
- return res;
452
- }),
453
- );
454
-
455
- PostGIS_Funcs = PostGIS_Funcs.concat(
456
- ["ST_Length", "ST_X", "ST_Y", "ST_Z"].map(fname => ({
457
- name: "$" + fname,
458
- type: "function",
548
+ type: "aggregation",
459
549
  singleColArg: true,
460
550
  numArgs: 1,
461
551
  getFields: (args: any[]) => [args[0]],
462
- getQuery: ({ allColumns, args, tableAlias }) => {
463
- const colName = args[0];
464
- const escapedColName = asNameAlias(colName, tableAlias);
465
- const col = allColumns.find(c => c.name === colName);
466
- if(!col) throw new Error("Col not found: " + colName)
467
-
468
- return `${fname}(${escapedColName})`;
469
- }
470
- }))
471
- );
472
-
552
+ getQuery: ({ args, tableAlias }) => {
553
+ const escTabelName = asNameAlias(args[0], tableAlias) + "::geometry";
554
+ if (fname.includes("Extent")) {
555
+ return `${fname}(${escTabelName})`;
556
+ }
557
+ return `${fname.endsWith("_Agg") ? fname.slice(0, -4) : fname}(ST_Collect(${escTabelName}))`;
558
+ },
559
+ };
560
+ return res;
561
+ }),
562
+ );
563
+
564
+ PostGIS_Funcs = PostGIS_Funcs.concat(
565
+ ["ST_Length", "ST_X", "ST_Y", "ST_Z"].map((fname) => ({
566
+ name: "$" + fname,
567
+ type: "function",
568
+ singleColArg: true,
569
+ numArgs: 1,
570
+ getFields: (args: any[]) => [args[0]],
571
+ getQuery: ({ allColumns, args, tableAlias }) => {
572
+ const colName = args[0];
573
+ const escapedColName = asNameAlias(colName, tableAlias);
574
+ const col = allColumns.find((c) => c.name === colName);
575
+ if (!col) throw new Error("Col not found: " + colName);
576
+
577
+ return `${fname}(${escapedColName})`;
578
+ },
579
+ })),
580
+ );
581
+
473
582
  /**
474
- * Each function expects a column at the very least
475
- */
583
+ * Each function expects a column at the very least
584
+ */
476
585
  export const FUNCTIONS: FunctionSpec[] = [
477
-
478
586
  // Hashing
479
587
  {
480
588
  name: "$md5_multi",
@@ -484,9 +592,18 @@ export const FUNCTIONS: FunctionSpec[] = [
484
592
  numArgs: MAX_COL_NUM,
485
593
  getFields: (args: any[]) => args,
486
594
  getQuery: ({ args, tableAlias }) => {
487
- const q = pgp.as.format("md5(" + args.map(fname => "COALESCE( " + asNameAlias(fname, tableAlias) + "::text, '' )" ).join(" || ") + ")");
488
- return q
489
- }
595
+ const q = pgp.as.format(
596
+ "md5(" +
597
+ args
598
+ .map(
599
+ (fname) =>
600
+ "COALESCE( " + asNameAlias(fname, tableAlias) + "::text, '' )",
601
+ )
602
+ .join(" || ") +
603
+ ")",
604
+ );
605
+ return q;
606
+ },
490
607
  },
491
608
  {
492
609
  name: "$md5_multi_agg",
@@ -496,9 +613,18 @@ export const FUNCTIONS: FunctionSpec[] = [
496
613
  numArgs: MAX_COL_NUM,
497
614
  getFields: (args: any[]) => args,
498
615
  getQuery: ({ args, tableAlias }) => {
499
- const q = pgp.as.format("md5(string_agg(" + args.map(fname => "COALESCE( " + asNameAlias(fname, tableAlias) + "::text, '' )" ).join(" || ") + ", ','))");
500
- return q
501
- }
616
+ const q = pgp.as.format(
617
+ "md5(string_agg(" +
618
+ args
619
+ .map(
620
+ (fname) =>
621
+ "COALESCE( " + asNameAlias(fname, tableAlias) + "::text, '' )",
622
+ )
623
+ .join(" || ") +
624
+ ", ','))",
625
+ );
626
+ return q;
627
+ },
502
628
  },
503
629
 
504
630
  {
@@ -509,9 +635,18 @@ export const FUNCTIONS: FunctionSpec[] = [
509
635
  numArgs: MAX_COL_NUM,
510
636
  getFields: (args: any[]) => args,
511
637
  getQuery: ({ args, tableAlias }) => {
512
- const q = pgp.as.format("encode(sha256((" + args.map(fname => "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )" ).join(" || ") + ")::text::bytea), 'hex')");
513
- return q
514
- }
638
+ const q = pgp.as.format(
639
+ "encode(sha256((" +
640
+ args
641
+ .map(
642
+ (fname) =>
643
+ "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )",
644
+ )
645
+ .join(" || ") +
646
+ ")::text::bytea), 'hex')",
647
+ );
648
+ return q;
649
+ },
515
650
  },
516
651
  {
517
652
  name: "$sha256_multi_agg",
@@ -521,9 +656,18 @@ export const FUNCTIONS: FunctionSpec[] = [
521
656
  numArgs: MAX_COL_NUM,
522
657
  getFields: (args: any[]) => args,
523
658
  getQuery: ({ args, tableAlias }) => {
524
- const q = pgp.as.format("encode(sha256(string_agg(" + args.map(fname => "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )" ).join(" || ") + ", ',')::text::bytea), 'hex')");
525
- return q
526
- }
659
+ const q = pgp.as.format(
660
+ "encode(sha256(string_agg(" +
661
+ args
662
+ .map(
663
+ (fname) =>
664
+ "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )",
665
+ )
666
+ .join(" || ") +
667
+ ", ',')::text::bytea), 'hex')",
668
+ );
669
+ return q;
670
+ },
527
671
  },
528
672
  {
529
673
  name: "$sha512_multi",
@@ -533,9 +677,18 @@ export const FUNCTIONS: FunctionSpec[] = [
533
677
  numArgs: MAX_COL_NUM,
534
678
  getFields: (args: any[]) => args,
535
679
  getQuery: ({ args, tableAlias }) => {
536
- const q = pgp.as.format("encode(sha512((" + args.map(fname => "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )" ).join(" || ") + ")::text::bytea), 'hex')");
537
- return q
538
- }
680
+ const q = pgp.as.format(
681
+ "encode(sha512((" +
682
+ args
683
+ .map(
684
+ (fname) =>
685
+ "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )",
686
+ )
687
+ .join(" || ") +
688
+ ")::text::bytea), 'hex')",
689
+ );
690
+ return q;
691
+ },
539
692
  },
540
693
  {
541
694
  name: "$sha512_multi_agg",
@@ -545,9 +698,18 @@ export const FUNCTIONS: FunctionSpec[] = [
545
698
  numArgs: MAX_COL_NUM,
546
699
  getFields: (args: any[]) => args,
547
700
  getQuery: ({ args, tableAlias }) => {
548
- const q = pgp.as.format("encode(sha512(string_agg(" + args.map(fname => "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )" ).join(" || ") + ", ',')::text::bytea), 'hex')");
549
- return q
550
- }
701
+ const q = pgp.as.format(
702
+ "encode(sha512(string_agg(" +
703
+ args
704
+ .map(
705
+ (fname) =>
706
+ "COALESCE( " + asNameAlias(fname, tableAlias) + ", '' )",
707
+ )
708
+ .join(" || ") +
709
+ ", ',')::text::bytea), 'hex')",
710
+ );
711
+ return q;
712
+ },
551
713
  },
552
714
 
553
715
  ...FTS_Funcs,
@@ -564,8 +726,11 @@ export const FUNCTIONS: FunctionSpec[] = [
564
726
  singleColArg: false,
565
727
  getFields: (args: any[]) => [args[0]],
566
728
  getQuery: ({ allowedFields, args, tableAlias }) => {
567
- return pgp.as.format("LEFT(" + asNameAlias(args[0], tableAlias) + ", $1)", [args[1]]);
568
- }
729
+ return pgp.as.format(
730
+ "LEFT(" + asNameAlias(args[0], tableAlias) + ", $1)",
731
+ [args[1]],
732
+ );
733
+ },
569
734
  },
570
735
  {
571
736
  name: "$unnest_words",
@@ -575,8 +740,12 @@ export const FUNCTIONS: FunctionSpec[] = [
575
740
  singleColArg: true,
576
741
  getFields: (args: any[]) => [args[0]],
577
742
  getQuery: ({ allowedFields, args, tableAlias }) => {
578
- return pgp.as.format("unnest(string_to_array(" + asNameAlias(args[0], tableAlias) + "::TEXT , ' '))");//, [args[1]]
579
- }
743
+ return pgp.as.format(
744
+ "unnest(string_to_array(" +
745
+ asNameAlias(args[0], tableAlias) +
746
+ "::TEXT , ' '))",
747
+ ); //, [args[1]]
748
+ },
580
749
  },
581
750
  {
582
751
  name: "$right",
@@ -586,8 +755,11 @@ export const FUNCTIONS: FunctionSpec[] = [
586
755
  singleColArg: false,
587
756
  getFields: (args: any[]) => [args[0]],
588
757
  getQuery: ({ allowedFields, args, tableAlias }) => {
589
- return pgp.as.format("RIGHT(" + asNameAlias(args[0], tableAlias) + ", $1)", [args[1]]);
590
- }
758
+ return pgp.as.format(
759
+ "RIGHT(" + asNameAlias(args[0], tableAlias) + ", $1)",
760
+ [args[1]],
761
+ );
762
+ },
591
763
  },
592
764
 
593
765
  {
@@ -598,11 +770,17 @@ export const FUNCTIONS: FunctionSpec[] = [
598
770
  numArgs: 2,
599
771
  getFields: (args: any[]) => [args[0]],
600
772
  getQuery: ({ allowedFields, args, tableAlias }) => {
601
- if(args.length === 3){
602
- return pgp.as.format("to_char(" + asNameAlias(args[0], tableAlias) + ", $2, $3)", [args[0], args[1], args[2]]);
773
+ if (args.length === 3) {
774
+ return pgp.as.format(
775
+ "to_char(" + asNameAlias(args[0], tableAlias) + ", $2, $3)",
776
+ [args[0], args[1], args[2]],
777
+ );
603
778
  }
604
- return pgp.as.format("to_char(" + asNameAlias(args[0], tableAlias) + ", $2)", [args[0], args[1]]);
605
- }
779
+ return pgp.as.format(
780
+ "to_char(" + asNameAlias(args[0], tableAlias) + ", $2)",
781
+ [args[0], args[1]],
782
+ );
783
+ },
606
784
  },
607
785
 
608
786
  /**
@@ -621,88 +799,101 @@ export const FUNCTIONS: FunctionSpec[] = [
621
799
  "year",
622
800
  "decade",
623
801
  "century",
624
- "millennium"
625
- ].map(k => ({ val: 0, unit: k }))
626
- .concat([
627
- { val: 6, unit: 'month' },
628
- { val: 4, unit: 'month' },
629
- { val: 2, unit: 'month' },
630
- { val: 8, unit: 'hour' },
631
- { val: 4, unit: 'hour' },
632
- { val: 2, unit: 'hour' },
633
- { val: 30, unit: 'minute' },
634
- { val: 15, unit: 'minute' },
635
- { val: 6, unit: 'minute' },
636
- { val: 5, unit: 'minute' },
637
- { val: 4, unit: 'minute' },
638
- { val: 3, unit: 'minute' },
639
- { val: 2, unit: 'minute' },
640
- { val: 30, unit: 'second' },
641
- { val: 15, unit: 'second' },
642
- { val: 10, unit: 'second' },
643
- { val: 8, unit: 'second' },
644
- { val: 6, unit: 'second' },
645
- { val: 5, unit: 'second' },
646
- { val: 4, unit: 'second' },
647
- { val: 3, unit: 'second' },
648
- { val: 2, unit: 'second' },
649
-
650
- { val: 500, unit: 'millisecond' },
651
- { val: 250, unit: 'millisecond' },
652
- { val: 100, unit: 'millisecond' },
653
- { val: 50, unit: 'millisecond' },
654
- { val: 25, unit: 'millisecond' },
655
- { val: 10, unit: 'millisecond' },
656
- { val: 5, unit: 'millisecond' },
657
- { val: 2, unit: 'millisecond' },
658
- ]).map(({ val, unit }) => ({
659
- name: "$date_trunc_" + (val || "") + unit,
660
- type: "function",
661
- description: ` :[column_name, opts?: { timeZone: true | 'TZ Name' }] -> round down timestamp to closest ${val || ""} ${unit} `,
662
- singleColArg: true,
663
- numArgs: 2,
664
- getFields: (args: any[]) => [args[0]],
665
- getQuery: ({ allColumns, args, tableAlias }) => {
666
- /** Timestamp added to ensure filters work correctly (psql will loose the string value timezone when comparing to a non tz column) */
667
- const col = parseUnix(args[0], tableAlias, allColumns, args[1]);
668
- if(!val) return `date_trunc(${asValue(unit)}, ${col})`;
669
- const PreviousUnit = {
670
- year: "decade",
671
- month: "year",
672
- hour: "day",
673
- minute: "hour",
674
- second: "minute",
675
- millisecond: "second",
676
- microsecond: "millisecond",
677
- };
678
-
679
- const prevUnit = PreviousUnit[unit as "month"];
680
- if(!prevUnit){
681
- throw "Not supported. prevUnit not found";
682
- }
802
+ "millennium",
803
+ ]
804
+ .map((k) => ({ val: 0, unit: k }))
805
+ .concat([
806
+ { val: 6, unit: "month" },
807
+ { val: 4, unit: "month" },
808
+ { val: 2, unit: "month" },
809
+ { val: 8, unit: "hour" },
810
+ { val: 4, unit: "hour" },
811
+ { val: 2, unit: "hour" },
812
+ { val: 30, unit: "minute" },
813
+ { val: 15, unit: "minute" },
814
+ { val: 6, unit: "minute" },
815
+ { val: 5, unit: "minute" },
816
+ { val: 4, unit: "minute" },
817
+ { val: 3, unit: "minute" },
818
+ { val: 2, unit: "minute" },
819
+ { val: 30, unit: "second" },
820
+ { val: 15, unit: "second" },
821
+ { val: 10, unit: "second" },
822
+ { val: 8, unit: "second" },
823
+ { val: 6, unit: "second" },
824
+ { val: 5, unit: "second" },
825
+ { val: 4, unit: "second" },
826
+ { val: 3, unit: "second" },
827
+ { val: 2, unit: "second" },
828
+
829
+ { val: 500, unit: "millisecond" },
830
+ { val: 250, unit: "millisecond" },
831
+ { val: 100, unit: "millisecond" },
832
+ { val: 50, unit: "millisecond" },
833
+ { val: 25, unit: "millisecond" },
834
+ { val: 10, unit: "millisecond" },
835
+ { val: 5, unit: "millisecond" },
836
+ { val: 2, unit: "millisecond" },
837
+ ])
838
+ .map(
839
+ ({ val, unit }) =>
840
+ ({
841
+ name: "$date_trunc_" + (val || "") + unit,
842
+ type: "function",
843
+ description: ` :[column_name, opts?: { timeZone: true | 'TZ Name' }] -> round down timestamp to closest ${val || ""} ${unit} `,
844
+ singleColArg: true,
845
+ numArgs: 2,
846
+ getFields: (args: any[]) => [args[0]],
847
+ getQuery: ({ allColumns, args, tableAlias }) => {
848
+ /** Timestamp added to ensure filters work correctly (psql will loose the string value timezone when comparing to a non tz column) */
849
+ const col = parseUnix(args[0], tableAlias, allColumns, args[1]);
850
+ if (!val) return `date_trunc(${asValue(unit)}, ${col})`;
851
+ const PreviousUnit = {
852
+ year: "decade",
853
+ month: "year",
854
+ hour: "day",
855
+ minute: "hour",
856
+ second: "minute",
857
+ millisecond: "second",
858
+ microsecond: "millisecond",
859
+ };
860
+
861
+ const prevUnit = PreviousUnit[unit as "month"];
862
+ if (!prevUnit) {
863
+ throw "Not supported. prevUnit not found";
864
+ }
683
865
 
684
- let extractedUnit = `date_part(${asValue(unit, "::text")}, ${col})::int`;
685
- if(unit === "microsecond" || unit === "millisecond"){
686
- extractedUnit = `(${extractedUnit} - 1000 * floor(${extractedUnit}/1000)::int)`
687
- }
688
- const res = `(date_trunc(${asValue(prevUnit)}, ${col}) + floor(${extractedUnit} / ${val}) * interval ${asValue(val + " " + unit)})`;
689
- // console.log(res);
690
- return res;
691
- }
692
- } as FunctionSpec)),
866
+ let extractedUnit = `date_part(${asValue(unit, "::text")}, ${col})::int`;
867
+ if (unit === "microsecond" || unit === "millisecond") {
868
+ extractedUnit = `(${extractedUnit} - 1000 * floor(${extractedUnit}/1000)::int)`;
869
+ }
870
+ const res = `(date_trunc(${asValue(prevUnit)}, ${col}) + floor(${extractedUnit} / ${val}) * interval ${asValue(val + " " + unit)})`;
871
+ // console.log(res);
872
+ return res;
873
+ },
874
+ }) as FunctionSpec,
875
+ ),
693
876
 
694
877
  /* Date funcs date_part */
695
- ...["date_trunc", "date_part"].map(funcName => ({
696
- name: "$" + funcName,
697
- type: "function",
698
- numArgs: 3,
699
- description: ` :[unit<string>, column_name, opts?: { timeZone: true | string }] -> ` + (funcName === "date_trunc"? ` round down timestamp to closest unit value. ` : ` extract date unit as float8. ` ) + ` E.g. ['hour', col] `,
700
- singleColArg: false,
701
- getFields: (args: any[]) => [args[1]],
702
- getQuery: ({ allColumns, args, tableAlias }) => {
703
- return `${funcName}(${asValue(args[0])}, ${parseUnix(args[1], tableAlias, allColumns, args[2])})`;
704
- }
705
- } as FunctionSpec)),
878
+ ...["date_trunc", "date_part"].map(
879
+ (funcName) =>
880
+ ({
881
+ name: "$" + funcName,
882
+ type: "function",
883
+ numArgs: 3,
884
+ description:
885
+ ` :[unit<string>, column_name, opts?: { timeZone: true | string }] -> ` +
886
+ (funcName === "date_trunc"
887
+ ? ` round down timestamp to closest unit value. `
888
+ : ` extract date unit as float8. `) +
889
+ ` E.g. ['hour', col] `,
890
+ singleColArg: false,
891
+ getFields: (args: any[]) => [args[1]],
892
+ getQuery: ({ allColumns, args, tableAlias }) => {
893
+ return `${funcName}(${asValue(args[0])}, ${parseUnix(args[1], tableAlias, allColumns, args[2])})`;
894
+ },
895
+ }) as FunctionSpec,
896
+ ),
706
897
 
707
898
  /* Handy date funcs */
708
899
  ...[
@@ -740,136 +931,186 @@ export const FUNCTIONS: FunctionSpec[] = [
740
931
  ["yyyy", "yyyy"],
741
932
  ["yy", "yy"],
742
933
  ["yr", "yy"],
743
- ].map(([funcName, txt]) => ({
744
- name: "$" + funcName,
745
- type: "function",
746
- description: ` :[column_name, opts?: { timeZone: true | string }] -> get timestamp formated as ` + txt,
747
- singleColArg: true,
748
- numArgs: 1,
749
- getFields: (args: any[]) => [args[0]],
750
- getQuery: ({ allColumns, args, tableAlias }) => {
751
- return pgp.as.format("trim(to_char(" + parseUnix(args[0], tableAlias, allColumns, args[1]) + ", $2))", [args[0], txt]);
752
- }
753
- } as FunctionSpec)),
934
+ ].map(
935
+ ([funcName, txt]) =>
936
+ ({
937
+ name: "$" + funcName,
938
+ type: "function",
939
+ description:
940
+ ` :[column_name, opts?: { timeZone: true | string }] -> get timestamp formated as ` +
941
+ txt,
942
+ singleColArg: true,
943
+ numArgs: 1,
944
+ getFields: (args: any[]) => [args[0]],
945
+ getQuery: ({ allColumns, args, tableAlias }) => {
946
+ return pgp.as.format(
947
+ "trim(to_char(" +
948
+ parseUnix(args[0], tableAlias, allColumns, args[1]) +
949
+ ", $2))",
950
+ [args[0], txt],
951
+ );
952
+ },
953
+ }) as FunctionSpec,
954
+ ),
754
955
 
755
956
  /* Basic 1 arg col funcs */
756
957
  ...[
757
- ...["TEXT"].flatMap(cast => [
758
- "upper", "lower", "length", "reverse", "trim", "initcap"
759
- ].map(funcName => ({ cast, funcName }))),
760
- ...[""].flatMap(cast => [
761
- "round", "ceil", "floor", "sign", "md5"
762
- ].map(funcName => ({ cast, funcName }))),
763
- ].map(({ funcName, cast }) => ({
764
- name: "$" + funcName,
765
- type: "function",
766
- numArgs: 1,
767
- singleColArg: true,
768
- getFields: (args: any[]) => [args[0]],
769
- getQuery: ({ args, tableAlias }) => {
770
- return `${funcName}(${asNameAlias(args[0], tableAlias)}${cast? `::${cast}`: ""})`;
771
- }
772
- } as FunctionSpec)),
958
+ ...["TEXT"].flatMap((cast) =>
959
+ ["upper", "lower", "length", "reverse", "trim", "initcap"].map(
960
+ (funcName) => ({ cast, funcName }),
961
+ ),
962
+ ),
963
+ ...[""].flatMap((cast) =>
964
+ ["round", "ceil", "floor", "sign", "md5"].map((funcName) => ({
965
+ cast,
966
+ funcName,
967
+ })),
968
+ ),
969
+ ].map(
970
+ ({ funcName, cast }) =>
971
+ ({
972
+ name: "$" + funcName,
973
+ type: "function",
974
+ numArgs: 1,
975
+ singleColArg: true,
976
+ getFields: (args: any[]) => [args[0]],
977
+ getQuery: ({ args, tableAlias }) => {
978
+ return `${funcName}(${asNameAlias(args[0], tableAlias)}${cast ? `::${cast}` : ""})`;
979
+ },
980
+ }) as FunctionSpec,
981
+ ),
773
982
 
774
983
  /**
775
- * Interval funcs
984
+ * Interval funcs
776
985
  * (col1, col2?, trunc )
777
986
  * */
778
- ...["age", "ageNow", "difference"].map(funcName => ({
779
- name: "$" + funcName,
780
- type: "function",
781
- numArgs: 2,
782
- singleColArg: true,
783
- getFields: (args: any[]) => args.slice(0, 2).filter(a => typeof a === "string"), // Filtered because the second arg is optional
784
- getQuery: ({ allowedFields, args, tableAlias, allColumns }) => {
785
- const validColCount = args.slice(0, 2).filter(a => typeof a === "string").length;
786
- const trunc = args[2];
787
- const allowedTruncs = ["second", "minute", "hour", "day", "month", "year"];
788
- if(trunc && !allowedTruncs.includes(trunc)) throw new Error("Incorrect trunc provided. Allowed values: " + allowedTruncs)
789
- if(funcName === "difference" && validColCount !== 2) throw new Error("Must have two column names")
790
- if(![1,2].includes(validColCount)) throw new Error("Must have one or two column names")
791
- const [leftField, rightField] = args as [string, string];
792
- const tzOpts = args[2];
793
- const leftQ = parseUnix(leftField, tableAlias, allColumns, tzOpts);
794
- let rightQ = rightField? parseUnix(rightField, tableAlias, allColumns, tzOpts) : "";
795
- let query = "";
796
- if(funcName === "ageNow" && validColCount === 1){
797
- query = `age(now(), ${leftQ})`;
798
- } else if(funcName === "age" || funcName === "ageNow"){
799
- if(rightQ) rightQ = ", " + rightQ;
800
- query = `age(${leftQ} ${rightQ})`;
801
- } else {
802
- query = `${leftQ} - ${rightQ}`;
803
- }
804
- return trunc? `date_trunc(${asValue(trunc)}, ${query})` : query;
805
- }
806
- } as FunctionSpec)),
987
+ ...["age", "ageNow", "difference"].map(
988
+ (funcName) =>
989
+ ({
990
+ name: "$" + funcName,
991
+ type: "function",
992
+ numArgs: 2,
993
+ singleColArg: true,
994
+ getFields: (args: any[]) =>
995
+ args.slice(0, 2).filter((a) => typeof a === "string"), // Filtered because the second arg is optional
996
+ getQuery: ({ allowedFields, args, tableAlias, allColumns }) => {
997
+ const validColCount = args
998
+ .slice(0, 2)
999
+ .filter((a) => typeof a === "string").length;
1000
+ const trunc = args[2];
1001
+ const allowedTruncs = [
1002
+ "second",
1003
+ "minute",
1004
+ "hour",
1005
+ "day",
1006
+ "month",
1007
+ "year",
1008
+ ];
1009
+ if (trunc && !allowedTruncs.includes(trunc))
1010
+ throw new Error(
1011
+ "Incorrect trunc provided. Allowed values: " + allowedTruncs,
1012
+ );
1013
+ if (funcName === "difference" && validColCount !== 2)
1014
+ throw new Error("Must have two column names");
1015
+ if (![1, 2].includes(validColCount))
1016
+ throw new Error("Must have one or two column names");
1017
+ const [leftField, rightField] = args as [string, string];
1018
+ const tzOpts = args[2];
1019
+ const leftQ = parseUnix(leftField, tableAlias, allColumns, tzOpts);
1020
+ let rightQ = rightField
1021
+ ? parseUnix(rightField, tableAlias, allColumns, tzOpts)
1022
+ : "";
1023
+ let query = "";
1024
+ if (funcName === "ageNow" && validColCount === 1) {
1025
+ query = `age(now(), ${leftQ})`;
1026
+ } else if (funcName === "age" || funcName === "ageNow") {
1027
+ if (rightQ) rightQ = ", " + rightQ;
1028
+ query = `age(${leftQ} ${rightQ})`;
1029
+ } else {
1030
+ query = `${leftQ} - ${rightQ}`;
1031
+ }
1032
+ return trunc ? `date_trunc(${asValue(trunc)}, ${query})` : query;
1033
+ },
1034
+ }) as FunctionSpec,
1035
+ ),
807
1036
 
808
1037
  /* pgcrypto funcs */
809
- ...["crypt"].map(funcName => ({
810
- name: "$" + funcName,
811
- type: "function",
812
- numArgs: 1,
813
- singleColArg: false,
814
- getFields: (args: any[]) => [args[1]],
815
- getQuery: ({ allowedFields, args, tableAlias }) => {
816
- const value = asValue(args[0]) + "",
817
- seedColumnName = asNameAlias(args[1], tableAlias);
818
-
819
- return `crypt(${value}, ${seedColumnName}::text)`;
820
- }
821
- } as FunctionSpec)),
1038
+ ...["crypt"].map(
1039
+ (funcName) =>
1040
+ ({
1041
+ name: "$" + funcName,
1042
+ type: "function",
1043
+ numArgs: 1,
1044
+ singleColArg: false,
1045
+ getFields: (args: any[]) => [args[1]],
1046
+ getQuery: ({ allowedFields, args, tableAlias }) => {
1047
+ const value = asValue(args[0]) + "",
1048
+ seedColumnName = asNameAlias(args[1], tableAlias);
1049
+
1050
+ return `crypt(${value}, ${seedColumnName}::text)`;
1051
+ },
1052
+ }) as FunctionSpec,
1053
+ ),
822
1054
 
823
1055
  /* Text col and value funcs */
824
- ...["position", "position_lower"].map(funcName => ({
825
- name: "$" + funcName,
826
- type: "function",
827
- numArgs: 1,
828
- singleColArg: false,
829
- getFields: (args: any[]) => [args[1]],
830
- getQuery: ({ allowedFields, args, tableAlias }) => {
831
- let a1 = asValue(args[0]),
832
- a2 = asNameAlias(args[1], tableAlias);
833
- if(funcName === "position_lower"){
834
- a1 = `LOWER(${a1}::text)`;
835
- a2 = `LOWER(${a2}::text)`;
836
- }
837
- return `position( ${a1} IN ${a2} )`;
838
- }
839
- } as FunctionSpec)),
840
- ...["template_string"].map(funcName => ({
841
- name: "$" + funcName,
842
- type: "function",
843
- numArgs: 1,
844
- minCols: 0,
845
- singleColArg: false,
846
- getFields: (args: any[]) => [] as string[], // Fields not validated because we'll use the allowed ones anyway
847
- getQuery: ({ allowedFields, args, tableAlias }) => {
848
- if(typeof args[0] !== "string") throw "First argument must be a string. E.g.: '{col1} ..text {col2} ...' ";
849
-
850
- const rawValue = args[0];
851
- let finalValue = rawValue;
852
- const usedColumns = allowedFields.filter(fName => rawValue.includes(`{${fName}}`));
853
- usedColumns.forEach((colName, idx) => {
854
- finalValue = finalValue.split(`{${colName}}`).join(`%${idx + 1}$s`)
855
- });
856
- finalValue = asValue(finalValue);
857
-
858
- if(usedColumns.length){
859
- return `format(${finalValue}, ${usedColumns.map(c => `${asNameAlias(c, tableAlias)}::TEXT`).join(", ")})`;
860
- }
861
-
862
- return `format(${finalValue})`;
863
- }
864
- } as FunctionSpec)),
1056
+ ...["position", "position_lower"].map(
1057
+ (funcName) =>
1058
+ ({
1059
+ name: "$" + funcName,
1060
+ type: "function",
1061
+ numArgs: 1,
1062
+ singleColArg: false,
1063
+ getFields: (args: any[]) => [args[1]],
1064
+ getQuery: ({ allowedFields, args, tableAlias }) => {
1065
+ let a1 = asValue(args[0]),
1066
+ a2 = asNameAlias(args[1], tableAlias);
1067
+ if (funcName === "position_lower") {
1068
+ a1 = `LOWER(${a1}::text)`;
1069
+ a2 = `LOWER(${a2}::text)`;
1070
+ }
1071
+ return `position( ${a1} IN ${a2} )`;
1072
+ },
1073
+ }) as FunctionSpec,
1074
+ ),
1075
+ ...["template_string"].map(
1076
+ (funcName) =>
1077
+ ({
1078
+ name: "$" + funcName,
1079
+ type: "function",
1080
+ numArgs: 1,
1081
+ minCols: 0,
1082
+ singleColArg: false,
1083
+ getFields: (args: any[]) => [] as string[], // Fields not validated because we'll use the allowed ones anyway
1084
+ getQuery: ({ allowedFields, args, tableAlias }) => {
1085
+ if (typeof args[0] !== "string")
1086
+ throw "First argument must be a string. E.g.: '{col1} ..text {col2} ...' ";
1087
+
1088
+ const rawValue = args[0];
1089
+ let finalValue = rawValue;
1090
+ const usedColumns = allowedFields.filter((fName) =>
1091
+ rawValue.includes(`{${fName}}`),
1092
+ );
1093
+ usedColumns.forEach((colName, idx) => {
1094
+ finalValue = finalValue.split(`{${colName}}`).join(`%${idx + 1}$s`);
1095
+ });
1096
+ finalValue = asValue(finalValue);
1097
+
1098
+ if (usedColumns.length) {
1099
+ return `format(${finalValue}, ${usedColumns.map((c) => `${asNameAlias(c, tableAlias)}::TEXT`).join(", ")})`;
1100
+ }
1101
+
1102
+ return `format(${finalValue})`;
1103
+ },
1104
+ }) as FunctionSpec,
1105
+ ),
865
1106
 
866
1107
  /** Custom highlight -> myterm => ['some text and', ['myterm'], ' and some other text']
867
- * (fields: "*" | string[], term: string, { edgeTruncate: number = -1; noFields: boolean = false }) => string | (string | [string])[]
1108
+ * (fields: "*" | string[], term: string, { edgeTruncate: number = -1; noFields: boolean = false }) => string | (string | [string])[]
868
1109
  * edgeTruncate = maximum extra characters left and right of matches
869
1110
  * noFields = exclude field names in search
870
- * */
1111
+ * */
871
1112
  {
872
- name: "$term_highlight", /* */
1113
+ name: "$term_highlight" /* */,
873
1114
  description: ` :[column_names<string[] | "*">, search_term<string>, opts?<{ returnIndex?: number; edgeTruncate?: number; noFields?: boolean }>] -> get case-insensitive text match highlight`,
874
1115
  type: "function",
875
1116
  numArgs: 1,
@@ -877,37 +1118,56 @@ export const FUNCTIONS: FunctionSpec[] = [
877
1118
  canBeUsedForFilter: true,
878
1119
  getFields: (args: any[]) => args[0],
879
1120
  getQuery: ({ allowedFields, args, tableAlias, allColumns }) => {
880
-
881
1121
  const cols = parseFieldFilter(args[0], false, allowedFields);
882
1122
  let term = args[1];
883
1123
  const rawTerm = args[1];
884
- const { edgeTruncate, noFields = false, returnType, matchCase = false } = args[2] || {};
885
- if(!isEmpty(args[2])){
1124
+ const {
1125
+ edgeTruncate,
1126
+ noFields = false,
1127
+ returnType,
1128
+ matchCase = false,
1129
+ } = args[2] || {};
1130
+ if (!isEmpty(args[2])) {
886
1131
  const keys = Object.keys(args[2]);
887
- const validKeys = ["edgeTruncate", "noFields", "returnType", "matchCase"];
888
- const bad_keys = keys.filter(k => !validKeys.includes(k));
889
- if(bad_keys.length) throw "Invalid options provided for $term_highlight. Expecting one of: " + validKeys.join(", ");
1132
+ const validKeys = [
1133
+ "edgeTruncate",
1134
+ "noFields",
1135
+ "returnType",
1136
+ "matchCase",
1137
+ ];
1138
+ const bad_keys = keys.filter((k) => !validKeys.includes(k));
1139
+ if (bad_keys.length)
1140
+ throw (
1141
+ "Invalid options provided for $term_highlight. Expecting one of: " +
1142
+ validKeys.join(", ")
1143
+ );
890
1144
  }
891
- if(!cols.length) throw "Cols are empty/invalid";
892
- if(typeof term !== "string") throw "Non string term provided: " + term;
893
- if(edgeTruncate !== undefined && (!Number.isInteger(edgeTruncate) || edgeTruncate < -1)) throw "Invalid edgeTruncate. expecting a positive integer";
894
- if(typeof noFields !== "boolean") throw "Invalid noFields. expecting boolean";
1145
+ if (!cols.length) throw "Cols are empty/invalid";
1146
+ if (typeof term !== "string") throw "Non string term provided: " + term;
1147
+ if (
1148
+ edgeTruncate !== undefined &&
1149
+ (!Number.isInteger(edgeTruncate) || edgeTruncate < -1)
1150
+ )
1151
+ throw "Invalid edgeTruncate. expecting a positive integer";
1152
+ if (typeof noFields !== "boolean")
1153
+ throw "Invalid noFields. expecting boolean";
895
1154
  const RETURN_TYPES = ["index", "boolean", "object"];
896
- if(returnType && !RETURN_TYPES.includes(returnType)){
897
- throw `returnType can only be one of: ${RETURN_TYPES}`
1155
+ if (returnType && !RETURN_TYPES.includes(returnType)) {
1156
+ throw `returnType can only be one of: ${RETURN_TYPES}`;
898
1157
  }
899
1158
 
900
1159
  const makeTextMatcherArray = (rawText: string, _term: string) => {
901
- let matchText = rawText, term = _term;
902
- if(!matchCase) {
903
- matchText = `LOWER(${rawText})`
904
- term = `LOWER(${term})`
1160
+ let matchText = rawText,
1161
+ term = _term;
1162
+ if (!matchCase) {
1163
+ matchText = `LOWER(${rawText})`;
1164
+ term = `LOWER(${term})`;
905
1165
  }
906
1166
  let leftStr = `substr(${rawText}, 1, position(${term} IN ${matchText}) - 1 )`,
907
1167
  rightStr = `substr(${rawText}, position(${term} IN ${matchText}) + length(${term}) )`;
908
- if(edgeTruncate){
1168
+ if (edgeTruncate) {
909
1169
  leftStr = `RIGHT(${leftStr}, ${asValue(edgeTruncate)})`;
910
- rightStr = `LEFT(${rightStr}, ${asValue(edgeTruncate)})`
1170
+ rightStr = `LEFT(${rightStr}, ${asValue(edgeTruncate)})`;
911
1171
  }
912
1172
  return `
913
1173
  CASE WHEN position(${term} IN ${matchText}) > 0 AND ${term} <> ''
@@ -922,87 +1182,94 @@ export const FUNCTIONS: FunctionSpec[] = [
922
1182
  array_to_json(ARRAY[(${rawText})::TEXT])
923
1183
  END
924
1184
  `;
925
- }
1185
+ };
926
1186
 
927
- const colRaw = "( " + cols.map(c =>`${noFields? "" : (asValue(c + ": ") + " || ")} COALESCE(${asNameAlias(c, tableAlias)}::TEXT, '')`).join(" || ', ' || ") + " )";
1187
+ const colRaw =
1188
+ "( " +
1189
+ cols
1190
+ .map(
1191
+ (c) =>
1192
+ `${noFields ? "" : asValue(c + ": ") + " || "} COALESCE(${asNameAlias(c, tableAlias)}::TEXT, '')`,
1193
+ )
1194
+ .join(" || ', ' || ") +
1195
+ " )";
928
1196
  let col = colRaw;
929
1197
  term = asValue(term);
930
- if(!matchCase) {
1198
+ if (!matchCase) {
931
1199
  col = "LOWER" + col;
932
- term = `LOWER(${term})`
1200
+ term = `LOWER(${term})`;
933
1201
  }
934
1202
 
935
1203
  let leftStr = `substr(${colRaw}, 1, position(${term} IN ${col}) - 1 )`,
936
1204
  rightStr = `substr(${colRaw}, position(${term} IN ${col}) + length(${term}) )`;
937
- if(edgeTruncate){
1205
+ if (edgeTruncate) {
938
1206
  leftStr = `RIGHT(${leftStr}, ${asValue(edgeTruncate)})`;
939
- rightStr = `LEFT(${rightStr}, ${asValue(edgeTruncate)})`
1207
+ rightStr = `LEFT(${rightStr}, ${asValue(edgeTruncate)})`;
940
1208
  }
941
-
1209
+
942
1210
  // console.log(col);
943
- let res = ""
944
- if(returnType === "index"){
1211
+ let res = "";
1212
+ if (returnType === "index") {
945
1213
  res = `CASE WHEN position(${term} IN ${col}) > 0 THEN position(${term} IN ${col}) - 1 ELSE -1 END`;
946
1214
 
947
- // } else if(returnType === "boolean"){
948
- // res = `CASE WHEN position(${term} IN ${col}) > 0 THEN TRUE ELSE FALSE END`;
949
-
950
- } else if(returnType === "object" || returnType === "boolean"){
951
- const hasChars = Boolean(rawTerm && /[a-z]/i.test(rawTerm));
952
- const validCols = cols.map(c => {
953
- const colInfo = allColumns.find(ac => ac.name === c);
1215
+ // } else if(returnType === "boolean"){
1216
+ // res = `CASE WHEN position(${term} IN ${col}) > 0 THEN TRUE ELSE FALSE END`;
1217
+ } else if (returnType === "object" || returnType === "boolean") {
1218
+ const hasChars = Boolean(rawTerm && /[a-z]/i.test(rawTerm));
1219
+ const validCols = cols
1220
+ .map((c) => {
1221
+ const colInfo = allColumns.find((ac) => ac.name === c);
954
1222
  return {
955
1223
  key: c,
956
- colInfo
957
- }
1224
+ colInfo,
1225
+ };
958
1226
  })
959
- .filter(c => c.colInfo && c.colInfo.udt_name !== "bytea")
960
-
961
- const _cols = validCols.filter(c =>
962
- /** Exclude numeric columns when the search tern contains a character */
963
- !hasChars ||
964
- postgresToTsType(c.colInfo!.udt_name) !== "number"
1227
+ .filter((c) => c.colInfo && c.colInfo.udt_name !== "bytea");
1228
+
1229
+ const _cols = validCols.filter(
1230
+ (c) =>
1231
+ /** Exclude numeric columns when the search tern contains a character */
1232
+ !hasChars || postgresToTsType(c.colInfo!.udt_name) !== "number",
965
1233
  );
966
1234
 
967
1235
  /** This will break GROUP BY (non-integer constant in GROUP BY) */
968
- if(!_cols.length){
969
- if(validCols.length && hasChars) 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) `
970
- return (returnType === "boolean")? "FALSE" : "NULL"
1236
+ if (!_cols.length) {
1237
+ if (validCols.length && hasChars)
1238
+ 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) `;
1239
+ return returnType === "boolean" ? "FALSE" : "NULL";
971
1240
  }
972
1241
  res = `CASE
973
1242
  ${_cols
974
- .map(c => {
975
- const colNameEscaped = asNameAlias(c.key, tableAlias)
976
- let colSelect = `${colNameEscaped}::TEXT`;
977
- const isTstamp = c.colInfo?.udt_name.startsWith("timestamp");
978
- if(isTstamp || c.colInfo?.udt_name === "date"){
979
- colSelect = `( CASE WHEN ${colNameEscaped} IS NULL THEN ''
1243
+ .map((c) => {
1244
+ const colNameEscaped = asNameAlias(c.key, tableAlias);
1245
+ let colSelect = `${colNameEscaped}::TEXT`;
1246
+ const isTstamp = c.colInfo?.udt_name.startsWith("timestamp");
1247
+ if (isTstamp || c.colInfo?.udt_name === "date") {
1248
+ colSelect = `( CASE WHEN ${colNameEscaped} IS NULL THEN ''
980
1249
  ELSE concat_ws(' ',
981
1250
  trim(to_char(${colNameEscaped}, 'YYYY-MM-DD HH24:MI:SS')),
982
1251
  trim(to_char(${colNameEscaped}, 'Day Month')),
983
1252
  'Q' || trim(to_char(${colNameEscaped}, 'Q')),
984
1253
  'WK' || trim(to_char(${colNameEscaped}, 'WW'))
985
- ) END)`
986
- }
987
- const colTxt = `COALESCE(${colSelect}, '')`; // position(${term} IN ${colTxt}) > 0
988
- if(returnType === "boolean"){
989
- return `
990
- WHEN ${colTxt} ${matchCase? "LIKE" : "ILIKE"} ${asValue('%' + rawTerm + '%')}
1254
+ ) END)`;
1255
+ }
1256
+ const colTxt = `COALESCE(${colSelect}, '')`; // position(${term} IN ${colTxt}) > 0
1257
+ if (returnType === "boolean") {
1258
+ return `
1259
+ WHEN ${colTxt} ${matchCase ? "LIKE" : "ILIKE"} ${asValue("%" + rawTerm + "%")}
991
1260
  THEN TRUE
992
- `
993
- }
994
- return `
995
- WHEN ${colTxt} ${matchCase? "LIKE" : "ILIKE"} ${asValue('%' + rawTerm + '%')}
1261
+ `;
1262
+ }
1263
+ return `
1264
+ WHEN ${colTxt} ${matchCase ? "LIKE" : "ILIKE"} ${asValue("%" + rawTerm + "%")}
996
1265
  THEN json_build_object(
997
1266
  ${asValue(c.key)},
998
- ${makeTextMatcherArray(
999
- colTxt,
1000
- term
1001
- )}
1267
+ ${makeTextMatcherArray(colTxt, term)}
1002
1268
  )::jsonb
1003
- `
1004
- }).join(" ")}
1005
- ELSE ${(returnType === "boolean")? "FALSE" : "NULL"}
1269
+ `;
1270
+ })
1271
+ .join(" ")}
1272
+ ELSE ${returnType === "boolean" ? "FALSE" : "NULL"}
1006
1273
 
1007
1274
  END`;
1008
1275
 
@@ -1016,28 +1283,42 @@ export const FUNCTIONS: FunctionSpec[] = [
1016
1283
  ),
1017
1284
  to_json(${rightStr}::TEXT )
1018
1285
  ]) ELSE array_to_json(ARRAY[(${colRaw})::TEXT]) END`;
1019
-
1020
1286
  }
1021
1287
 
1022
1288
  return res;
1023
- }
1289
+ },
1024
1290
  },
1025
1291
 
1026
1292
  /* Aggs */
1027
- ...["max", "min", "count", "avg", "json_agg", "jsonb_agg", "string_agg", "array_agg", "sum"].map(aggName => ({
1028
- name: "$" + aggName,
1029
- type: "aggregation",
1030
- numArgs: 1,
1031
- singleColArg: true,
1032
- getFields: (args: any[]) => [args[0]],
1033
- getQuery: ({ args, tableAlias }) => {
1034
- let extraArgs = "";
1035
- if(args.length > 1){
1036
- extraArgs = pgp.as.format(", $1:csv", args.slice(1))
1037
- }
1038
- return aggName + "(" + asNameAlias(args[0], tableAlias) + `${extraArgs})`;
1039
- }
1040
- } satisfies FunctionSpec)),
1293
+ ...[
1294
+ "max",
1295
+ "min",
1296
+ "count",
1297
+ "avg",
1298
+ "json_agg",
1299
+ "jsonb_agg",
1300
+ "string_agg",
1301
+ "array_agg",
1302
+ "sum",
1303
+ ].map(
1304
+ (aggName) =>
1305
+ ({
1306
+ name: "$" + aggName,
1307
+ type: "aggregation",
1308
+ numArgs: 1,
1309
+ singleColArg: true,
1310
+ getFields: (args: any[]) => [args[0]],
1311
+ getQuery: ({ args, tableAlias }) => {
1312
+ let extraArgs = "";
1313
+ if (args.length > 1) {
1314
+ extraArgs = pgp.as.format(", $1:csv", args.slice(1));
1315
+ }
1316
+ return (
1317
+ aggName + "(" + asNameAlias(args[0], tableAlias) + `${extraArgs})`
1318
+ );
1319
+ },
1320
+ }) satisfies FunctionSpec,
1321
+ ),
1041
1322
 
1042
1323
  {
1043
1324
  name: "$jsonb_build_object",
@@ -1045,10 +1326,10 @@ export const FUNCTIONS: FunctionSpec[] = [
1045
1326
  numArgs: 22,
1046
1327
  minCols: 1,
1047
1328
  singleColArg: false,
1048
- getFields: args => args,
1329
+ getFields: (args) => args,
1049
1330
  getQuery: ({ args, tableAlias }) => {
1050
- return `jsonb_build_object(${args.flatMap(arg => [asValue(arg), asNameAlias(arg, tableAlias)]).join(", ")})`;
1051
- }
1331
+ return `jsonb_build_object(${args.flatMap((arg) => [asValue(arg), asNameAlias(arg, tableAlias)]).join(", ")})`;
1332
+ },
1052
1333
  },
1053
1334
 
1054
1335
  /* More aggs */
@@ -1061,7 +1342,7 @@ export const FUNCTIONS: FunctionSpec[] = [
1061
1342
  getFields: (args: any[]) => [],
1062
1343
  getQuery: ({ allowedFields, args, tableAlias }) => {
1063
1344
  return "COUNT(*)";
1064
- }
1345
+ },
1065
1346
  } as FunctionSpec,
1066
1347
  {
1067
1348
  name: "$diff_perc",
@@ -1071,14 +1352,13 @@ export const FUNCTIONS: FunctionSpec[] = [
1071
1352
  getFields: (args: any[]) => [args[0]],
1072
1353
  getQuery: ({ allowedFields, args, tableAlias }) => {
1073
1354
  const col = asNameAlias(args[0], tableAlias);
1074
- return `round( ( ( MAX(${col}) - MIN(${col}) )::float/MIN(${col}) ) * 100, 2)`
1075
- }
1076
- } as FunctionSpec
1355
+ return `round( ( ( MAX(${col}) - MIN(${col}) )::float/MIN(${col}) ) * 100, 2)`;
1356
+ },
1357
+ } as FunctionSpec,
1077
1358
  ];
1078
1359
 
1079
1360
  /* The difference between a function and computed field is that the computed field does not require any arguments */
1080
1361
  export const COMPUTED_FIELDS: FieldSpec[] = [
1081
-
1082
1362
  /**
1083
1363
  * Used instead of row id. Must be used as a last resort. Use all non pseudo or domain data type columns first!
1084
1364
  */
@@ -1087,18 +1367,20 @@ export const COMPUTED_FIELDS: FieldSpec[] = [
1087
1367
  type: "computed",
1088
1368
  // description: ` order hash of row content `,
1089
1369
  getQuery: ({ allowedFields, tableAlias, ctidField }) => {
1090
- return "md5(" +
1370
+ return (
1371
+ "md5(" +
1091
1372
  allowedFields
1092
1373
 
1093
1374
  /* CTID not available in AFTER trigger */
1094
1375
  // .concat(ctidField? [ctidField] : [])
1095
1376
  .sort()
1096
- .map(f => asNameAlias(f, tableAlias))
1097
- .map(f => `md5(coalesce(${f}::text, 'dd'))`)
1098
- .join(" || ") +
1099
- `)`;
1100
- }
1101
- }
1377
+ .map((f) => asNameAlias(f, tableAlias))
1378
+ .map((f) => `md5(coalesce(${f}::text, 'dd'))`)
1379
+ .join(" || ") +
1380
+ `)`
1381
+ );
1382
+ },
1383
+ },
1102
1384
  // ,{
1103
1385
  // name: "ctid",
1104
1386
  // type: "computed",
@@ -1150,4 +1432,4 @@ WHERE NOT EXISTS ( --Keep only leaf values
1150
1432
  AND starts_with(t2.path, t1.path)
1151
1433
  );
1152
1434
 
1153
- */
1435
+ */