@effect-app/infra 4.0.0-beta.33 → 4.0.0-beta.331

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (490) hide show
  1. package/CHANGELOG.md +2562 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +29 -10
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +36 -15
  6. package/dist/ClusterCosmos.d.ts +64 -0
  7. package/dist/ClusterCosmos.d.ts.map +1 -0
  8. package/dist/ClusterCosmos.js +576 -0
  9. package/dist/ClusterServiceBus.d.ts +67 -0
  10. package/dist/ClusterServiceBus.d.ts.map +1 -0
  11. package/dist/ClusterServiceBus.js +84 -0
  12. package/dist/ContextProvider.d.ts +34 -0
  13. package/dist/ContextProvider.d.ts.map +1 -0
  14. package/dist/ContextProvider.js +40 -0
  15. package/dist/Emailer/Sendgrid.d.ts +110 -146
  16. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  17. package/dist/Emailer/Sendgrid.js +24 -19
  18. package/dist/Emailer/fake.d.ts +1 -1
  19. package/dist/Emailer/fake.d.ts.map +1 -1
  20. package/dist/Emailer/fake.js +4 -4
  21. package/dist/MainFiberSet.d.ts +12 -8
  22. package/dist/MainFiberSet.d.ts.map +1 -1
  23. package/dist/MainFiberSet.js +23 -7
  24. package/dist/QueueMaker/errors.d.ts +4 -2
  25. package/dist/QueueMaker/errors.d.ts.map +1 -1
  26. package/dist/QueueMaker/errors.js +4 -2
  27. package/dist/{adapters/SQL → SQL}/Model.d.ts +31 -42
  28. package/dist/SQL/Model.d.ts.map +1 -0
  29. package/dist/SQL/Model.js +469 -0
  30. package/dist/SQL.d.ts.map +1 -0
  31. package/dist/{adapters/SQL.js → SQL.js} +1 -1
  32. package/dist/Store/Cosmos/query.d.ts +16 -4
  33. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  34. package/dist/Store/Cosmos/query.js +238 -42
  35. package/dist/Store/Cosmos.d.ts +2 -2
  36. package/dist/Store/Cosmos.d.ts.map +1 -1
  37. package/dist/Store/Cosmos.js +395 -256
  38. package/dist/Store/Disk.d.ts +4 -4
  39. package/dist/Store/Disk.d.ts.map +1 -1
  40. package/dist/Store/Disk.js +93 -42
  41. package/dist/Store/Memory.d.ts +7 -10
  42. package/dist/Store/Memory.d.ts.map +1 -1
  43. package/dist/Store/Memory.js +349 -79
  44. package/dist/Store/SQL/Pg.d.ts +4 -0
  45. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  46. package/dist/Store/SQL/Pg.js +261 -0
  47. package/dist/Store/SQL/query.d.ts +53 -0
  48. package/dist/Store/SQL/query.d.ts.map +1 -0
  49. package/dist/Store/SQL/query.js +656 -0
  50. package/dist/Store/SQL.d.ts +28 -0
  51. package/dist/Store/SQL.d.ts.map +1 -0
  52. package/dist/Store/SQL.js +483 -0
  53. package/dist/Store/codeFilter.d.ts +4 -4
  54. package/dist/Store/codeFilter.d.ts.map +1 -1
  55. package/dist/Store/codeFilter.js +71 -22
  56. package/dist/Store/index.d.ts +6 -4
  57. package/dist/Store/index.d.ts.map +1 -1
  58. package/dist/Store/index.js +18 -5
  59. package/dist/Store/jsonDocument.d.ts +67 -0
  60. package/dist/Store/jsonDocument.d.ts.map +1 -0
  61. package/dist/Store/jsonDocument.js +107 -0
  62. package/dist/Store/utils.d.ts +21 -2
  63. package/dist/Store/utils.d.ts.map +1 -1
  64. package/dist/Store/utils.js +253 -10
  65. package/dist/WorkflowEngineCosmos.d.ts +30 -0
  66. package/dist/WorkflowEngineCosmos.d.ts.map +1 -0
  67. package/dist/WorkflowEngineCosmos.js +542 -0
  68. package/dist/WorkflowEngineSqlite.d.ts +24 -0
  69. package/dist/WorkflowEngineSqlite.d.ts.map +1 -0
  70. package/dist/WorkflowEngineSqlite.js +550 -0
  71. package/dist/arbs.d.ts +6 -3
  72. package/dist/arbs.d.ts.map +1 -1
  73. package/dist/arbs.js +20 -4
  74. package/dist/codec.d.ts.map +1 -0
  75. package/dist/codec.js +5 -0
  76. package/dist/cosmos-client.d.ts +40 -0
  77. package/dist/cosmos-client.d.ts.map +1 -0
  78. package/dist/cosmos-client.js +41 -0
  79. package/dist/errorReporter.d.ts +6 -4
  80. package/dist/errorReporter.d.ts.map +1 -1
  81. package/dist/errorReporter.js +23 -27
  82. package/dist/fileUtil.d.ts +1 -1
  83. package/dist/fileUtil.d.ts.map +1 -1
  84. package/dist/fileUtil.js +2 -2
  85. package/dist/index.d.ts +2 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +3 -2
  88. package/dist/internal/RequestContextMiddleware.d.ts +5 -0
  89. package/dist/internal/RequestContextMiddleware.d.ts.map +1 -0
  90. package/dist/internal/RequestContextMiddleware.js +45 -0
  91. package/dist/internal/auth.d.ts +53 -0
  92. package/dist/internal/auth.d.ts.map +1 -0
  93. package/dist/internal/auth.js +180 -0
  94. package/dist/internal/events.d.ts +11 -0
  95. package/dist/internal/events.d.ts.map +1 -0
  96. package/dist/internal/events.js +49 -0
  97. package/dist/internal/health.d.ts.map +1 -0
  98. package/dist/internal/health.js +5 -0
  99. package/dist/{api/layerUtils.d.ts → layerUtils.d.ts} +14 -6
  100. package/dist/layerUtils.d.ts.map +1 -0
  101. package/dist/layerUtils.js +17 -0
  102. package/dist/logger/jsonLogger.d.ts +1 -1
  103. package/dist/logger/jsonLogger.d.ts.map +1 -1
  104. package/dist/logger/jsonLogger.js +5 -3
  105. package/dist/logger/logFmtLogger.d.ts +1 -1
  106. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  107. package/dist/logger/logFmtLogger.js +3 -3
  108. package/dist/logger/shared.d.ts +2 -2
  109. package/dist/logger/shared.d.ts.map +1 -1
  110. package/dist/logger/shared.js +6 -6
  111. package/dist/logger.d.ts +4 -4
  112. package/dist/logger.d.ts.map +1 -1
  113. package/dist/middlewares.d.ts.map +1 -0
  114. package/dist/{api/middlewares.js → middlewares.js} +1 -1
  115. package/dist/{adapters/mongo-client.d.ts → mongo-client.d.ts} +3 -2
  116. package/dist/mongo-client.d.ts.map +1 -0
  117. package/dist/mongo-client.js +15 -0
  118. package/dist/otel.d.ts +75 -0
  119. package/dist/otel.d.ts.map +1 -0
  120. package/dist/otel.js +84 -0
  121. package/dist/rateLimit.d.ts +11 -3
  122. package/dist/rateLimit.d.ts.map +1 -1
  123. package/dist/rateLimit.js +7 -12
  124. package/dist/{adapters/redis-client.d.ts → redis-client.d.ts} +5 -2
  125. package/dist/redis-client.d.ts.map +1 -0
  126. package/dist/redis-client.js +98 -0
  127. package/dist/{api/reportError.d.ts → reportError.d.ts} +1 -1
  128. package/dist/reportError.d.ts.map +1 -0
  129. package/dist/reportError.js +28 -0
  130. package/dist/{api/routing → routing}/middleware/RouterMiddleware.d.ts +4 -3
  131. package/dist/routing/middleware/RouterMiddleware.d.ts.map +1 -0
  132. package/dist/{api/routing → routing}/middleware/RouterMiddleware.js +1 -1
  133. package/dist/routing/middleware/middleware.d.ts +48 -0
  134. package/dist/routing/middleware/middleware.d.ts.map +1 -0
  135. package/dist/routing/middleware/middleware.js +152 -0
  136. package/dist/{api/routing → routing}/middleware.d.ts +0 -1
  137. package/dist/routing/middleware.d.ts.map +1 -0
  138. package/dist/{api/routing → routing}/middleware.js +1 -2
  139. package/dist/routing/schema/jwt.d.ts.map +1 -0
  140. package/dist/routing/schema/jwt.js +12 -0
  141. package/dist/routing/tsort.d.ts.map +1 -0
  142. package/dist/routing/tsort.js +51 -0
  143. package/dist/{api/routing → routing}/utils.d.ts +3 -3
  144. package/dist/routing/utils.d.ts.map +1 -0
  145. package/dist/routing/utils.js +45 -0
  146. package/dist/routing.d.ts +182 -0
  147. package/dist/routing.d.ts.map +1 -0
  148. package/dist/routing.js +256 -0
  149. package/dist/test.d.ts +2 -2
  150. package/dist/test.d.ts.map +1 -1
  151. package/dist/test.js +5 -5
  152. package/dist/util.d.ts.map +1 -0
  153. package/dist/util.js +14 -0
  154. package/docs/cluster-storage.md +26 -0
  155. package/docs/workflow-engine.md +262 -0
  156. package/examples/query.ts +25 -21
  157. package/package.json +38 -352
  158. package/src/CUPS.ts +54 -15
  159. package/src/ClusterCosmos.ts +1150 -0
  160. package/src/ClusterServiceBus.ts +244 -0
  161. package/src/{api/ContextProvider.ts → ContextProvider.ts} +20 -17
  162. package/src/Emailer/Sendgrid.ts +83 -60
  163. package/src/Emailer/fake.ts +4 -4
  164. package/src/MainFiberSet.ts +32 -13
  165. package/src/QueueMaker/errors.ts +3 -1
  166. package/src/{adapters/SQL → SQL}/Model.ts +42 -41
  167. package/src/SQL.ts +1 -0
  168. package/src/Store/Cosmos/query.ts +275 -55
  169. package/src/Store/Cosmos.ts +547 -366
  170. package/src/Store/Disk.ts +146 -73
  171. package/src/Store/Memory.ts +420 -115
  172. package/src/Store/SQL/Pg.ts +412 -0
  173. package/src/Store/SQL/query.ts +748 -0
  174. package/src/Store/SQL.ts +806 -0
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +25 -10
  177. package/src/Store/jsonDocument.ts +143 -0
  178. package/src/Store/utils.ts +307 -30
  179. package/src/WorkflowEngineCosmos.ts +749 -0
  180. package/src/WorkflowEngineSqlite.ts +813 -0
  181. package/src/arbs.ts +25 -5
  182. package/src/cosmos-client.ts +72 -0
  183. package/src/errorReporter.ts +68 -78
  184. package/src/fileUtil.ts +1 -1
  185. package/src/index.ts +2 -1
  186. package/src/{api/internal → internal}/RequestContextMiddleware.ts +23 -6
  187. package/src/internal/auth.ts +272 -0
  188. package/src/{api/internal → internal}/events.ts +22 -13
  189. package/src/{api/layerUtils.ts → layerUtils.ts} +14 -10
  190. package/src/logger/jsonLogger.ts +5 -3
  191. package/src/logger/logFmtLogger.ts +3 -3
  192. package/src/logger/shared.ts +6 -5
  193. package/src/middlewares.ts +10 -0
  194. package/src/{adapters/mongo-client.ts → mongo-client.ts} +4 -2
  195. package/src/otel.ts +177 -0
  196. package/src/rateLimit.ts +35 -24
  197. package/src/{adapters/redis-client.ts → redis-client.ts} +7 -3
  198. package/src/{api/reportError.ts → reportError.ts} +3 -2
  199. package/src/{api/routing → routing}/middleware/RouterMiddleware.ts +5 -4
  200. package/src/routing/middleware/middleware.ts +196 -0
  201. package/src/routing/middleware.ts +4 -0
  202. package/src/{api/routing → routing}/schema/jwt.ts +2 -2
  203. package/src/{api/routing → routing}/utils.ts +2 -1
  204. package/src/routing.ts +823 -0
  205. package/src/test.ts +6 -6
  206. package/src/vitest.ts +1 -1
  207. package/test/arbs-magnitude.test.ts +33 -0
  208. package/test/arbs.test.ts +41 -0
  209. package/test/auth.test.ts +101 -0
  210. package/test/cluster-cosmos.test.ts +612 -0
  211. package/test/cluster-servicebus.test.ts +180 -0
  212. package/test/cluster-sqlite.test.ts +207 -0
  213. package/test/contextProvider.test.ts +15 -12
  214. package/test/controller.test.ts +27 -31
  215. package/test/cosmos-container-throughput.test.ts +80 -0
  216. package/test/cosmos-query.test.ts +368 -0
  217. package/test/dist/arbs-magnitude.test.d.ts.map +1 -0
  218. package/test/dist/arbs.test.d.ts.map +1 -0
  219. package/test/dist/auth.test.d.ts.map +1 -0
  220. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  221. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  222. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  223. package/test/dist/contextProvider.test.d.ts.map +1 -1
  224. package/test/dist/controller.test.d.ts.map +1 -1
  225. package/test/dist/cosmos-container-throughput.test.d.ts.map +1 -0
  226. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  227. package/test/dist/fixtures.d.ts +29 -11
  228. package/test/dist/fixtures.d.ts.map +1 -1
  229. package/test/dist/fixtures.js +17 -10
  230. package/test/dist/json-lower.test.d.ts.map +1 -0
  231. package/test/dist/query.test.d.ts.map +1 -1
  232. package/test/dist/rawQuery.test.d.ts.map +1 -1
  233. package/test/dist/repository-ext.test.d.ts.map +1 -0
  234. package/test/dist/repository-legacy-document.test.d.ts.map +1 -0
  235. package/test/dist/requires.test.d.ts.map +1 -1
  236. package/test/dist/router-generator.test.d.ts.map +1 -0
  237. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  238. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  239. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  240. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  241. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  242. package/test/dist/sql-store.test.d.ts.map +1 -0
  243. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  244. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  245. package/test/fixtures.ts +16 -9
  246. package/test/json-lower.test.ts +129 -0
  247. package/test/layerUtils.test.ts +2 -2
  248. package/test/query.test.ts +1382 -44
  249. package/test/rawQuery.test.ts +433 -8
  250. package/test/repository-ext.test.ts +456 -0
  251. package/test/repository-legacy-document.test.ts +394 -0
  252. package/test/requires.test.ts +10 -5
  253. package/test/router-generator.test.ts +187 -0
  254. package/test/routing-interruptibility.test.ts +66 -0
  255. package/test/rpc-context-map-streaming.test.ts +265 -0
  256. package/test/rpc-e2e-invalidation.test.ts +421 -0
  257. package/test/rpc-multi-middleware.test.ts +85 -10
  258. package/test/rpc-stream-fullstack.test.ts +307 -0
  259. package/test/sql-store.test.ts +1931 -0
  260. package/test/validateSample.test.ts +71 -43
  261. package/test/workflow-engine-cosmos.test.ts +345 -0
  262. package/test/workflow-engine-sqlite.test.ts +297 -0
  263. package/tsconfig.examples.json +1 -1
  264. package/tsconfig.json +9 -2
  265. package/tsconfig.src.json +35 -35
  266. package/tsconfig.test.json +2 -2
  267. package/dist/Emailer/service.d.ts +0 -55
  268. package/dist/Emailer/service.d.ts.map +0 -1
  269. package/dist/Emailer/service.js +0 -6
  270. package/dist/Emailer.d.ts +0 -2
  271. package/dist/Emailer.d.ts.map +0 -1
  272. package/dist/Emailer.js +0 -2
  273. package/dist/Model/Repository/ext.d.ts +0 -41
  274. package/dist/Model/Repository/ext.d.ts.map +0 -1
  275. package/dist/Model/Repository/ext.js +0 -65
  276. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  277. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  278. package/dist/Model/Repository/internal/internal.js +0 -316
  279. package/dist/Model/Repository/legacy.d.ts +0 -19
  280. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  281. package/dist/Model/Repository/legacy.js +0 -2
  282. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  283. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  284. package/dist/Model/Repository/makeRepo.js +0 -24
  285. package/dist/Model/Repository/service.d.ts +0 -89
  286. package/dist/Model/Repository/service.d.ts.map +0 -1
  287. package/dist/Model/Repository/service.js +0 -2
  288. package/dist/Model/Repository/validation.d.ts +0 -42
  289. package/dist/Model/Repository/validation.d.ts.map +0 -1
  290. package/dist/Model/Repository/validation.js +0 -32
  291. package/dist/Model/Repository.d.ts +0 -6
  292. package/dist/Model/Repository.d.ts.map +0 -1
  293. package/dist/Model/Repository.js +0 -6
  294. package/dist/Model/dsl.d.ts +0 -32
  295. package/dist/Model/dsl.d.ts.map +0 -1
  296. package/dist/Model/dsl.js +0 -44
  297. package/dist/Model/filter/filterApi.d.ts +0 -30
  298. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  299. package/dist/Model/filter/filterApi.js +0 -2
  300. package/dist/Model/filter/types/errors.d.ts +0 -29
  301. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  302. package/dist/Model/filter/types/errors.js +0 -2
  303. package/dist/Model/filter/types/fields.d.ts +0 -15
  304. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  305. package/dist/Model/filter/types/fields.js +0 -2
  306. package/dist/Model/filter/types/path/common.d.ts +0 -316
  307. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  308. package/dist/Model/filter/types/path/common.js +0 -2
  309. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  310. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  311. package/dist/Model/filter/types/path/eager.js +0 -31
  312. package/dist/Model/filter/types/path/index.d.ts +0 -4
  313. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  314. package/dist/Model/filter/types/path/index.js +0 -3
  315. package/dist/Model/filter/types/utils.d.ts +0 -79
  316. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  317. package/dist/Model/filter/types/utils.js +0 -2
  318. package/dist/Model/filter/types/validator.d.ts +0 -30
  319. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  320. package/dist/Model/filter/types/validator.js +0 -2
  321. package/dist/Model/filter/types.d.ts +0 -5
  322. package/dist/Model/filter/types.d.ts.map +0 -1
  323. package/dist/Model/filter/types.js +0 -7
  324. package/dist/Model/query/dsl.d.ts +0 -248
  325. package/dist/Model/query/dsl.d.ts.map +0 -1
  326. package/dist/Model/query/dsl.js +0 -104
  327. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  328. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  329. package/dist/Model/query/new-kid-interpreter.js +0 -165
  330. package/dist/Model/query.d.ts +0 -15
  331. package/dist/Model/query.d.ts.map +0 -1
  332. package/dist/Model/query.js +0 -3
  333. package/dist/Model.d.ts +0 -4
  334. package/dist/Model.d.ts.map +0 -1
  335. package/dist/Model.js +0 -4
  336. package/dist/Operations.d.ts +0 -55
  337. package/dist/Operations.d.ts.map +0 -1
  338. package/dist/Operations.js +0 -102
  339. package/dist/OperationsRepo.d.ts +0 -41
  340. package/dist/OperationsRepo.d.ts.map +0 -1
  341. package/dist/OperationsRepo.js +0 -14
  342. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  343. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  344. package/dist/QueueMaker/SQLQueue.js +0 -130
  345. package/dist/QueueMaker/memQueue.d.ts +0 -11
  346. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  347. package/dist/QueueMaker/memQueue.js +0 -76
  348. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  349. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  350. package/dist/QueueMaker/sbqueue.js +0 -91
  351. package/dist/QueueMaker/service.d.ts +0 -11
  352. package/dist/QueueMaker/service.d.ts.map +0 -1
  353. package/dist/QueueMaker/service.js +0 -4
  354. package/dist/RequestContext.d.ts +0 -63
  355. package/dist/RequestContext.d.ts.map +0 -1
  356. package/dist/RequestContext.js +0 -49
  357. package/dist/RequestFiberSet.d.ts +0 -36
  358. package/dist/RequestFiberSet.d.ts.map +0 -1
  359. package/dist/RequestFiberSet.js +0 -78
  360. package/dist/Store/ContextMapContainer.d.ts +0 -14
  361. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  362. package/dist/Store/ContextMapContainer.js +0 -16
  363. package/dist/Store/service.d.ts +0 -108
  364. package/dist/Store/service.d.ts.map +0 -1
  365. package/dist/Store/service.js +0 -71
  366. package/dist/Store.d.ts +0 -2
  367. package/dist/Store.d.ts.map +0 -1
  368. package/dist/Store.js +0 -2
  369. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  370. package/dist/adapters/SQL/Model.js +0 -478
  371. package/dist/adapters/SQL.d.ts.map +0 -1
  372. package/dist/adapters/ServiceBus.d.ts +0 -58
  373. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  374. package/dist/adapters/ServiceBus.js +0 -99
  375. package/dist/adapters/cosmos-client.d.ts +0 -14
  376. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  377. package/dist/adapters/cosmos-client.js +0 -9
  378. package/dist/adapters/index.d.ts +0 -2
  379. package/dist/adapters/index.d.ts.map +0 -1
  380. package/dist/adapters/index.js +0 -2
  381. package/dist/adapters/logger.d.ts +0 -9
  382. package/dist/adapters/logger.d.ts.map +0 -1
  383. package/dist/adapters/logger.js +0 -3
  384. package/dist/adapters/memQueue.d.ts +0 -13
  385. package/dist/adapters/memQueue.d.ts.map +0 -1
  386. package/dist/adapters/memQueue.js +0 -20
  387. package/dist/adapters/mongo-client.d.ts.map +0 -1
  388. package/dist/adapters/mongo-client.js +0 -13
  389. package/dist/adapters/redis-client.d.ts.map +0 -1
  390. package/dist/adapters/redis-client.js +0 -94
  391. package/dist/api/ContextProvider.d.ts +0 -31
  392. package/dist/api/ContextProvider.d.ts.map +0 -1
  393. package/dist/api/ContextProvider.js +0 -38
  394. package/dist/api/codec.d.ts.map +0 -1
  395. package/dist/api/codec.js +0 -5
  396. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  397. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  398. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  399. package/dist/api/internal/auth.d.ts +0 -15
  400. package/dist/api/internal/auth.d.ts.map +0 -1
  401. package/dist/api/internal/auth.js +0 -47
  402. package/dist/api/internal/events.d.ts +0 -9
  403. package/dist/api/internal/events.d.ts.map +0 -1
  404. package/dist/api/internal/events.js +0 -42
  405. package/dist/api/internal/health.d.ts.map +0 -1
  406. package/dist/api/internal/health.js +0 -5
  407. package/dist/api/layerUtils.d.ts.map +0 -1
  408. package/dist/api/layerUtils.js +0 -16
  409. package/dist/api/middlewares.d.ts.map +0 -1
  410. package/dist/api/reportError.d.ts.map +0 -1
  411. package/dist/api/reportError.js +0 -27
  412. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  413. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  414. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  415. package/dist/api/routing/middleware/middleware.js +0 -92
  416. package/dist/api/routing/middleware.d.ts.map +0 -1
  417. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  418. package/dist/api/routing/schema/jwt.js +0 -12
  419. package/dist/api/routing/tsort.d.ts.map +0 -1
  420. package/dist/api/routing/tsort.js +0 -51
  421. package/dist/api/routing/utils.d.ts.map +0 -1
  422. package/dist/api/routing/utils.js +0 -44
  423. package/dist/api/routing.d.ts +0 -138
  424. package/dist/api/routing.d.ts.map +0 -1
  425. package/dist/api/routing.js +0 -166
  426. package/dist/api/setupRequest.d.ts +0 -12
  427. package/dist/api/setupRequest.d.ts.map +0 -1
  428. package/dist/api/setupRequest.js +0 -44
  429. package/dist/api/util.d.ts.map +0 -1
  430. package/dist/api/util.js +0 -14
  431. package/eslint.config.mjs +0 -24
  432. package/src/Emailer/service.ts +0 -52
  433. package/src/Emailer.ts +0 -1
  434. package/src/Model/Repository/ext.ts +0 -283
  435. package/src/Model/Repository/internal/internal.ts +0 -577
  436. package/src/Model/Repository/legacy.ts +0 -27
  437. package/src/Model/Repository/makeRepo.ts +0 -139
  438. package/src/Model/Repository/service.ts +0 -627
  439. package/src/Model/Repository/validation.ts +0 -31
  440. package/src/Model/Repository.ts +0 -5
  441. package/src/Model/dsl.ts +0 -128
  442. package/src/Model/filter/filterApi.ts +0 -60
  443. package/src/Model/filter/types/errors.ts +0 -47
  444. package/src/Model/filter/types/fields.ts +0 -50
  445. package/src/Model/filter/types/path/common.ts +0 -404
  446. package/src/Model/filter/types/path/eager.ts +0 -298
  447. package/src/Model/filter/types/path/index.ts +0 -4
  448. package/src/Model/filter/types/utils.ts +0 -128
  449. package/src/Model/filter/types/validator.ts +0 -46
  450. package/src/Model/filter/types.ts +0 -6
  451. package/src/Model/query/dsl.ts +0 -2110
  452. package/src/Model/query/new-kid-interpreter.ts +0 -210
  453. package/src/Model/query.ts +0 -13
  454. package/src/Model.ts +0 -3
  455. package/src/Operations.ts +0 -235
  456. package/src/OperationsRepo.ts +0 -16
  457. package/src/QueueMaker/SQLQueue.ts +0 -189
  458. package/src/QueueMaker/memQueue.ts +0 -130
  459. package/src/QueueMaker/sbqueue.ts +0 -137
  460. package/src/QueueMaker/service.ts +0 -17
  461. package/src/RequestContext.ts +0 -63
  462. package/src/RequestFiberSet.ts +0 -105
  463. package/src/Store/ContextMapContainer.ts +0 -20
  464. package/src/Store/index.test.ts.bak +0 -112
  465. package/src/Store/service.ts +0 -184
  466. package/src/Store.ts +0 -1
  467. package/src/adapters/SQL.ts +0 -1
  468. package/src/adapters/ServiceBus.ts +0 -209
  469. package/src/adapters/cosmos-client.ts +0 -16
  470. package/src/adapters/index.ts +0 -0
  471. package/src/adapters/logger.ts +0 -3
  472. package/src/adapters/memQueue.ts +0 -21
  473. package/src/api/internal/auth.ts +0 -68
  474. package/src/api/middlewares.ts +0 -10
  475. package/src/api/routing/middleware/middleware.ts +0 -128
  476. package/src/api/routing/middleware.ts +0 -6
  477. package/src/api/routing.ts +0 -598
  478. package/src/api/setupRequest.ts +0 -84
  479. package/tsconfig.json.bak +0 -12
  480. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  481. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  482. /package/dist/{api/internal → internal}/health.d.ts +0 -0
  483. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  484. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  485. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  486. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  487. /package/src/{api/codec.ts → codec.ts} +0 -0
  488. /package/src/{api/internal → internal}/health.ts +0 -0
  489. /package/src/{api/routing → routing}/tsort.ts +0 -0
  490. /package/src/{api/util.ts → util.ts} +0 -0
