@effect-app/infra 4.0.0-beta.98 → 4.0.0
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/CHANGELOG.md +2891 -0
- package/_check.sh +1 -1
- package/dist/CUPS.d.ts +28 -9
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +35 -14
- package/dist/ClusterCosmos.d.ts +67 -0
- package/dist/ClusterCosmos.d.ts.map +1 -0
- package/dist/ClusterCosmos.js +588 -0
- package/dist/ClusterServiceBus.d.ts +67 -0
- package/dist/ClusterServiceBus.d.ts.map +1 -0
- package/dist/ClusterServiceBus.js +84 -0
- package/dist/{api/ContextProvider.d.ts → ContextProvider.d.ts} +7 -4
- package/dist/ContextProvider.d.ts.map +1 -0
- package/dist/ContextProvider.js +40 -0
- package/dist/Emailer/Sendgrid.d.ts +110 -146
- package/dist/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/Emailer/Sendgrid.js +24 -19
- package/dist/Emailer/fake.d.ts +1 -1
- package/dist/Emailer/fake.d.ts.map +1 -1
- package/dist/Emailer/fake.js +4 -4
- package/dist/MainFiberSet.d.ts +11 -7
- package/dist/MainFiberSet.d.ts.map +1 -1
- package/dist/MainFiberSet.js +22 -6
- package/dist/QueueMaker/errors.d.ts +3 -1
- package/dist/QueueMaker/errors.d.ts.map +1 -1
- package/dist/QueueMaker/errors.js +4 -2
- package/dist/{adapters/SQL → SQL}/Model.d.ts +34 -45
- package/dist/SQL/Model.d.ts.map +1 -0
- package/dist/SQL/Model.js +469 -0
- package/dist/SQL.d.ts.map +1 -0
- package/dist/{adapters/SQL.js → SQL.js} +1 -1
- package/dist/Store/Cosmos/query.d.ts +16 -4
- package/dist/Store/Cosmos/query.d.ts.map +1 -1
- package/dist/Store/Cosmos/query.js +238 -42
- package/dist/Store/Cosmos.d.ts +2 -2
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +394 -319
- package/dist/Store/Disk.d.ts +4 -4
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +91 -39
- package/dist/Store/Memory.d.ts +7 -10
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +348 -78
- package/dist/Store/SQL/Pg.d.ts +2 -2
- package/dist/Store/SQL/Pg.d.ts.map +1 -1
- package/dist/Store/SQL/Pg.js +229 -154
- package/dist/Store/SQL/query.d.ts +19 -3
- package/dist/Store/SQL/query.d.ts.map +1 -1
- package/dist/Store/SQL/query.js +306 -12
- package/dist/Store/SQL.d.ts +22 -5
- package/dist/Store/SQL.d.ts.map +1 -1
- package/dist/Store/SQL.js +369 -98
- package/dist/Store/codeFilter.d.ts +4 -4
- package/dist/Store/codeFilter.d.ts.map +1 -1
- package/dist/Store/codeFilter.js +71 -22
- package/dist/Store/index.d.ts +6 -4
- package/dist/Store/index.d.ts.map +1 -1
- package/dist/Store/index.js +9 -6
- package/dist/Store/jsonDocument.d.ts +67 -0
- package/dist/Store/jsonDocument.d.ts.map +1 -0
- package/dist/Store/jsonDocument.js +107 -0
- package/dist/Store/utils.d.ts +21 -2
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +253 -10
- package/dist/WorkflowEngineCosmos.d.ts +30 -0
- package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
- package/dist/WorkflowEngineCosmos.js +542 -0
- package/dist/WorkflowEngineSqlite.d.ts +24 -0
- package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
- package/dist/WorkflowEngineSqlite.js +550 -0
- package/dist/arbs.d.ts +6 -3
- package/dist/arbs.d.ts.map +1 -1
- package/dist/arbs.js +20 -4
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +5 -0
- package/dist/cosmos-client.d.ts +40 -0
- package/dist/cosmos-client.d.ts.map +1 -0
- package/dist/cosmos-client.js +41 -0
- package/dist/errorReporter.d.ts +6 -4
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +23 -27
- package/dist/fileUtil.d.ts +1 -1
- package/dist/fileUtil.d.ts.map +1 -1
- package/dist/fileUtil.js +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/internal/RequestContextMiddleware.d.ts +5 -0
- package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
- package/dist/internal/RequestContextMiddleware.js +45 -0
- package/dist/internal/auth.d.ts +53 -0
- package/dist/internal/auth.d.ts.map +1 -0
- package/dist/internal/auth.js +180 -0
- package/dist/internal/events.d.ts +11 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +49 -0
- package/dist/{api/internal → internal}/health.d.ts +1 -1
- package/dist/internal/health.d.ts.map +1 -0
- package/dist/internal/health.js +5 -0
- package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +10 -2
- package/dist/layerUtils.d.ts.map +1 -0
- package/dist/layerUtils.js +17 -0
- package/dist/logger/jsonLogger.d.ts +1 -1
- package/dist/logger/jsonLogger.d.ts.map +1 -1
- package/dist/logger/jsonLogger.js +5 -3
- package/dist/logger/logFmtLogger.d.ts +1 -1
- package/dist/logger/logFmtLogger.d.ts.map +1 -1
- package/dist/logger/logFmtLogger.js +3 -3
- package/dist/logger/shared.d.ts +2 -2
- package/dist/logger/shared.d.ts.map +1 -1
- package/dist/logger/shared.js +6 -6
- package/dist/logger.d.ts.map +1 -1
- package/dist/middlewares.d.ts.map +1 -0
- package/dist/{api/middlewares.js → middlewares.js} +1 -1
- package/dist/{adapters/mongo-client.d.ts → mongo-client.d.ts} +2 -1
- package/dist/mongo-client.d.ts.map +1 -0
- package/dist/mongo-client.js +15 -0
- package/dist/otel.d.ts +75 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +84 -0
- package/dist/rateLimit.d.ts +11 -3
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +7 -12
- package/dist/{adapters/redis-client.d.ts → redis-client.d.ts} +4 -1
- package/dist/redis-client.d.ts.map +1 -0
- package/dist/redis-client.js +98 -0
- package/dist/{api/reportError.d.ts → reportError.d.ts} +1 -1
- package/dist/reportError.d.ts.map +1 -0
- package/dist/reportError.js +28 -0
- package/dist/{api/routing → routing}/middleware/RouterMiddleware.d.ts +2 -1
- package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
- package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
- package/dist/{api/routing → routing}/middleware/middleware.d.ts +11 -6
- package/dist/routing/middleware/middleware.d.ts.map +1 -0
- package/dist/routing/middleware/middleware.js +152 -0
- package/dist/{api/routing → routing}/middleware.d.ts +0 -1
- package/dist/routing/middleware.d.ts.map +1 -0
- package/dist/{api/routing → routing}/middleware.js +1 -2
- package/dist/routing/schema/jwt.d.ts.map +1 -0
- package/dist/routing/schema/jwt.js +12 -0
- package/dist/routing/tsort.d.ts.map +1 -0
- package/dist/routing/tsort.js +51 -0
- package/dist/{api/routing → routing}/utils.d.ts +3 -3
- package/dist/routing/utils.d.ts.map +1 -0
- package/dist/routing/utils.js +45 -0
- package/dist/routing.d.ts +182 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +256 -0
- package/dist/test.d.ts +2 -2
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +5 -5
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +14 -0
- package/docs/cluster-storage.md +26 -0
- package/docs/workflow-engine.md +262 -0
- package/examples/query.ts +23 -19
- package/package.json +36 -364
- package/src/CUPS.ts +53 -14
- package/src/ClusterCosmos.ts +1170 -0
- package/src/ClusterServiceBus.ts +244 -0
- package/src/{api/ContextProvider.ts → ContextProvider.ts} +10 -7
- package/src/Emailer/Sendgrid.ts +83 -60
- package/src/Emailer/fake.ts +4 -4
- package/src/MainFiberSet.ts +31 -12
- package/src/QueueMaker/errors.ts +3 -1
- package/src/{adapters/SQL → SQL}/Model.ts +48 -47
- package/src/SQL.ts +1 -0
- package/src/Store/Cosmos/query.ts +275 -55
- package/src/Store/Cosmos.ts +597 -515
- package/src/Store/Disk.ts +145 -71
- package/src/Store/Memory.ts +420 -115
- package/src/Store/SQL/Pg.ts +352 -268
- package/src/Store/SQL/query.ts +366 -20
- package/src/Store/SQL.ts +742 -293
- package/src/Store/codeFilter.ts +78 -28
- package/src/Store/index.ts +18 -13
- package/src/Store/jsonDocument.ts +143 -0
- package/src/Store/utils.ts +307 -30
- package/src/WorkflowEngineCosmos.ts +749 -0
- package/src/WorkflowEngineSqlite.ts +813 -0
- package/src/arbs.ts +25 -5
- package/src/cosmos-client.ts +72 -0
- package/src/errorReporter.ts +68 -78
- package/src/fileUtil.ts +1 -1
- package/src/index.ts +2 -1
- package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
- package/src/internal/auth.ts +272 -0
- package/src/{api/internal → internal}/events.ts +18 -9
- package/src/{api/layerUtils.ts → layerUtils.ts} +7 -3
- package/src/logger/jsonLogger.ts +5 -3
- package/src/logger/logFmtLogger.ts +3 -3
- package/src/logger/shared.ts +6 -5
- package/src/middlewares.ts +10 -0
- package/src/{adapters/mongo-client.ts → mongo-client.ts} +3 -1
- package/src/otel.ts +177 -0
- package/src/rateLimit.ts +35 -24
- package/src/{adapters/redis-client.ts → redis-client.ts} +6 -2
- package/src/{api/reportError.ts → reportError.ts} +3 -2
- package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +2 -1
- package/src/{api/routing → routing}/middleware/middleware.ts +75 -50
- package/src/routing/middleware.ts +4 -0
- package/src/{api/routing → routing}/schema/jwt.ts +2 -2
- package/src/{api/routing → routing}/utils.ts +2 -1
- package/src/routing.ts +823 -0
- package/src/test.ts +6 -6
- package/src/vitest.ts +1 -1
- package/test/arbs-magnitude.test.ts +33 -0
- package/test/arbs.test.ts +41 -0
- package/test/auth.test.ts +101 -0
- package/test/cluster-cosmos.test.ts +634 -0
- package/test/cluster-servicebus.test.ts +180 -0
- package/test/cluster-sqlite.test.ts +207 -0
- package/test/contextProvider.test.ts +11 -8
- package/test/controller.test.ts +23 -28
- package/test/cosmos-container-throughput.test.ts +80 -0
- package/test/cosmos-query.test.ts +368 -0
- package/test/dist/arbs-magnitude.test.d.ts.map +1 -0
- package/test/dist/arbs.test.d.ts.map +1 -0
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
- package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
- package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
- package/test/dist/contextProvider.test.d.ts.map +1 -1
- package/test/dist/controller.test.d.ts.map +1 -1
- package/test/dist/cosmos-container-throughput.test.d.ts.map +1 -0
- package/test/dist/cosmos-query.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +17 -9
- package/test/dist/fixtures.d.ts.map +1 -1
- package/test/dist/fixtures.js +8 -3
- package/test/dist/json-lower.test.d.ts.map +1 -0
- package/test/dist/query.test.d.ts.map +1 -1
- package/test/dist/rawQuery.test.d.ts.map +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- package/test/dist/repository-legacy-document.test.d.ts.map +1 -0
- package/test/dist/requires.test.d.ts.map +1 -1
- package/test/dist/router-generator.test.d.ts.map +1 -0
- package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
- package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
- package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
- package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
- package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
- package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
- package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
- package/test/fixtures.ts +7 -2
- package/test/json-lower.test.ts +129 -0
- package/test/layerUtils.test.ts +2 -2
- package/test/query.test.ts +1232 -42
- package/test/rawQuery.test.ts +432 -7
- package/test/repository-ext.test.ts +456 -0
- package/test/repository-legacy-document.test.ts +394 -0
- package/test/requires.test.ts +7 -3
- package/test/router-generator.test.ts +187 -0
- package/test/routing-interruptibility.test.ts +66 -0
- package/test/rpc-context-map-streaming.test.ts +265 -0
- package/test/rpc-e2e-invalidation.test.ts +421 -0
- package/test/rpc-multi-middleware.test.ts +17 -11
- package/test/rpc-stream-fullstack.test.ts +307 -0
- package/test/sql-store.test.ts +1202 -47
- package/test/validateSample.test.ts +70 -42
- package/test/workflow-engine-cosmos.test.ts +345 -0
- package/test/workflow-engine-sqlite.test.ts +297 -0
- package/tsconfig.examples.json +1 -1
- package/tsconfig.json +9 -1
- package/tsconfig.src.json +35 -35
- package/tsconfig.test.json +2 -2
- package/dist/Emailer/service.d.ts +0 -55
- package/dist/Emailer/service.d.ts.map +0 -1
- package/dist/Emailer/service.js +0 -6
- package/dist/Emailer.d.ts +0 -2
- package/dist/Emailer.d.ts.map +0 -1
- package/dist/Emailer.js +0 -2
- package/dist/Model/Repository/ext.d.ts +0 -41
- package/dist/Model/Repository/ext.d.ts.map +0 -1
- package/dist/Model/Repository/ext.js +0 -65
- package/dist/Model/Repository/internal/internal.d.ts +0 -59
- package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
- package/dist/Model/Repository/internal/internal.js +0 -320
- package/dist/Model/Repository/legacy.d.ts +0 -19
- package/dist/Model/Repository/legacy.d.ts.map +0 -1
- package/dist/Model/Repository/legacy.js +0 -2
- package/dist/Model/Repository/makeRepo.d.ts +0 -49
- package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
- package/dist/Model/Repository/makeRepo.js +0 -24
- package/dist/Model/Repository/service.d.ts +0 -89
- package/dist/Model/Repository/service.d.ts.map +0 -1
- package/dist/Model/Repository/service.js +0 -2
- package/dist/Model/Repository/validation.d.ts +0 -43
- package/dist/Model/Repository/validation.d.ts.map +0 -1
- package/dist/Model/Repository/validation.js +0 -32
- package/dist/Model/Repository.d.ts +0 -6
- package/dist/Model/Repository.d.ts.map +0 -1
- package/dist/Model/Repository.js +0 -6
- package/dist/Model/dsl.d.ts +0 -32
- package/dist/Model/dsl.d.ts.map +0 -1
- package/dist/Model/dsl.js +0 -44
- package/dist/Model/filter/filterApi.d.ts +0 -30
- package/dist/Model/filter/filterApi.d.ts.map +0 -1
- package/dist/Model/filter/filterApi.js +0 -2
- package/dist/Model/filter/types/errors.d.ts +0 -29
- package/dist/Model/filter/types/errors.d.ts.map +0 -1
- package/dist/Model/filter/types/errors.js +0 -2
- package/dist/Model/filter/types/fields.d.ts +0 -15
- package/dist/Model/filter/types/fields.d.ts.map +0 -1
- package/dist/Model/filter/types/fields.js +0 -2
- package/dist/Model/filter/types/path/common.d.ts +0 -316
- package/dist/Model/filter/types/path/common.d.ts.map +0 -1
- package/dist/Model/filter/types/path/common.js +0 -2
- package/dist/Model/filter/types/path/eager.d.ts +0 -95
- package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
- package/dist/Model/filter/types/path/eager.js +0 -31
- package/dist/Model/filter/types/path/index.d.ts +0 -4
- package/dist/Model/filter/types/path/index.d.ts.map +0 -1
- package/dist/Model/filter/types/path/index.js +0 -3
- package/dist/Model/filter/types/utils.d.ts +0 -79
- package/dist/Model/filter/types/utils.d.ts.map +0 -1
- package/dist/Model/filter/types/utils.js +0 -2
- package/dist/Model/filter/types/validator.d.ts +0 -30
- package/dist/Model/filter/types/validator.d.ts.map +0 -1
- package/dist/Model/filter/types/validator.js +0 -2
- package/dist/Model/filter/types.d.ts +0 -5
- package/dist/Model/filter/types.d.ts.map +0 -1
- package/dist/Model/filter/types.js +0 -7
- package/dist/Model/query/dsl.d.ts +0 -248
- package/dist/Model/query/dsl.d.ts.map +0 -1
- package/dist/Model/query/dsl.js +0 -104
- package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
- package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
- package/dist/Model/query/new-kid-interpreter.js +0 -165
- package/dist/Model/query.d.ts +0 -15
- package/dist/Model/query.d.ts.map +0 -1
- package/dist/Model/query.js +0 -3
- package/dist/Model.d.ts +0 -4
- package/dist/Model.d.ts.map +0 -1
- package/dist/Model.js +0 -4
- package/dist/Operations.d.ts +0 -55
- package/dist/Operations.d.ts.map +0 -1
- package/dist/Operations.js +0 -102
- package/dist/OperationsRepo.d.ts +0 -41
- package/dist/OperationsRepo.d.ts.map +0 -1
- package/dist/OperationsRepo.js +0 -14
- package/dist/QueueMaker/SQLQueue.d.ts +0 -14
- package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
- package/dist/QueueMaker/SQLQueue.js +0 -132
- package/dist/QueueMaker/memQueue.d.ts +0 -11
- package/dist/QueueMaker/memQueue.d.ts.map +0 -1
- package/dist/QueueMaker/memQueue.js +0 -76
- package/dist/QueueMaker/sbqueue.d.ts +0 -12
- package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
- package/dist/QueueMaker/sbqueue.js +0 -91
- package/dist/QueueMaker/service.d.ts +0 -11
- package/dist/QueueMaker/service.d.ts.map +0 -1
- package/dist/QueueMaker/service.js +0 -4
- package/dist/RequestContext.d.ts +0 -68
- package/dist/RequestContext.d.ts.map +0 -1
- package/dist/RequestContext.js +0 -49
- package/dist/RequestFiberSet.d.ts +0 -36
- package/dist/RequestFiberSet.d.ts.map +0 -1
- package/dist/RequestFiberSet.js +0 -78
- package/dist/Store/ContextMapContainer.d.ts +0 -25
- package/dist/Store/ContextMapContainer.d.ts.map +0 -1
- package/dist/Store/ContextMapContainer.js +0 -77
- package/dist/Store/service.d.ts +0 -111
- package/dist/Store/service.d.ts.map +0 -1
- package/dist/Store/service.js +0 -79
- package/dist/Store.d.ts +0 -2
- package/dist/Store.d.ts.map +0 -1
- package/dist/Store.js +0 -2
- package/dist/adapters/SQL/Model.d.ts.map +0 -1
- package/dist/adapters/SQL/Model.js +0 -478
- package/dist/adapters/SQL.d.ts.map +0 -1
- package/dist/adapters/ServiceBus.d.ts +0 -58
- package/dist/adapters/ServiceBus.d.ts.map +0 -1
- package/dist/adapters/ServiceBus.js +0 -99
- package/dist/adapters/cosmos-client.d.ts +0 -14
- package/dist/adapters/cosmos-client.d.ts.map +0 -1
- package/dist/adapters/cosmos-client.js +0 -9
- package/dist/adapters/index.d.ts +0 -2
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -2
- package/dist/adapters/logger.d.ts +0 -9
- package/dist/adapters/logger.d.ts.map +0 -1
- package/dist/adapters/logger.js +0 -3
- package/dist/adapters/memQueue.d.ts +0 -13
- package/dist/adapters/memQueue.d.ts.map +0 -1
- package/dist/adapters/memQueue.js +0 -20
- package/dist/adapters/mongo-client.d.ts.map +0 -1
- package/dist/adapters/mongo-client.js +0 -13
- package/dist/adapters/redis-client.d.ts.map +0 -1
- package/dist/adapters/redis-client.js +0 -94
- package/dist/api/ContextProvider.d.ts.map +0 -1
- package/dist/api/ContextProvider.js +0 -38
- package/dist/api/codec.d.ts.map +0 -1
- package/dist/api/codec.js +0 -5
- package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
- package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
- package/dist/api/internal/RequestContextMiddleware.js +0 -35
- package/dist/api/internal/auth.d.ts +0 -15
- package/dist/api/internal/auth.d.ts.map +0 -1
- package/dist/api/internal/auth.js +0 -47
- package/dist/api/internal/events.d.ts +0 -9
- package/dist/api/internal/events.d.ts.map +0 -1
- package/dist/api/internal/events.js +0 -42
- package/dist/api/internal/health.d.ts.map +0 -1
- package/dist/api/internal/health.js +0 -5
- package/dist/api/layerUtils.d.ts.map +0 -1
- package/dist/api/layerUtils.js +0 -16
- package/dist/api/middlewares.d.ts.map +0 -1
- package/dist/api/reportError.d.ts.map +0 -1
- package/dist/api/reportError.js +0 -27
- package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
- package/dist/api/routing/middleware/middleware.js +0 -130
- package/dist/api/routing/middleware.d.ts.map +0 -1
- package/dist/api/routing/schema/jwt.d.ts.map +0 -1
- package/dist/api/routing/schema/jwt.js +0 -12
- package/dist/api/routing/tsort.d.ts.map +0 -1
- package/dist/api/routing/tsort.js +0 -51
- package/dist/api/routing/utils.d.ts.map +0 -1
- package/dist/api/routing/utils.js +0 -44
- package/dist/api/routing.d.ts +0 -134
- package/dist/api/routing.d.ts.map +0 -1
- package/dist/api/routing.js +0 -167
- package/dist/api/setupRequest.d.ts +0 -15
- package/dist/api/setupRequest.d.ts.map +0 -1
- package/dist/api/setupRequest.js +0 -49
- package/dist/api/util.d.ts.map +0 -1
- package/dist/api/util.js +0 -14
- package/eslint.config.mjs +0 -24
- package/src/Emailer/service.ts +0 -52
- package/src/Emailer.ts +0 -1
- package/src/Model/Repository/ext.ts +0 -283
- package/src/Model/Repository/internal/internal.ts +0 -580
- package/src/Model/Repository/legacy.ts +0 -27
- package/src/Model/Repository/makeRepo.ts +0 -139
- package/src/Model/Repository/service.ts +0 -627
- package/src/Model/Repository/validation.ts +0 -31
- package/src/Model/Repository.ts +0 -5
- package/src/Model/dsl.ts +0 -128
- package/src/Model/filter/filterApi.ts +0 -60
- package/src/Model/filter/types/errors.ts +0 -47
- package/src/Model/filter/types/fields.ts +0 -50
- package/src/Model/filter/types/path/common.ts +0 -404
- package/src/Model/filter/types/path/eager.ts +0 -298
- package/src/Model/filter/types/path/index.ts +0 -4
- package/src/Model/filter/types/utils.ts +0 -128
- package/src/Model/filter/types/validator.ts +0 -46
- package/src/Model/filter/types.ts +0 -6
- package/src/Model/query/dsl.ts +0 -2110
- package/src/Model/query/new-kid-interpreter.ts +0 -210
- package/src/Model/query.ts +0 -13
- package/src/Model.ts +0 -3
- package/src/Operations.ts +0 -235
- package/src/OperationsRepo.ts +0 -16
- package/src/QueueMaker/SQLQueue.ts +0 -190
- package/src/QueueMaker/memQueue.ts +0 -130
- package/src/QueueMaker/sbqueue.ts +0 -137
- package/src/QueueMaker/service.ts +0 -17
- package/src/RequestContext.ts +0 -63
- package/src/RequestFiberSet.ts +0 -105
- package/src/Store/ContextMapContainer.ts +0 -116
- package/src/Store/index.test.ts.bak +0 -112
- package/src/Store/service.ts +0 -193
- package/src/Store.ts +0 -1
- package/src/adapters/SQL.ts +0 -1
- package/src/adapters/ServiceBus.ts +0 -209
- package/src/adapters/cosmos-client.ts +0 -16
- package/src/adapters/index.ts +0 -0
- package/src/adapters/logger.ts +0 -3
- package/src/adapters/memQueue.ts +0 -21
- package/src/api/internal/auth.ts +0 -68
- package/src/api/middlewares.ts +0 -10
- package/src/api/routing/middleware.ts +0 -6
- package/src/api/routing.ts +0 -598
- package/src/api/setupRequest.ts +0 -104
- package/test/dist/date-query.test.d.ts.map +0 -1
- package/tsconfig.json.bak +0 -12
- /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
- /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
- /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
- /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
- /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
- /package/dist/{api/util.d.ts → util.d.ts} +0 -0
- /package/src/{api/codec.ts → codec.ts} +0 -0
- /package/src/{api/internal → internal}/health.ts +0 -0
- /package/src/{api/routing → routing}/tsort.ts +0 -0
- /package/src/{api/util.ts → util.ts} +0 -0
package/src/Store/SQL/query.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import {
|
|
2
|
+
import type { NonEmptyReadonlyArray } from "effect-app/Array"
|
|
3
|
+
import * as Effect from "effect-app/Effect"
|
|
4
|
+
import type { FilterR, FilterResult } from "effect-app/Model/filter/filterApi"
|
|
5
|
+
import type { AggregateIrExpression, ComputedProjectionIrExpression, ComputedProjectionMathIrExpression } from "effect-app/Model/query"
|
|
3
6
|
import { assertUnreachable } from "effect-app/utils"
|
|
4
|
-
import { InfraLogger } from "../../logger.
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
+
import { InfraLogger } from "../../logger.ts"
|
|
8
|
+
import { isRelationCheck } from "../codeFilter.ts"
|
|
9
|
+
import { jsonifyFilter, type JsonLower } from "../utils.ts"
|
|
7
10
|
|
|
8
11
|
export interface SQLDialect {
|
|
9
12
|
readonly jsonExtract: (path: string) => string
|
|
@@ -15,6 +18,9 @@ export interface SQLDialect {
|
|
|
15
18
|
readonly jsonArrayNotContainsAny: (arrPath: string, valPlaceholders: readonly string[]) => string
|
|
16
19
|
readonly jsonArrayContainsAll: (arrPath: string, valPlaceholders: readonly string[]) => string
|
|
17
20
|
readonly jsonArrayNotContainsAll: (arrPath: string, valPlaceholders: readonly string[]) => string
|
|
21
|
+
readonly jsonMapHasKey: (arrPath: string, valPlaceholder: string) => string
|
|
22
|
+
readonly jsonMapHasValue: (arrPath: string, valPlaceholder: string) => string
|
|
23
|
+
readonly jsonMapHasPair: (arrPath: string, valPlaceholder: string) => string
|
|
18
24
|
readonly caseInsensitiveLike: (expr: string, valPlaceholder: string) => string
|
|
19
25
|
readonly caseInsensitiveNotLike: (expr: string, valPlaceholder: string) => string
|
|
20
26
|
readonly jsonColumnType: "JSON" | "JSONB"
|
|
@@ -22,11 +28,13 @@ export interface SQLDialect {
|
|
|
22
28
|
readonly jsonEachFrom: (arrPath: string, alias: string) => string
|
|
23
29
|
readonly jsonExtractElement: (alias: string, subPath: string) => string
|
|
24
30
|
readonly serializeJsonValue: (v: unknown) => unknown
|
|
31
|
+
readonly serializeScalar: (v: unknown) => unknown
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
export const sqliteDialect: SQLDialect = {
|
|
28
35
|
jsonExtract: (path) => `json_extract(data, '$.${path}')`,
|
|
29
|
-
jsonExtractJson: (path) =>
|
|
36
|
+
jsonExtractJson: (path) =>
|
|
37
|
+
`CASE json_type(data, '$.${path}') WHEN 'true' THEN 'true' WHEN 'false' THEN 'false' ELSE json_quote(json_extract(data, '$.${path}')) END`,
|
|
30
38
|
placeholder: (_index) => "?",
|
|
31
39
|
jsonArrayContains: (arrPath, val) => `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${val})`,
|
|
32
40
|
jsonArrayNotContains: (arrPath, val) =>
|
|
@@ -41,13 +49,21 @@ export const sqliteDialect: SQLDialect = {
|
|
|
41
49
|
`NOT (${
|
|
42
50
|
vals.map((v) => `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${v})`).join(" AND ")
|
|
43
51
|
})`,
|
|
52
|
+
jsonMapHasKey: (arrPath, val) =>
|
|
53
|
+
`EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE json_extract(value, '$[0]') = ${val})`,
|
|
54
|
+
jsonMapHasValue: (arrPath, val) =>
|
|
55
|
+
`EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE json_extract(value, '$[1]') = ${val})`,
|
|
56
|
+
jsonMapHasPair: (arrPath, val) => `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${val})`,
|
|
44
57
|
caseInsensitiveLike: (expr, val) => `LOWER(${expr}) LIKE LOWER(${val})`,
|
|
45
58
|
caseInsensitiveNotLike: (expr, val) => `LOWER(${expr}) NOT LIKE LOWER(${val})`,
|
|
46
59
|
jsonColumnType: "JSON",
|
|
47
60
|
arrayLength: (path) => `json_array_length(data, '$.${path}')`,
|
|
48
61
|
jsonEachFrom: (arrPath, alias) => `json_each(data, '$.${arrPath}') AS ${alias}`,
|
|
49
62
|
jsonExtractElement: (alias, subPath) => `json_extract(${alias}.value, '$.${subPath}')`,
|
|
50
|
-
serializeJsonValue: (v) => v
|
|
63
|
+
serializeJsonValue: (v) => v,
|
|
64
|
+
// SQLite stores JSON booleans as integers (0/1) and better-sqlite3 refuses
|
|
65
|
+
// to bind JS booleans, so coerce them to integers for WHERE params.
|
|
66
|
+
serializeScalar: (v) => typeof v === "boolean" ? (v ? 1 : 0) : v
|
|
51
67
|
}
|
|
52
68
|
|
|
53
69
|
export const pgDialect: SQLDialect = {
|
|
@@ -105,6 +121,27 @@ export const pgDialect: SQLDialect = {
|
|
|
105
121
|
: `data${parts.map((p) => `->'${p}'`).join("")}`
|
|
106
122
|
return `NOT (${vals.map((v) => `${jsonPath} @> ${v}::jsonb`).join(" AND ")})`
|
|
107
123
|
},
|
|
124
|
+
jsonMapHasKey: (arrPath, val) => {
|
|
125
|
+
const parts = arrPath.split(".")
|
|
126
|
+
const jsonPath = parts.length === 1
|
|
127
|
+
? `data->'${parts[0]}'`
|
|
128
|
+
: `data${parts.map((p) => `->'${p}'`).join("")}`
|
|
129
|
+
return `EXISTS(SELECT 1 FROM jsonb_array_elements(${jsonPath}) e WHERE e->0 = ${val}::jsonb)`
|
|
130
|
+
},
|
|
131
|
+
jsonMapHasValue: (arrPath, val) => {
|
|
132
|
+
const parts = arrPath.split(".")
|
|
133
|
+
const jsonPath = parts.length === 1
|
|
134
|
+
? `data->'${parts[0]}'`
|
|
135
|
+
: `data${parts.map((p) => `->'${p}'`).join("")}`
|
|
136
|
+
return `EXISTS(SELECT 1 FROM jsonb_array_elements(${jsonPath}) e WHERE e->1 = ${val}::jsonb)`
|
|
137
|
+
},
|
|
138
|
+
jsonMapHasPair: (arrPath, val) => {
|
|
139
|
+
const parts = arrPath.split(".")
|
|
140
|
+
const jsonPath = parts.length === 1
|
|
141
|
+
? `data->'${parts[0]}'`
|
|
142
|
+
: `data${parts.map((p) => `->'${p}'`).join("")}`
|
|
143
|
+
return `${jsonPath} @> jsonb_build_array(${val}::jsonb)`
|
|
144
|
+
},
|
|
108
145
|
caseInsensitiveLike: (expr, val) => `${expr} ILIKE ${val}`,
|
|
109
146
|
caseInsensitiveNotLike: (expr, val) => `${expr} NOT ILIKE ${val}`,
|
|
110
147
|
jsonColumnType: "JSONB",
|
|
@@ -122,7 +159,9 @@ export const pgDialect: SQLDialect = {
|
|
|
122
159
|
const last = parts.pop()!
|
|
123
160
|
return `${alias}${parts.map((p) => `->'${p}'`).join("")}->>'${last}'`
|
|
124
161
|
},
|
|
125
|
-
serializeJsonValue: (v) => JSON.stringify(v)
|
|
162
|
+
serializeJsonValue: (v) => JSON.stringify(v),
|
|
163
|
+
// PG's ->> operator yields text, so compare booleans as 'true'/'false' text.
|
|
164
|
+
serializeScalar: (v) => typeof v === "boolean" ? (v ? "true" : "false") : v
|
|
126
165
|
}
|
|
127
166
|
|
|
128
167
|
export function logQuery(q: { sql: string; params: unknown[] }) {
|
|
@@ -140,22 +179,51 @@ const dottedToJsonPath = (path: string) =>
|
|
|
140
179
|
.filter((p) => p !== "-1")
|
|
141
180
|
.join(".")
|
|
142
181
|
|
|
182
|
+
const mapItemParam = (dialect: SQLDialect, value: unknown) =>
|
|
183
|
+
dialect.jsonColumnType === "JSONB" ? dialect.serializeJsonValue(value) : value
|
|
184
|
+
|
|
185
|
+
const mapPairParam = (dialect: SQLDialect, value: unknown) => {
|
|
186
|
+
const encoded = dialect.serializeJsonValue(value)
|
|
187
|
+
return typeof encoded === "string" ? encoded : JSON.stringify(value)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const sqlStringLiteral = (value: string) => `'${value.replaceAll("'", "''")}'`
|
|
191
|
+
|
|
143
192
|
export function buildWhereSQLQuery(
|
|
144
193
|
dialect: SQLDialect,
|
|
145
194
|
idKey: PropertyKey,
|
|
146
195
|
filter: readonly FilterResult[],
|
|
147
196
|
tableName: string,
|
|
148
197
|
defaultValues: Record<string, unknown>,
|
|
149
|
-
select?: NonEmptyReadonlyArray<
|
|
198
|
+
select?: NonEmptyReadonlyArray<
|
|
199
|
+
string | {
|
|
200
|
+
key: string
|
|
201
|
+
subKeys: readonly string[]
|
|
202
|
+
} | {
|
|
203
|
+
key: string
|
|
204
|
+
computed: ComputedProjectionIrExpression
|
|
205
|
+
} | {
|
|
206
|
+
key: string
|
|
207
|
+
path: string
|
|
208
|
+
} | {
|
|
209
|
+
key: string
|
|
210
|
+
aggregate: AggregateIrExpression
|
|
211
|
+
}
|
|
212
|
+
>,
|
|
150
213
|
order?: NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }>,
|
|
151
214
|
skip?: number,
|
|
152
|
-
limit?: number
|
|
215
|
+
limit?: number,
|
|
216
|
+
namespace?: string,
|
|
217
|
+
json?: JsonLower
|
|
153
218
|
) {
|
|
219
|
+
// defaultValues are already JSON-lowered at store construction; a second
|
|
220
|
+
// schema encode of an ISO Date string throws "Expected a valid Date".
|
|
221
|
+
filter = (json?.jsonifyFilter ?? jsonifyFilter)(filter)
|
|
154
222
|
const params: unknown[] = []
|
|
155
223
|
let paramIndex = 1
|
|
156
224
|
|
|
157
225
|
const addParam = (value: unknown): string => {
|
|
158
|
-
params.push(value)
|
|
226
|
+
params.push(dialect.serializeScalar(value))
|
|
159
227
|
return dialect.placeholder(paramIndex++)
|
|
160
228
|
}
|
|
161
229
|
|
|
@@ -188,7 +256,7 @@ export function buildWhereSQLQuery(
|
|
|
188
256
|
|
|
189
257
|
switch (x.op) {
|
|
190
258
|
case "in": {
|
|
191
|
-
const vals = x.value as
|
|
259
|
+
const vals = x.value as readonly unknown[]
|
|
192
260
|
const hasNull = vals.some((v) => v == null)
|
|
193
261
|
const nonNullVals = vals.filter((v) => v != null)
|
|
194
262
|
const parts: string[] = []
|
|
@@ -200,7 +268,7 @@ export function buildWhereSQLQuery(
|
|
|
200
268
|
return parts.length > 1 ? `(${parts.join(" OR ")})` : parts[0] ?? "1=0"
|
|
201
269
|
}
|
|
202
270
|
case "notIn": {
|
|
203
|
-
const vals = x.value as
|
|
271
|
+
const vals = x.value as readonly unknown[]
|
|
204
272
|
const hasNull = vals.some((v) => v == null)
|
|
205
273
|
const nonNullVals = vals.filter((v) => v != null)
|
|
206
274
|
const parts: string[] = []
|
|
@@ -225,30 +293,133 @@ export function buildWhereSQLQuery(
|
|
|
225
293
|
|
|
226
294
|
case "includes-any": {
|
|
227
295
|
const arrPath = dottedToJsonPath(resolvedPath)
|
|
228
|
-
const vals = x.value as
|
|
296
|
+
const vals = x.value as readonly unknown[]
|
|
229
297
|
const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
|
|
230
298
|
return dialect.jsonArrayContainsAny(arrPath, placeholders)
|
|
231
299
|
}
|
|
232
300
|
case "notIncludes-any": {
|
|
233
301
|
const arrPath = dottedToJsonPath(resolvedPath)
|
|
234
|
-
const vals = x.value as
|
|
302
|
+
const vals = x.value as readonly unknown[]
|
|
235
303
|
const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
|
|
236
304
|
return dialect.jsonArrayNotContainsAny(arrPath, placeholders)
|
|
237
305
|
}
|
|
238
306
|
|
|
239
307
|
case "includes-all": {
|
|
240
308
|
const arrPath = dottedToJsonPath(resolvedPath)
|
|
241
|
-
const vals = x.value as
|
|
309
|
+
const vals = x.value as readonly unknown[]
|
|
242
310
|
const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
|
|
243
311
|
return dialect.jsonArrayContainsAll(arrPath, placeholders)
|
|
244
312
|
}
|
|
245
313
|
case "notIncludes-all": {
|
|
246
314
|
const arrPath = dottedToJsonPath(resolvedPath)
|
|
247
|
-
const vals = x.value as
|
|
315
|
+
const vals = x.value as readonly unknown[]
|
|
248
316
|
const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
|
|
249
317
|
return dialect.jsonArrayNotContainsAll(arrPath, placeholders)
|
|
250
318
|
}
|
|
251
319
|
|
|
320
|
+
case "hasKey": {
|
|
321
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
322
|
+
const v = addParam(mapItemParam(dialect, x.value))
|
|
323
|
+
return dialect.jsonMapHasKey(arrPath, v)
|
|
324
|
+
}
|
|
325
|
+
case "notHasKey": {
|
|
326
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
327
|
+
const v = addParam(mapItemParam(dialect, x.value))
|
|
328
|
+
return `NOT (${dialect.jsonMapHasKey(arrPath, v)})`
|
|
329
|
+
}
|
|
330
|
+
case "hasValue": {
|
|
331
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
332
|
+
const v = addParam(mapItemParam(dialect, x.value))
|
|
333
|
+
return dialect.jsonMapHasValue(arrPath, v)
|
|
334
|
+
}
|
|
335
|
+
case "notHasValue": {
|
|
336
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
337
|
+
const v = addParam(mapItemParam(dialect, x.value))
|
|
338
|
+
return `NOT (${dialect.jsonMapHasValue(arrPath, v)})`
|
|
339
|
+
}
|
|
340
|
+
case "hasKeyValue": {
|
|
341
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
342
|
+
const v = addParam(mapPairParam(dialect, x.value))
|
|
343
|
+
return dialect.jsonMapHasPair(arrPath, v)
|
|
344
|
+
}
|
|
345
|
+
case "notHasKeyValue": {
|
|
346
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
347
|
+
const v = addParam(mapPairParam(dialect, x.value))
|
|
348
|
+
return `NOT (${dialect.jsonMapHasPair(arrPath, v)})`
|
|
349
|
+
}
|
|
350
|
+
case "hasKey-any": {
|
|
351
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
352
|
+
const vals = x.value as readonly unknown[]
|
|
353
|
+
const parts = vals.map((val) => dialect.jsonMapHasKey(arrPath, addParam(mapItemParam(dialect, val))))
|
|
354
|
+
return `(${parts.join(" OR ")})`
|
|
355
|
+
}
|
|
356
|
+
case "notHasKey-any": {
|
|
357
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
358
|
+
const vals = x.value as readonly unknown[]
|
|
359
|
+
const parts = vals.map((val) => dialect.jsonMapHasKey(arrPath, addParam(mapItemParam(dialect, val))))
|
|
360
|
+
return `NOT (${parts.join(" OR ")})`
|
|
361
|
+
}
|
|
362
|
+
case "hasKey-all": {
|
|
363
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
364
|
+
const vals = x.value as readonly unknown[]
|
|
365
|
+
return vals.map((val) => dialect.jsonMapHasKey(arrPath, addParam(mapItemParam(dialect, val)))).join(" AND ")
|
|
366
|
+
}
|
|
367
|
+
case "notHasKey-all": {
|
|
368
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
369
|
+
const vals = x.value as readonly unknown[]
|
|
370
|
+
return `NOT (${
|
|
371
|
+
vals.map((val) => dialect.jsonMapHasKey(arrPath, addParam(mapItemParam(dialect, val)))).join(" AND ")
|
|
372
|
+
})`
|
|
373
|
+
}
|
|
374
|
+
case "hasValue-any": {
|
|
375
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
376
|
+
const vals = x.value as readonly unknown[]
|
|
377
|
+
const parts = vals.map((val) => dialect.jsonMapHasValue(arrPath, addParam(mapItemParam(dialect, val))))
|
|
378
|
+
return `(${parts.join(" OR ")})`
|
|
379
|
+
}
|
|
380
|
+
case "notHasValue-any": {
|
|
381
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
382
|
+
const vals = x.value as readonly unknown[]
|
|
383
|
+
const parts = vals.map((val) => dialect.jsonMapHasValue(arrPath, addParam(mapItemParam(dialect, val))))
|
|
384
|
+
return `NOT (${parts.join(" OR ")})`
|
|
385
|
+
}
|
|
386
|
+
case "hasValue-all": {
|
|
387
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
388
|
+
const vals = x.value as readonly unknown[]
|
|
389
|
+
return vals.map((val) => dialect.jsonMapHasValue(arrPath, addParam(mapItemParam(dialect, val)))).join(" AND ")
|
|
390
|
+
}
|
|
391
|
+
case "notHasValue-all": {
|
|
392
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
393
|
+
const vals = x.value as readonly unknown[]
|
|
394
|
+
return `NOT (${
|
|
395
|
+
vals.map((val) => dialect.jsonMapHasValue(arrPath, addParam(mapItemParam(dialect, val)))).join(" AND ")
|
|
396
|
+
})`
|
|
397
|
+
}
|
|
398
|
+
case "hasKeyValue-any": {
|
|
399
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
400
|
+
const vals = x.value as readonly unknown[]
|
|
401
|
+
const parts = vals.map((val) => dialect.jsonMapHasPair(arrPath, addParam(mapPairParam(dialect, val))))
|
|
402
|
+
return `(${parts.join(" OR ")})`
|
|
403
|
+
}
|
|
404
|
+
case "notHasKeyValue-any": {
|
|
405
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
406
|
+
const vals = x.value as readonly unknown[]
|
|
407
|
+
const parts = vals.map((val) => dialect.jsonMapHasPair(arrPath, addParam(mapPairParam(dialect, val))))
|
|
408
|
+
return `NOT (${parts.join(" OR ")})`
|
|
409
|
+
}
|
|
410
|
+
case "hasKeyValue-all": {
|
|
411
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
412
|
+
const vals = x.value as readonly unknown[]
|
|
413
|
+
return vals.map((val) => dialect.jsonMapHasPair(arrPath, addParam(mapPairParam(dialect, val)))).join(" AND ")
|
|
414
|
+
}
|
|
415
|
+
case "notHasKeyValue-all": {
|
|
416
|
+
const arrPath = dottedToJsonPath(resolvedPath)
|
|
417
|
+
const vals = x.value as readonly unknown[]
|
|
418
|
+
return `NOT (${
|
|
419
|
+
vals.map((val) => dialect.jsonMapHasPair(arrPath, addParam(mapPairParam(dialect, val)))).join(" AND ")
|
|
420
|
+
})`
|
|
421
|
+
}
|
|
422
|
+
|
|
252
423
|
case "contains": {
|
|
253
424
|
const v = addParam(`%${x.value}%`)
|
|
254
425
|
return dialect.caseInsensitiveLike(k, v)
|
|
@@ -371,6 +542,136 @@ export function buildWhereSQLQuery(
|
|
|
371
542
|
return s
|
|
372
543
|
}
|
|
373
544
|
|
|
545
|
+
const computedSelectExpr = (key: string, computed: ComputedProjectionIrExpression): string => {
|
|
546
|
+
const relationPath = dottedToJsonPath(computed.path)
|
|
547
|
+
const relationAlias = `_${computed.path}`
|
|
548
|
+
const relationFrom = dialect.jsonEachFrom(relationPath, relationAlias)
|
|
549
|
+
const toNumber = (expr: string) =>
|
|
550
|
+
dialect.jsonColumnType === "JSON" ? `CAST(${expr} AS REAL)` : `(${expr})::numeric`
|
|
551
|
+
const compileExpr = (expression: ComputedProjectionMathIrExpression): string => {
|
|
552
|
+
switch (expression._tag) {
|
|
553
|
+
case "field":
|
|
554
|
+
return toNumber(dialect.jsonExtractElement(relationAlias, expression.field))
|
|
555
|
+
case "mul":
|
|
556
|
+
return `(${compileExpr(expression.left)} * ${compileExpr(expression.right)})`
|
|
557
|
+
default:
|
|
558
|
+
return assertUnreachable(expression)
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
const factorCaseExpr = (unitExpr: string, toBase: string, factors: Readonly<Record<string, number>>) => {
|
|
562
|
+
const entries = Object.entries(factors).filter(([, factor]) => Number.isFinite(factor))
|
|
563
|
+
const cases = entries.map(([unit, factor]) => ` WHEN ${sqlStringLiteral(unit)} THEN ${factor}`).join("")
|
|
564
|
+
return `CASE ${unitExpr} WHEN ${sqlStringLiteral(toBase)} THEN 1${cases} ELSE NULL END`
|
|
565
|
+
}
|
|
566
|
+
const filter = "filter" in computed ? computed.filter : []
|
|
567
|
+
const whereClause = () =>
|
|
568
|
+
filter.length > 0
|
|
569
|
+
? ` WHERE ${print(filter, computed.path, false)}`
|
|
570
|
+
: ""
|
|
571
|
+
const boolExpr = (sqlExpr: string) =>
|
|
572
|
+
dialect.jsonColumnType === "JSON"
|
|
573
|
+
? `CASE WHEN ${sqlExpr} THEN 'true' ELSE 'false' END AS "${key}"`
|
|
574
|
+
: `${sqlExpr} AS "${key}"`
|
|
575
|
+
switch (computed._tag) {
|
|
576
|
+
case "relation-count":
|
|
577
|
+
return `(SELECT COUNT(1) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
578
|
+
case "relation-any":
|
|
579
|
+
return boolExpr(`EXISTS(SELECT 1 FROM ${relationFrom}${whereClause()})`)
|
|
580
|
+
case "relation-every":
|
|
581
|
+
// ∀x.P(x) ≡ ¬∃x.¬P(x). When no filter, no element exists that violates ⊤ → true.
|
|
582
|
+
return boolExpr(
|
|
583
|
+
filter.length === 0
|
|
584
|
+
? `1=1`
|
|
585
|
+
: `NOT EXISTS(SELECT 1 FROM ${relationFrom} WHERE NOT (${print(filter, computed.path, false)}))`
|
|
586
|
+
)
|
|
587
|
+
case "relation-distinct-count": {
|
|
588
|
+
const fieldExtract = dialect.jsonExtractElement(relationAlias, computed.field)
|
|
589
|
+
return `(SELECT COUNT(DISTINCT ${fieldExtract}) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
590
|
+
}
|
|
591
|
+
case "relation-sum": {
|
|
592
|
+
const fieldExtract = dialect.jsonExtractElement(relationAlias, computed.field)
|
|
593
|
+
return `(SELECT COALESCE(SUM(${toNumber(fieldExtract)}), 0) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
594
|
+
}
|
|
595
|
+
case "relation-sum-expr": {
|
|
596
|
+
const expression = compileExpr(computed.expression)
|
|
597
|
+
return `(SELECT COALESCE(SUM(${expression}), 0) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
598
|
+
}
|
|
599
|
+
case "relation-sum-expr-by": {
|
|
600
|
+
const expression = compileExpr(computed.expression)
|
|
601
|
+
const unitExpr = dialect.jsonExtractElement(relationAlias, computed.unit)
|
|
602
|
+
if (dialect.jsonColumnType === "JSON") {
|
|
603
|
+
return `(SELECT COALESCE(json_group_array(json_object('unit', __unit, 'total', __total)), json_array()) FROM (SELECT ${unitExpr} AS __unit, COALESCE(SUM(${expression}), 0) AS __total FROM ${relationFrom}${whereClause()} GROUP BY ${unitExpr})) AS "${key}"`
|
|
604
|
+
}
|
|
605
|
+
return `(SELECT COALESCE(jsonb_agg(jsonb_build_object('unit', __unit, 'total', __total)), '[]'::jsonb) FROM (SELECT ${unitExpr} AS __unit, COALESCE(SUM(${expression}), 0) AS __total FROM ${relationFrom}${whereClause()} GROUP BY ${unitExpr}) __grouped) AS "${key}"`
|
|
606
|
+
}
|
|
607
|
+
case "relation-sum-expr-normalized": {
|
|
608
|
+
const expression = compileExpr(computed.expression)
|
|
609
|
+
const unitExpr = dialect.jsonExtractElement(relationAlias, computed.unit)
|
|
610
|
+
const factorExpr = factorCaseExpr(unitExpr, computed.toBase, computed.factors)
|
|
611
|
+
return `(SELECT COALESCE(SUM((${expression}) * (${factorExpr})), 0) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
612
|
+
}
|
|
613
|
+
case "relation-collect": {
|
|
614
|
+
const fieldExtract = dialect.jsonExtractElement(relationAlias, computed.field)
|
|
615
|
+
if (dialect.jsonColumnType === "JSON") {
|
|
616
|
+
// sqlite: json_group_array does not accept DISTINCT; emulate via inner DISTINCT subquery
|
|
617
|
+
if (computed.distinct) {
|
|
618
|
+
return `(SELECT COALESCE(json_group_array(__v), json_array()) FROM (SELECT DISTINCT ${fieldExtract} AS __v FROM ${relationFrom}${whereClause()})) AS "${key}"`
|
|
619
|
+
}
|
|
620
|
+
return `(SELECT COALESCE(json_group_array(${fieldExtract}), json_array()) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
621
|
+
}
|
|
622
|
+
const aggArg = computed.distinct ? `DISTINCT ${fieldExtract}` : fieldExtract
|
|
623
|
+
return `(SELECT COALESCE(jsonb_agg(${aggArg}), '[]'::jsonb) FROM ${relationFrom}${whereClause()}) AS "${key}"`
|
|
624
|
+
}
|
|
625
|
+
case "relation-length": {
|
|
626
|
+
const arrPath = dottedToJsonPath(computed.path)
|
|
627
|
+
return `${dialect.arrayLength(arrPath)} AS "${key}"`
|
|
628
|
+
}
|
|
629
|
+
case "relation-collect-fields": {
|
|
630
|
+
const branches = computed.fields.map((field) => {
|
|
631
|
+
const fieldExtract = dialect.jsonExtractElement(relationAlias, field)
|
|
632
|
+
return `SELECT ${fieldExtract} AS __v FROM ${relationFrom}${whereClause()}`
|
|
633
|
+
})
|
|
634
|
+
const unionQuery = branches.join(" UNION ALL ")
|
|
635
|
+
if (dialect.jsonColumnType === "JSON") {
|
|
636
|
+
if (computed.distinct) {
|
|
637
|
+
return `(SELECT COALESCE(json_group_array(__v), json_array()) FROM (SELECT DISTINCT __v FROM (${unionQuery}))) AS "${key}"`
|
|
638
|
+
}
|
|
639
|
+
return `(SELECT COALESCE(json_group_array(__v), json_array()) FROM (${unionQuery})) AS "${key}"`
|
|
640
|
+
}
|
|
641
|
+
if (computed.distinct) {
|
|
642
|
+
return `(SELECT COALESCE(jsonb_agg(__v), '[]'::jsonb) FROM (SELECT DISTINCT __v FROM (${unionQuery}) inner_q) outer_q) AS "${key}"`
|
|
643
|
+
}
|
|
644
|
+
return `(SELECT COALESCE(jsonb_agg(__v), '[]'::jsonb) FROM (${unionQuery}) t) AS "${key}"`
|
|
645
|
+
}
|
|
646
|
+
default:
|
|
647
|
+
return assertUnreachable(computed)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const aggregateSelectExpr = (key: string, agg: AggregateIrExpression): string => {
|
|
652
|
+
switch (agg._tag) {
|
|
653
|
+
case "agg-count":
|
|
654
|
+
return `COUNT(1) AS "${key}"`
|
|
655
|
+
case "agg-count-when": {
|
|
656
|
+
if (agg.filter.length === 0) return `COUNT(1) AS "${key}"`
|
|
657
|
+
const cond = print([{ t: "where-scope", result: agg.filter, relation: "some" }], null, false)
|
|
658
|
+
return `COUNT(CASE WHEN ${cond} THEN 1 END) AS "${key}"`
|
|
659
|
+
}
|
|
660
|
+
case "agg-sum":
|
|
661
|
+
return `COALESCE(SUM(${fieldExpr(agg.field)}), 0) AS "${key}"`
|
|
662
|
+
case "agg-min":
|
|
663
|
+
return `MIN(${fieldExpr(agg.field)}) AS "${key}"`
|
|
664
|
+
case "agg-max":
|
|
665
|
+
return `MAX(${fieldExpr(agg.field)}) AS "${key}"`
|
|
666
|
+
default:
|
|
667
|
+
return assertUnreachable(agg)
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const hasAggregates = select
|
|
672
|
+
? select.some((s) => typeof s === "object" && s !== null && "aggregate" in s)
|
|
673
|
+
: false
|
|
674
|
+
|
|
374
675
|
const getSelectExpr = (): string => {
|
|
375
676
|
if (!select) return "id, _etag, data"
|
|
376
677
|
const fields = select.map((s) => {
|
|
@@ -379,24 +680,69 @@ export function buildWhereSQLQuery(
|
|
|
379
680
|
if (s === "_etag") return `_etag`
|
|
380
681
|
return `${dialect.jsonExtractJson(s)} AS "${s}"`
|
|
381
682
|
}
|
|
683
|
+
if ("computed" in s) {
|
|
684
|
+
return computedSelectExpr(s.key, s.computed)
|
|
685
|
+
}
|
|
686
|
+
if ("aggregate" in s) {
|
|
687
|
+
return aggregateSelectExpr(s.key, s.aggregate)
|
|
688
|
+
}
|
|
689
|
+
if ("path" in s) {
|
|
690
|
+
// Group-by fields: extract as scalar (not JSON-encoded) so grouping works and values compare as plain strings/numbers
|
|
691
|
+
return `${fieldExpr(dottedToJsonPath(s.path))} AS "${s.key}"`
|
|
692
|
+
}
|
|
382
693
|
return `${dialect.jsonExtractJson(s.key)} AS "${s.key}"`
|
|
383
694
|
})
|
|
384
695
|
return fields.join(", ")
|
|
385
696
|
}
|
|
386
697
|
|
|
387
|
-
|
|
388
|
-
|
|
698
|
+
// Order matters: projection params must be emitted BEFORE user-filter
|
|
699
|
+
// params so positional `?` placeholders in SQLite match `params[]` order.
|
|
700
|
+
const selectExpr = getSelectExpr()
|
|
701
|
+
|
|
702
|
+
const namespaceClause = namespace !== undefined
|
|
703
|
+
? `_namespace = ${addParam(namespace)}`
|
|
704
|
+
: ""
|
|
705
|
+
const userWhere = filter.length
|
|
706
|
+
? print([{ t: "where-scope", result: filter, relation: "some" }], null, false)
|
|
707
|
+
: ""
|
|
708
|
+
const whereClause = namespaceClause && userWhere
|
|
709
|
+
? `WHERE ${namespaceClause} AND ${userWhere}`
|
|
710
|
+
: namespaceClause
|
|
711
|
+
? `WHERE ${namespaceClause}`
|
|
712
|
+
: userWhere
|
|
713
|
+
? `WHERE ${userWhere}`
|
|
714
|
+
: ""
|
|
715
|
+
|
|
716
|
+
const groupByClause = hasAggregates && select
|
|
717
|
+
? (() => {
|
|
718
|
+
const groupByExprs = select
|
|
719
|
+
.filter((s): s is string | { key: string; path: string } =>
|
|
720
|
+
typeof s === "string" || (typeof s === "object" && s !== null && "path" in s)
|
|
721
|
+
)
|
|
722
|
+
.map((s) => typeof s === "string" ? fieldExpr(s) : fieldExpr(dottedToJsonPath(s.path)))
|
|
723
|
+
return groupByExprs.length > 0 ? `GROUP BY ${groupByExprs.join(", ")}` : ""
|
|
724
|
+
})()
|
|
389
725
|
: ""
|
|
390
726
|
|
|
391
727
|
const orderClause = order
|
|
392
|
-
? `ORDER BY ${
|
|
728
|
+
? `ORDER BY ${
|
|
729
|
+
order
|
|
730
|
+
.map((_) =>
|
|
731
|
+
hasAggregates
|
|
732
|
+
? `"${_.key}" ${_.direction}`
|
|
733
|
+
: `${fieldExpr(_.key)} ${_.direction}`
|
|
734
|
+
)
|
|
735
|
+
.join(", ")
|
|
736
|
+
}`
|
|
393
737
|
: ""
|
|
394
738
|
|
|
395
739
|
const limitClause = limit !== undefined || skip !== undefined
|
|
396
740
|
? `LIMIT ${addParam(limit ?? 999999)} OFFSET ${addParam(skip ?? 0)}`
|
|
397
741
|
: ""
|
|
398
742
|
|
|
399
|
-
const sql = `SELECT ${
|
|
743
|
+
const sql = `SELECT ${selectExpr} FROM "${tableName}" ${whereClause} ${groupByClause} ${orderClause} ${limitClause}`
|
|
744
|
+
.replace(/\s+/g, " ")
|
|
745
|
+
.trim()
|
|
400
746
|
|
|
401
747
|
return { sql, params }
|
|
402
748
|
}
|