prostgles-server 4.2.183 → 4.2.185
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.
- package/.github/workflows/main.yml +15 -15
- package/.prettierignore +2 -0
- package/README.md +1 -1
- package/dist/Auth/AuthHandler.d.ts +1 -1
- package/dist/Auth/AuthHandler.d.ts.map +1 -1
- package/dist/Auth/AuthHandler.js +64 -32
- package/dist/Auth/AuthHandler.js.map +1 -1
- package/dist/Auth/AuthTypes.d.ts +15 -1
- package/dist/Auth/AuthTypes.d.ts.map +1 -1
- package/dist/Auth/getSafeReturnURL.d.ts.map +1 -1
- package/dist/Auth/getSafeReturnURL.js.map +1 -1
- package/dist/Auth/sendEmail.d.ts.map +1 -1
- package/dist/Auth/sendEmail.js +6 -6
- package/dist/Auth/sendEmail.js.map +1 -1
- package/dist/Auth/setAuthProviders.d.ts +1 -1
- package/dist/Auth/setAuthProviders.d.ts.map +1 -1
- package/dist/Auth/setAuthProviders.js +15 -8
- package/dist/Auth/setAuthProviders.js.map +1 -1
- package/dist/Auth/setEmailProvider.d.ts.map +1 -1
- package/dist/Auth/setEmailProvider.js +23 -4
- package/dist/Auth/setEmailProvider.js.map +1 -1
- package/dist/Auth/setupAuthRoutes.d.ts.map +1 -1
- package/dist/Auth/setupAuthRoutes.js +27 -9
- package/dist/Auth/setupAuthRoutes.js.map +1 -1
- package/dist/DBEventsManager.d.ts.map +1 -1
- package/dist/DBEventsManager.js +24 -19
- package/dist/DBEventsManager.js.map +1 -1
- package/dist/DBSchemaBuilder.d.ts.map +1 -1
- package/dist/DBSchemaBuilder.js +18 -5
- package/dist/DBSchemaBuilder.js.map +1 -1
- package/dist/DboBuilder/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder/DboBuilder.js +7 -2
- package/dist/DboBuilder/DboBuilder.js.map +1 -1
- package/dist/DboBuilder/DboBuilderTypes.d.ts +4 -4
- package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
- package/dist/DboBuilder/DboBuilderTypes.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions.d.ts +2 -2
- package/dist/DboBuilder/QueryBuilder/Functions.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/Functions.js +293 -173
- package/dist/DboBuilder/QueryBuilder/Functions.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts +2 -2
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +52 -29
- package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getJoinQuery.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getJoinQuery.js +51 -32
- package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getNewQuery.js +48 -25
- package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts +1 -1
- package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getSelectQuery.js +32 -23
- package/dist/DboBuilder/QueryBuilder/getSelectQuery.js.map +1 -1
- package/dist/DboBuilder/QueryStreamer.d.ts +2 -2
- package/dist/DboBuilder/QueryStreamer.d.ts.map +1 -1
- package/dist/DboBuilder/QueryStreamer.js +68 -23
- package/dist/DboBuilder/QueryStreamer.js.map +1 -1
- package/dist/DboBuilder/TableHandler/DataValidator.d.ts +1 -1
- package/dist/DboBuilder/TableHandler/DataValidator.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/DataValidator.js +79 -43
- package/dist/DboBuilder/TableHandler/DataValidator.js.map +1 -1
- package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/TableHandler.js +39 -15
- package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
- package/dist/DboBuilder/TableHandler/delete.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/delete.js +44 -13
- package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
- package/dist/DboBuilder/TableHandler/insert.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/insert.js +81 -22
- package/dist/DboBuilder/TableHandler/insert.js.map +1 -1
- package/dist/DboBuilder/TableHandler/insertTest.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/insertTest.js.map +1 -1
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts +1 -1
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js +7 -4
- package/dist/DboBuilder/TableHandler/onDeleteFromFileTable.js.map +1 -1
- package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js +24 -5
- package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js.map +1 -1
- package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/update.js +16 -4
- package/dist/DboBuilder/TableHandler/update.js.map +1 -1
- package/dist/DboBuilder/TableHandler/updateBatch.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/updateBatch.js +33 -10
- package/dist/DboBuilder/TableHandler/updateBatch.js.map +1 -1
- package/dist/DboBuilder/TableHandler/updateFile.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/updateFile.js +24 -6
- package/dist/DboBuilder/TableHandler/updateFile.js.map +1 -1
- package/dist/DboBuilder/TableHandler/upsert.d.ts.map +1 -1
- package/dist/DboBuilder/TableHandler/upsert.js +22 -6
- package/dist/DboBuilder/TableHandler/upsert.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +5 -5
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/ViewHandler.js +64 -36
- package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/count.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/count.js +21 -7
- package/dist/DboBuilder/ViewHandler/count.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/find.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/find.js +76 -22
- package/dist/DboBuilder/ViewHandler/find.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/getExistsCondition.js +19 -10
- package/dist/DboBuilder/ViewHandler/getExistsCondition.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/getExistsFilters.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/getExistsFilters.js +12 -5
- package/dist/DboBuilder/ViewHandler/getExistsFilters.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/getInfo.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/getInfo.js +27 -9
- package/dist/DboBuilder/ViewHandler/getInfo.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts +2 -2
- package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js +42 -23
- package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.js +22 -9
- package/dist/DboBuilder/ViewHandler/parseComplexFilter.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseFieldFilter.d.ts +4 -4
- package/dist/DboBuilder/ViewHandler/parseFieldFilter.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseFieldFilter.js +13 -11
- package/dist/DboBuilder/ViewHandler/parseFieldFilter.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseJoinPath.d.ts +1 -1
- package/dist/DboBuilder/ViewHandler/parseJoinPath.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/parseJoinPath.js +44 -29
- package/dist/DboBuilder/ViewHandler/parseJoinPath.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/prepareSortItems.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/prepareSortItems.js +36 -27
- package/dist/DboBuilder/ViewHandler/prepareSortItems.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/prepareWhere.js +16 -12
- package/dist/DboBuilder/ViewHandler/prepareWhere.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/size.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/size.js +24 -7
- package/dist/DboBuilder/ViewHandler/size.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.js +40 -12
- package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/validateViewRules.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/validateViewRules.js +20 -5
- package/dist/DboBuilder/ViewHandler/validateViewRules.js.map +1 -1
- package/dist/DboBuilder/dboBuilderUtils.d.ts.map +1 -1
- package/dist/DboBuilder/dboBuilderUtils.js +18 -7
- package/dist/DboBuilder/dboBuilderUtils.js.map +1 -1
- package/dist/DboBuilder/getColumns.d.ts.map +1 -1
- package/dist/DboBuilder/getColumns.js +22 -7
- package/dist/DboBuilder/getColumns.js.map +1 -1
- package/dist/DboBuilder/getCondition.d.ts.map +1 -1
- package/dist/DboBuilder/getCondition.js +43 -30
- package/dist/DboBuilder/getCondition.js.map +1 -1
- package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
- package/dist/DboBuilder/getSubscribeRelatedTables.js +38 -27
- package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
- package/dist/DboBuilder/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
- package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js +9 -9
- package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js.map +1 -1
- package/dist/DboBuilder/insertNestedRecords.d.ts +3 -3
- package/dist/DboBuilder/insertNestedRecords.d.ts.map +1 -1
- package/dist/DboBuilder/insertNestedRecords.js +79 -44
- package/dist/DboBuilder/insertNestedRecords.js.map +1 -1
- package/dist/DboBuilder/parseUpdateRules.d.ts.map +1 -1
- package/dist/DboBuilder/parseUpdateRules.js +38 -14
- package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
- package/dist/DboBuilder/prepareShortestJoinPaths.d.ts.map +1 -1
- package/dist/DboBuilder/prepareShortestJoinPaths.js +56 -31
- package/dist/DboBuilder/prepareShortestJoinPaths.js.map +1 -1
- package/dist/DboBuilder/runSQL.d.ts.map +1 -1
- package/dist/DboBuilder/runSQL.js +41 -21
- package/dist/DboBuilder/runSQL.js.map +1 -1
- package/dist/DboBuilder/runTransaction.d.ts +1 -1
- package/dist/DboBuilder/runTransaction.d.ts.map +1 -1
- package/dist/DboBuilder/runTransaction.js +2 -2
- package/dist/DboBuilder/runTransaction.js.map +1 -1
- package/dist/DboBuilder/sqlErrCodeToMsg.d.ts.map +1 -1
- package/dist/DboBuilder/sqlErrCodeToMsg.js +297 -38
- package/dist/DboBuilder/sqlErrCodeToMsg.js.map +1 -1
- package/dist/DboBuilder/uploadFile.d.ts.map +1 -1
- package/dist/DboBuilder/uploadFile.js +33 -9
- package/dist/DboBuilder/uploadFile.js.map +1 -1
- package/dist/Event_Trigger_Tags.d.ts +1 -1
- package/dist/Event_Trigger_Tags.d.ts.map +1 -1
- package/dist/Event_Trigger_Tags.js +1 -1
- package/dist/Event_Trigger_Tags.js.map +1 -1
- package/dist/FileManager/FileManager.d.ts.map +1 -1
- package/dist/FileManager/FileManager.js +6 -3
- package/dist/FileManager/FileManager.js.map +1 -1
- package/dist/FileManager/getValidatedFileType.d.ts.map +1 -1
- package/dist/FileManager/getValidatedFileType.js +18 -16
- package/dist/FileManager/getValidatedFileType.js.map +1 -1
- package/dist/FileManager/initFileManager.d.ts.map +1 -1
- package/dist/FileManager/initFileManager.js +7 -1
- package/dist/FileManager/initFileManager.js.map +1 -1
- package/dist/FileManager/upload.d.ts +1 -1
- package/dist/FileManager/upload.d.ts.map +1 -1
- package/dist/FileManager/upload.js +3 -3
- package/dist/FileManager/upload.js.map +1 -1
- package/dist/FileManager/uploadStream.d.ts +1 -1
- package/dist/FileManager/uploadStream.d.ts.map +1 -1
- package/dist/FileManager/uploadStream.js +6 -7
- package/dist/FileManager/uploadStream.js.map +1 -1
- package/dist/Filtering.d.ts +3 -3
- package/dist/Filtering.d.ts.map +1 -1
- package/dist/Filtering.js +70 -37
- package/dist/Filtering.js.map +1 -1
- package/dist/JSONBValidation/validate_jsonb_schema_sql.d.ts.map +1 -1
- package/dist/JSONBValidation/validate_jsonb_schema_sql.js +1 -4
- package/dist/JSONBValidation/validate_jsonb_schema_sql.js.map +1 -1
- package/dist/JSONBValidation/validation.d.ts.map +1 -1
- package/dist/JSONBValidation/validation.js +46 -24
- package/dist/JSONBValidation/validation.js.map +1 -1
- package/dist/Logging.d.ts +2 -2
- package/dist/Logging.d.ts.map +1 -1
- package/dist/PostgresNotifListenManager.d.ts.map +1 -1
- package/dist/PostgresNotifListenManager.js +20 -22
- package/dist/PostgresNotifListenManager.js.map +1 -1
- package/dist/Prostgles.d.ts +1 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +37 -11
- package/dist/Prostgles.js.map +1 -1
- package/dist/ProstglesTypes.d.ts.map +1 -1
- package/dist/ProstglesTypes.js +6 -1
- package/dist/ProstglesTypes.js.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js +10 -5
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/addSub.d.ts.map +1 -1
- package/dist/PubSubManager/addSub.js +4 -6
- package/dist/PubSubManager/addSub.js.map +1 -1
- package/dist/PubSubManager/addSync.d.ts.map +1 -1
- package/dist/PubSubManager/addSync.js +10 -6
- package/dist/PubSubManager/addSync.js.map +1 -1
- package/dist/PubSubManager/getCreatePubSubManagerError.d.ts.map +1 -1
- package/dist/PubSubManager/getCreatePubSubManagerError.js +3 -1
- package/dist/PubSubManager/getCreatePubSubManagerError.js.map +1 -1
- package/dist/PubSubManager/getPubSubManagerInitQuery.d.ts.map +1 -1
- package/dist/PubSubManager/getPubSubManagerInitQuery.js +8 -8
- package/dist/PubSubManager/getPubSubManagerInitQuery.js.map +1 -1
- package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/initPubSubManager.js +7 -9
- package/dist/PubSubManager/initPubSubManager.js.map +1 -1
- package/dist/PubSubManager/notifListener.d.ts.map +1 -1
- package/dist/PubSubManager/notifListener.js +23 -12
- package/dist/PubSubManager/notifListener.js.map +1 -1
- package/dist/PubSubManager/orphanTriggerCheck.d.ts.map +1 -1
- package/dist/PubSubManager/orphanTriggerCheck.js.map +1 -1
- package/dist/PubSubManager/pushSubData.d.ts.map +1 -1
- package/dist/PubSubManager/pushSubData.js +1 -1
- package/dist/PubSubManager/pushSubData.js.map +1 -1
- package/dist/PublishParser/PublishParser.d.ts +1 -1
- package/dist/PublishParser/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser/PublishParser.js +25 -14
- package/dist/PublishParser/PublishParser.js.map +1 -1
- package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
- package/dist/PublishParser/getFileTableRules.js +23 -16
- package/dist/PublishParser/getFileTableRules.js.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.js +39 -16
- package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js +42 -22
- package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.js +5 -1
- package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
- package/dist/RestApi.d.ts +1 -1
- package/dist/RestApi.d.ts.map +1 -1
- package/dist/RestApi.js +1 -1
- package/dist/RestApi.js.map +1 -1
- package/dist/SchemaWatch/SchemaWatch.d.ts +2 -2
- package/dist/SchemaWatch/SchemaWatch.d.ts.map +1 -1
- package/dist/SchemaWatch/SchemaWatch.js +11 -9
- package/dist/SchemaWatch/SchemaWatch.js.map +1 -1
- package/dist/SchemaWatch/getValidatedWatchSchemaType.d.ts.map +1 -1
- package/dist/SchemaWatch/getValidatedWatchSchemaType.js +3 -3
- package/dist/SchemaWatch/getValidatedWatchSchemaType.js.map +1 -1
- package/dist/SchemaWatch/getWatchSchemaTagList.d.ts.map +1 -1
- package/dist/SchemaWatch/getWatchSchemaTagList.js +12 -6
- package/dist/SchemaWatch/getWatchSchemaTagList.js.map +1 -1
- package/dist/SyncReplication.d.ts.map +1 -1
- package/dist/SyncReplication.js +84 -42
- package/dist/SyncReplication.js.map +1 -1
- package/dist/TableConfig/TableConfig.d.ts +5 -5
- package/dist/TableConfig/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig/TableConfig.js +18 -5
- package/dist/TableConfig/TableConfig.js.map +1 -1
- package/dist/TableConfig/getColumnDefinitionQuery.d.ts +2 -2
- package/dist/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
- package/dist/TableConfig/getColumnDefinitionQuery.js +20 -9
- package/dist/TableConfig/getColumnDefinitionQuery.js.map +1 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.d.ts +3 -3
- package/dist/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.js +12 -7
- package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
- package/dist/TableConfig/getFutureTableSchema.d.ts +1 -1
- package/dist/TableConfig/getFutureTableSchema.d.ts.map +1 -1
- package/dist/TableConfig/getFutureTableSchema.js +6 -4
- package/dist/TableConfig/getFutureTableSchema.js.map +1 -1
- package/dist/TableConfig/getPGIndexes.d.ts.map +1 -1
- package/dist/TableConfig/getPGIndexes.js.map +1 -1
- package/dist/TableConfig/getTableColumnQueries.d.ts +1 -1
- package/dist/TableConfig/getTableColumnQueries.d.ts.map +1 -1
- package/dist/TableConfig/getTableColumnQueries.js +38 -19
- package/dist/TableConfig/getTableColumnQueries.js.map +1 -1
- package/dist/TableConfig/initTableConfig.d.ts.map +1 -1
- package/dist/TableConfig/initTableConfig.js +91 -43
- package/dist/TableConfig/initTableConfig.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/initProstgles.d.ts.map +1 -1
- package/dist/initProstgles.js +14 -10
- package/dist/initProstgles.js.map +1 -1
- package/dist/onSocketConnected.d.ts.map +1 -1
- package/dist/onSocketConnected.js +38 -16
- package/dist/onSocketConnected.js.map +1 -1
- package/dist/runClientRequest.d.ts.map +1 -1
- package/dist/runClientRequest.js +33 -14
- package/dist/runClientRequest.js.map +1 -1
- package/dist/shortestPath.d.ts.map +1 -1
- package/dist/shortestPath.js +1 -1
- package/dist/shortestPath.js.map +1 -1
- package/dist/typeTests/dboTypeCheck.js.map +1 -1
- package/examples/full-example-typescript/DBoGenerated.d.ts +112 -54
- package/examples/full-example-typescript/DBoGenerated.js +3 -3
- package/examples/full-example-typescript/home.html +28 -26
- package/examples/full-example-typescript/index.d.ts +1 -1
- package/examples/full-example-typescript/index.js +80 -53
- package/examples/full-example-vanilla/home.html +151 -125
- package/examples/server/javascript/index.js +17 -19
- package/lib/Auth/AuthHandler.ts +234 -155
- package/lib/Auth/AuthTypes.ts +27 -4
- package/lib/Auth/getSafeReturnURL.ts +35 -21
- package/lib/Auth/sendEmail.ts +34 -31
- package/lib/Auth/setAuthProviders.ts +94 -71
- package/lib/Auth/setEmailProvider.ts +45 -27
- package/lib/Auth/setupAuthRoutes.ts +164 -100
- package/lib/DBEventsManager.ts +87 -65
- package/lib/DBSchemaBuilder.ts +62 -28
- package/lib/DboBuilder/DboBuilder.ts +45 -21
- package/lib/DboBuilder/DboBuilderTypes.ts +99 -95
- package/lib/DboBuilder/QueryBuilder/Functions.ts +862 -580
- package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +202 -141
- package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +199 -124
- package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +209 -148
- package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +101 -75
- package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +10 -5
- package/lib/DboBuilder/QueryStreamer.ts +207 -100
- package/lib/DboBuilder/TableHandler/DataValidator.ts +253 -148
- package/lib/DboBuilder/TableHandler/TableHandler.ts +155 -60
- package/lib/DboBuilder/TableHandler/delete.ts +82 -29
- package/lib/DboBuilder/TableHandler/insert.ts +177 -81
- package/lib/DboBuilder/TableHandler/insertTest.ts +13 -7
- package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +35 -21
- package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +95 -45
- package/lib/DboBuilder/TableHandler/update.ts +54 -14
- package/lib/DboBuilder/TableHandler/updateBatch.ts +59 -21
- package/lib/DboBuilder/TableHandler/updateFile.ts +57 -26
- package/lib/DboBuilder/TableHandler/upsert.ts +58 -13
- package/lib/DboBuilder/ViewHandler/ViewHandler.ts +264 -121
- package/lib/DboBuilder/ViewHandler/count.ts +56 -25
- package/lib/DboBuilder/ViewHandler/find.ts +153 -68
- package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +59 -32
- package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +31 -19
- package/lib/DboBuilder/ViewHandler/getInfo.ts +47 -16
- package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +91 -57
- package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +51 -29
- package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +35 -29
- package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +130 -76
- package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +140 -92
- package/lib/DboBuilder/ViewHandler/prepareWhere.ts +66 -26
- package/lib/DboBuilder/ViewHandler/size.ts +56 -22
- package/lib/DboBuilder/ViewHandler/subscribe.ts +122 -46
- package/lib/DboBuilder/ViewHandler/validateViewRules.ts +39 -14
- package/lib/DboBuilder/dboBuilderUtils.ts +41 -18
- package/lib/DboBuilder/getColumns.ts +44 -12
- package/lib/DboBuilder/getCondition.ts +120 -79
- package/lib/DboBuilder/getSubscribeRelatedTables.ts +144 -83
- package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +61 -44
- package/lib/DboBuilder/insertNestedRecords.ts +370 -235
- package/lib/DboBuilder/parseUpdateRules.ts +117 -61
- package/lib/DboBuilder/prepareShortestJoinPaths.ts +115 -56
- package/lib/DboBuilder/runSQL.ts +135 -74
- package/lib/DboBuilder/runTransaction.ts +27 -16
- package/lib/DboBuilder/sqlErrCodeToMsg.ts +502 -244
- package/lib/DboBuilder/uploadFile.ts +67 -31
- package/lib/Event_Trigger_Tags.ts +6 -4
- package/lib/FileManager/FileManager.ts +53 -21
- package/lib/FileManager/getValidatedFileType.ts +79 -35
- package/lib/FileManager/initFileManager.ts +21 -9
- package/lib/FileManager/upload.ts +21 -19
- package/lib/FileManager/uploadStream.ts +33 -34
- package/lib/Filtering.ts +249 -197
- package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +2 -7
- package/lib/JSONBValidation/validation.ts +147 -82
- package/lib/Logging.ts +107 -97
- package/lib/PostgresNotifListenManager.ts +96 -63
- package/lib/Prostgles.ts +106 -35
- package/lib/ProstglesTypes.ts +31 -9
- package/lib/PubSubManager/PubSubManager.ts +62 -27
- package/lib/PubSubManager/addSub.ts +56 -37
- package/lib/PubSubManager/addSync.ts +50 -33
- package/lib/PubSubManager/getCreatePubSubManagerError.ts +29 -21
- package/lib/PubSubManager/getPubSubManagerInitQuery.ts +45 -27
- package/lib/PubSubManager/initPubSubManager.ts +27 -18
- package/lib/PubSubManager/notifListener.ts +77 -59
- package/lib/PubSubManager/orphanTriggerCheck.ts +5 -4
- package/lib/PubSubManager/pushSubData.ts +11 -9
- package/lib/PublishParser/PublishParser.ts +102 -44
- package/lib/PublishParser/getFileTableRules.ts +97 -54
- package/lib/PublishParser/getSchemaFromPublish.ts +146 -74
- package/lib/PublishParser/getTableRulesWithoutFileTable.ts +101 -51
- package/lib/PublishParser/publishTypesAndUtils.ts +74 -23
- package/lib/RestApi.ts +10 -2
- package/lib/SchemaWatch/SchemaWatch.ts +52 -34
- package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +1 -1
- package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +32 -22
- package/lib/SchemaWatch/getWatchSchemaTagList.ts +24 -16
- package/lib/SyncReplication.ts +376 -190
- package/lib/TableConfig/TableConfig.ts +200 -136
- package/lib/TableConfig/getColumnDefinitionQuery.ts +65 -44
- package/lib/TableConfig/getConstraintDefinitionQueries.ts +41 -25
- package/lib/TableConfig/getFutureTableSchema.ts +31 -21
- package/lib/TableConfig/getPGIndexes.ts +7 -4
- package/lib/TableConfig/getTableColumnQueries.ts +101 -54
- package/lib/TableConfig/initTableConfig.ts +192 -101
- package/lib/index.ts +6 -5
- package/lib/initProstgles.ts +57 -51
- package/lib/onSocketConnected.ts +75 -40
- package/lib/runClientRequest.ts +148 -79
- package/lib/shortestPath.ts +80 -76
- package/lib/typeTests/DBoGenerated.d.ts +5 -1
- package/lib/typeTests/dboTypeCheck.ts +8 -8
- package/package.json +1 -1
|
@@ -1,54 +1,84 @@
|
|
|
1
|
-
import {
|
|
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: {
|
|
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)
|
|
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
|
|
26
|
-
|
|
27
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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 = (
|
|
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(
|
|
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 =
|
|
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:
|
|
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,
|
|
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
|
|
155
|
-
|
|
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 =
|
|
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:
|
|
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,
|
|
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 =
|
|
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
|
-
[
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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?
|
|
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],
|
|
232
|
-
|
|
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))
|
|
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
|
-
|
|
245
|
-
} else if(typeof qVal === "string") {
|
|
246
|
-
qVal = pgp.as.format(qType + "($1)", [qVal])
|
|
247
|
-
} else
|
|
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
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
|
|
336
|
-
|
|
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
|
-
|
|
340
|
-
|
|
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
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
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
|
-
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
|
|
525
|
+
return result;
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
return res;
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
430
531
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
|
|
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: ({
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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(
|
|
488
|
-
|
|
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(
|
|
500
|
-
|
|
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(
|
|
513
|
-
|
|
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(
|
|
525
|
-
|
|
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(
|
|
537
|
-
|
|
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(
|
|
549
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
]
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
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
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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(
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
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(
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
].
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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(
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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(
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
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(
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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 {
|
|
885
|
-
|
|
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 = [
|
|
888
|
-
|
|
889
|
-
|
|
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
|
|
894
|
-
|
|
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,
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
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 =
|
|
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
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
|
|
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(
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
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)
|
|
970
|
-
|
|
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
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
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
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
WHEN ${colTxt} ${matchCase? "LIKE" : "ILIKE"} ${asValue(
|
|
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
|
-
|
|
995
|
-
WHEN ${colTxt} ${matchCase? "LIKE" : "ILIKE"} ${asValue(
|
|
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
|
-
|
|
1005
|
-
|
|
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
|
-
...[
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
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
|
|
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
|
+
*/
|