@@ -0,0 +1,748 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
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"
6
+ import { assertUnreachable } from "effect-app/utils"
7
+ import { InfraLogger } from "../../logger.ts"
8
+ import { isRelationCheck } from "../codeFilter.ts"
9
+ import { jsonifyFilter, type JsonLower } from "../utils.ts"
10
+
11
+ export interface SQLDialect {
12
+ readonly jsonExtract: (path: string) => string
13
+ readonly jsonExtractJson: (path: string) => string
14
+ readonly placeholder: (index: number) => string
15
+ readonly jsonArrayContains: (arrPath: string, valPlaceholder: string) => string
16
+ readonly jsonArrayNotContains: (arrPath: string, valPlaceholder: string) => string
17
+ readonly jsonArrayContainsAny: (arrPath: string, valPlaceholders: readonly string[]) => string
18
+ readonly jsonArrayNotContainsAny: (arrPath: string, valPlaceholders: readonly string[]) => string
19
+ readonly jsonArrayContainsAll: (arrPath: string, valPlaceholders: readonly string[]) => string
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
24
+ readonly caseInsensitiveLike: (expr: string, valPlaceholder: string) => string
25
+ readonly caseInsensitiveNotLike: (expr: string, valPlaceholder: string) => string
26
+ readonly jsonColumnType: "JSON" | "JSONB"
27
+ readonly arrayLength: (path: string) => string
28
+ readonly jsonEachFrom: (arrPath: string, alias: string) => string
29
+ readonly jsonExtractElement: (alias: string, subPath: string) => string
30
+ readonly serializeJsonValue: (v: unknown) => unknown
31
+ readonly serializeScalar: (v: unknown) => unknown
32
+ }
33
+
34
+ export const sqliteDialect: SQLDialect = {
35
+ jsonExtract: (path) => `json_extract(data, '$.${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`,
38
+ placeholder: (_index) => "?",
39
+ jsonArrayContains: (arrPath, val) => `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${val})`,
40
+ jsonArrayNotContains: (arrPath, val) =>
41
+ `NOT EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${val})`,
42
+ jsonArrayContainsAny: (arrPath, vals) =>
43
+ `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value IN (${vals.join(", ")}))`,
44
+ jsonArrayNotContainsAny: (arrPath, vals) =>
45
+ `NOT EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value IN (${vals.join(", ")}))`,
46
+ jsonArrayContainsAll: (arrPath, vals) =>
47
+ vals.map((v) => `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${v})`).join(" AND "),
48
+ jsonArrayNotContainsAll: (arrPath, vals) =>
49
+ `NOT (${
50
+ vals.map((v) => `EXISTS(SELECT 1 FROM json_each(data, '$.${arrPath}') WHERE value = ${v})`).join(" AND ")
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})`,
57
+ caseInsensitiveLike: (expr, val) => `LOWER(${expr}) LIKE LOWER(${val})`,
58
+ caseInsensitiveNotLike: (expr, val) => `LOWER(${expr}) NOT LIKE LOWER(${val})`,
59
+ jsonColumnType: "JSON",
60
+ arrayLength: (path) => `json_array_length(data, '$.${path}')`,
61
+ jsonEachFrom: (arrPath, alias) => `json_each(data, '$.${arrPath}') AS ${alias}`,
62
+ jsonExtractElement: (alias, subPath) => `json_extract(${alias}.value, '$.${subPath}')`,
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
67
+ }
68
+
69
+ export const pgDialect: SQLDialect = {
70
+ jsonExtract: (path) => {
71
+ const parts = path.split(".")
72
+ if (parts.length === 1) return `data->>'${parts[0]}'`
73
+ const last = parts.pop()!
74
+ return `data${parts.map((p) => `->'${p}'`).join("")}->>'${last}'`
75
+ },
76
+ jsonExtractJson: (path) => {
77
+ const parts = path.split(".")
78
+ if (parts.length === 1) return `data->'${parts[0]}'`
79
+ return `data${parts.map((p) => `->'${p}'`).join("")}`
80
+ },
81
+ placeholder: (index) => `$${index}`,
82
+ jsonArrayContains: (arrPath, val) => {
83
+ const parts = arrPath.split(".")
84
+ const jsonPath = parts.length === 1
85
+ ? `data->'${parts[0]}'`
86
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
87
+ return `${jsonPath} @> ${val}::jsonb`
88
+ },
89
+ jsonArrayNotContains: (arrPath, val) => {
90
+ const parts = arrPath.split(".")
91
+ const jsonPath = parts.length === 1
92
+ ? `data->'${parts[0]}'`
93
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
94
+ return `NOT (${jsonPath} @> ${val}::jsonb)`
95
+ },
96
+ jsonArrayContainsAny: (arrPath, vals) => {
97
+ const parts = arrPath.split(".")
98
+ const jsonPath = parts.length === 1
99
+ ? `data->'${parts[0]}'`
100
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
101
+ return `(${vals.map((v) => `${jsonPath} @> ${v}::jsonb`).join(" OR ")})`
102
+ },
103
+ jsonArrayNotContainsAny: (arrPath, vals) => {
104
+ const parts = arrPath.split(".")
105
+ const jsonPath = parts.length === 1
106
+ ? `data->'${parts[0]}'`
107
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
108
+ return `NOT (${vals.map((v) => `${jsonPath} @> ${v}::jsonb`).join(" OR ")})`
109
+ },
110
+ jsonArrayContainsAll: (arrPath, vals) => {
111
+ const parts = arrPath.split(".")
112
+ const jsonPath = parts.length === 1
113
+ ? `data->'${parts[0]}'`
114
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
115
+ return vals.map((v) => `${jsonPath} @> ${v}::jsonb`).join(" AND ")
116
+ },
117
+ jsonArrayNotContainsAll: (arrPath, vals) => {
118
+ const parts = arrPath.split(".")
119
+ const jsonPath = parts.length === 1
120
+ ? `data->'${parts[0]}'`
121
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
122
+ return `NOT (${vals.map((v) => `${jsonPath} @> ${v}::jsonb`).join(" AND ")})`
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
+ },
145
+ caseInsensitiveLike: (expr, val) => `${expr} ILIKE ${val}`,
146
+ caseInsensitiveNotLike: (expr, val) => `${expr} NOT ILIKE ${val}`,
147
+ jsonColumnType: "JSONB",
148
+ arrayLength: (path) => `jsonb_array_length(data->'${path}')`,
149
+ jsonEachFrom: (arrPath, alias) => {
150
+ const parts = arrPath.split(".")
151
+ const jsonPath = parts.length === 1
152
+ ? `data->'${parts[0]}'`
153
+ : `data${parts.map((p) => `->'${p}'`).join("")}`
154
+ return `jsonb_array_elements(${jsonPath}) AS ${alias}`
155
+ },
156
+ jsonExtractElement: (alias, subPath) => {
157
+ const parts = subPath.split(".")
158
+ if (parts.length === 1) return `${alias}->>'${parts[0]}'`
159
+ const last = parts.pop()!
160
+ return `${alias}${parts.map((p) => `->'${p}'`).join("")}->>'${last}'`
161
+ },
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
165
+ }
166
+
167
+ export function logQuery(q: { sql: string; params: unknown[] }) {
168
+ return InfraLogger
169
+ .logDebug("sql query")
170
+ .pipe(Effect.annotateLogs({
171
+ query: q.sql,
172
+ parameters: JSON.stringify(q.params, undefined, 2)
173
+ }))
174
+ }
175
+
176
+ const dottedToJsonPath = (path: string) =>
177
+ path
178
+ .split(".")
179
+ .filter((p) => p !== "-1")
180
+ .join(".")
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
+
192
+ export function buildWhereSQLQuery(
193
+ dialect: SQLDialect,
194
+ idKey: PropertyKey,
195
+ filter: readonly FilterResult[],
196
+ tableName: string,
197
+ defaultValues: Record<string, unknown>,
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
+ >,
213
+ order?: NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }>,
214
+ skip?: number,
215
+ limit?: number,
216
+ namespace?: string,
217
+ json?: JsonLower
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)
222
+ const params: unknown[] = []
223
+ let paramIndex = 1
224
+
225
+ const addParam = (value: unknown): string => {
226
+ params.push(dialect.serializeScalar(value))
227
+ return dialect.placeholder(paramIndex++)
228
+ }
229
+
230
+ const fieldExpr = (path: string, relation?: string): string => {
231
+ if (path === idKey || path === "id") return "id"
232
+ if (relation && path.includes(".-1.")) {
233
+ const subPath = path.split(".-1.")[1]!
234
+ if (subPath.endsWith(".length")) {
235
+ // TODO: array length inside relation element
236
+ return dialect.jsonExtractElement(`_${relation}`, subPath.slice(0, -".length".length))
237
+ }
238
+ return dialect.jsonExtractElement(`_${relation}`, subPath)
239
+ }
240
+ if (path.endsWith(".length")) {
241
+ const arrPath = dottedToJsonPath(path.slice(0, -".length".length))
242
+ return dialect.arrayLength(arrPath)
243
+ }
244
+ const jsonPath = dottedToJsonPath(path)
245
+ const expr = dialect.jsonExtract(jsonPath)
246
+ const topKey = path.split(".")[0]
247
+ if (topKey in defaultValues) {
248
+ return `COALESCE(${expr}, ${addParam(defaultValues[topKey])})`
249
+ }
250
+ return expr
251
+ }
252
+
253
+ const statement = (x: FilterR, relation?: string): string => {
254
+ const resolvedPath = x.path === idKey ? "id" : x.path
255
+ const k = fieldExpr(resolvedPath, relation)
256
+
257
+ switch (x.op) {
258
+ case "in": {
259
+ const vals = x.value as readonly unknown[]
260
+ const hasNull = vals.some((v) => v == null)
261
+ const nonNullVals = vals.filter((v) => v != null)
262
+ const parts: string[] = []
263
+ if (nonNullVals.length > 0) {
264
+ const placeholders = nonNullVals.map((v) => addParam(v))
265
+ parts.push(`${k} IN (${placeholders.join(", ")})`)
266
+ }
267
+ if (hasNull) parts.push(`${k} IS NULL`)
268
+ return parts.length > 1 ? `(${parts.join(" OR ")})` : parts[0] ?? "1=0"
269
+ }
270
+ case "notIn": {
271
+ const vals = x.value as readonly unknown[]
272
+ const hasNull = vals.some((v) => v == null)
273
+ const nonNullVals = vals.filter((v) => v != null)
274
+ const parts: string[] = []
275
+ if (nonNullVals.length > 0) {
276
+ const placeholders = nonNullVals.map((v) => addParam(v))
277
+ parts.push(`${k} NOT IN (${placeholders.join(", ")})`)
278
+ }
279
+ if (hasNull) parts.push(`${k} IS NOT NULL`)
280
+ return parts.length > 1 ? `(${parts.join(" AND ")})` : parts[0] ?? "1=1"
281
+ }
282
+
283
+ case "includes": {
284
+ const arrPath = dottedToJsonPath(resolvedPath)
285
+ const v = addParam(x.value)
286
+ return dialect.jsonArrayContains(arrPath, v)
287
+ }
288
+ case "notIncludes": {
289
+ const arrPath = dottedToJsonPath(resolvedPath)
290
+ const v = addParam(x.value)
291
+ return dialect.jsonArrayNotContains(arrPath, v)
292
+ }
293
+
294
+ case "includes-any": {
295
+ const arrPath = dottedToJsonPath(resolvedPath)
296
+ const vals = x.value as readonly unknown[]
297
+ const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
298
+ return dialect.jsonArrayContainsAny(arrPath, placeholders)
299
+ }
300
+ case "notIncludes-any": {
301
+ const arrPath = dottedToJsonPath(resolvedPath)
302
+ const vals = x.value as readonly unknown[]
303
+ const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
304
+ return dialect.jsonArrayNotContainsAny(arrPath, placeholders)
305
+ }
306
+
307
+ case "includes-all": {
308
+ const arrPath = dottedToJsonPath(resolvedPath)
309
+ const vals = x.value as readonly unknown[]
310
+ const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
311
+ return dialect.jsonArrayContainsAll(arrPath, placeholders)
312
+ }
313
+ case "notIncludes-all": {
314
+ const arrPath = dottedToJsonPath(resolvedPath)
315
+ const vals = x.value as readonly unknown[]
316
+ const placeholders = vals.map((v) => addParam(dialect.serializeJsonValue(v)))
317
+ return dialect.jsonArrayNotContainsAll(arrPath, placeholders)
318
+ }
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
+
423
+ case "contains": {
424
+ const v = addParam(`%${x.value}%`)
425
+ return dialect.caseInsensitiveLike(k, v)
426
+ }
427
+ case "notContains": {
428
+ const v = addParam(`%${x.value}%`)
429
+ return dialect.caseInsensitiveNotLike(k, v)
430
+ }
431
+ case "startsWith": {
432
+ const v = addParam(`${x.value}%`)
433
+ return dialect.caseInsensitiveLike(k, v)
434
+ }
435
+ case "notStartsWith": {
436
+ const v = addParam(`${x.value}%`)
437
+ return dialect.caseInsensitiveNotLike(k, v)
438
+ }
439
+ case "endsWith": {
440
+ const v = addParam(`%${x.value}`)
441
+ return dialect.caseInsensitiveLike(k, v)
442
+ }
443
+ case "notEndsWith": {
444
+ const v = addParam(`%${x.value}`)
445
+ return dialect.caseInsensitiveNotLike(k, v)
446
+ }
447
+
448
+ case "lt": {
449
+ const v = addParam(x.value)
450
+ return `${k} < ${v}`
451
+ }
452
+ case "lte": {
453
+ const v = addParam(x.value)
454
+ return `${k} <= ${v}`
455
+ }
456
+ case "gt": {
457
+ const v = addParam(x.value)
458
+ return `${k} > ${v}`
459
+ }
460
+ case "gte": {
461
+ const v = addParam(x.value)
462
+ return `${k} >= ${v}`
463
+ }
464
+ case "neq": {
465
+ if (x.value === null) return `${k} IS NOT NULL`
466
+ const v = addParam(x.value)
467
+ return `${k} <> ${v}`
468
+ }
469
+ case undefined:
470
+ case "eq": {
471
+ if (x.value === null) return `${k} IS NULL`
472
+ const v = addParam(x.value)
473
+ return `${k} = ${v}`
474
+ }
475
+ default:
476
+ return assertUnreachable(x.op)
477
+ }
478
+ }
479
+
480
+ const wrapRelation = (rel: string, inner: string, every: boolean): string => {
481
+ // Optimize tautological/contradictory conditions
482
+ if (every && inner === "1=1") return "1=1"
483
+ if (!every && inner === "1=0") return "1=0"
484
+ const from = dialect.jsonEachFrom(rel, `_${rel}`)
485
+ // ∀x.P(x) ≡ ¬∃x.¬P(x), i.e. NOT EXISTS(... WHERE NOT P)
486
+ return every
487
+ ? `NOT EXISTS(SELECT 1 FROM ${from} WHERE NOT (${inner}))`
488
+ : `EXISTS(SELECT 1 FROM ${from} WHERE ${inner})`
489
+ }
490
+
491
+ const print = (state: readonly FilterResult[], isRelation: string | null, every: boolean): string => {
492
+ let s = ""
493
+ for (const e of state) {
494
+ switch (e.t) {
495
+ case "where":
496
+ s += statement(e, isRelation ?? undefined)
497
+ break
498
+ case "or":
499
+ s += ` OR ${statement(e, isRelation ?? undefined)}`
500
+ break
501
+ case "and":
502
+ s += ` AND ${statement(e, isRelation ?? undefined)}`
503
+ break
504
+ case "or-scope": {
505
+ if (!every) every = e.relation === "every"
506
+ const rel = isRelationCheck(e.result, isRelation)
507
+ if (rel) {
508
+ s += isRelation
509
+ ? ` OR (${print(e.result, rel, every)})`
510
+ : ` OR ${wrapRelation(rel, print(e.result, rel, every), every)}`
511
+ } else {
512
+ s += ` OR (${print(e.result, null, every)})`
513
+ }
514
+ break
515
+ }
516
+ case "and-scope": {
517
+ if (!every) every = e.relation === "every"
518
+ const rel = isRelationCheck(e.result, isRelation)
519
+ if (rel) {
520
+ s += isRelation
521
+ ? ` AND (${print(e.result, rel, every)})`
522
+ : ` AND ${wrapRelation(rel, print(e.result, rel, every), every)}`
523
+ } else {
524
+ s += ` AND (${print(e.result, null, every)})`
525
+ }
526
+ break
527
+ }
528
+ case "where-scope": {
529
+ if (!every) every = e.relation === "every"
530
+ const rel = isRelationCheck(e.result, isRelation)
531
+ if (rel) {
532
+ s += isRelation
533
+ ? `(${print(e.result, rel, every)})`
534
+ : wrapRelation(rel, print(e.result, rel, every), every)
535
+ } else {
536
+ s += `(${print(e.result, null, every)})`
537
+ }
538
+ break
539
+ }
540
+ }
541
+ }
542
+ return s
543
+ }
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
+
675
+ const getSelectExpr = (): string => {
676
+ if (!select) return "id, _etag, data"
677
+ const fields = select.map((s) => {
678
+ if (typeof s === "string") {
679
+ if (s === idKey || s === "id") return `id`
680
+ if (s === "_etag") return `_etag`
681
+ return `${dialect.jsonExtractJson(s)} AS "${s}"`
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
+ }
693
+ return `${dialect.jsonExtractJson(s.key)} AS "${s.key}"`
694
+ })
695
+ return fields.join(", ")
696
+ }
697
+
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
+ })()
725
+ : ""
726
+
727
+ const orderClause = order
728
+ ? `ORDER BY ${
729
+ order
730
+ .map((_) =>
731
+ hasAggregates
732
+ ? `"${_.key}" ${_.direction}`
733
+ : `${fieldExpr(_.key)} ${_.direction}`
734
+ )
735
+ .join(", ")
736
+ }`
737
+ : ""
738
+
739
+ const limitClause = limit !== undefined || skip !== undefined
740
+ ? `LIMIT ${addParam(limit ?? 999999)} OFFSET ${addParam(skip ?? 0)}`
741
+ : ""
742
+
743
+ const sql = `SELECT ${selectExpr} FROM "${tableName}" ${whereClause} ${groupByClause} ${orderClause} ${limitClause}`
744
+ .replace(/\s+/g, " ")
745
+ .trim()
746
+
747
+ return { sql, params }
748
+ }