@effect-app/infra 4.0.0-beta.32 → 4.0.0-beta.321

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 (480) hide show
  1. package/CHANGELOG.md +2469 -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 +70 -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 +392 -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 +87 -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 +346 -76
  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 +257 -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 +21 -0
  51. package/dist/Store/SQL.d.ts.map +1 -0
  52. package/dist/Store/SQL.js +478 -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 +13 -0
  60. package/dist/Store/jsonDocument.d.ts.map +1 -0
  61. package/dist/Store/jsonDocument.js +31 -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 +29 -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 +16 -4
  74. package/dist/codec.d.ts.map +1 -0
  75. package/dist/codec.js +5 -0
  76. package/dist/{adapters/cosmos-client.d.ts → cosmos-client.d.ts} +4 -2
  77. package/dist/cosmos-client.d.ts.map +1 -0
  78. package/dist/cosmos-client.js +11 -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 +49 -41
  157. package/package.json +38 -352
  158. package/src/CUPS.ts +54 -15
  159. package/src/ClusterCosmos.ts +1154 -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 +537 -367
  170. package/src/Store/Disk.ts +137 -74
  171. package/src/Store/Memory.ts +402 -113
  172. package/src/Store/SQL/Pg.ts +402 -0
  173. package/src/Store/SQL/query.ts +748 -0
  174. package/src/Store/SQL.ts +786 -0
  175. package/src/Store/codeFilter.ts +78 -28
  176. package/src/Store/index.ts +25 -10
  177. package/src/Store/jsonDocument.ts +43 -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 +20 -5
  182. package/src/{adapters/cosmos-client.ts → cosmos-client.ts} +5 -3
  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/auth.test.ts +101 -0
  208. package/test/cluster-cosmos.test.ts +612 -0
  209. package/test/cluster-servicebus.test.ts +180 -0
  210. package/test/cluster-sqlite.test.ts +207 -0
  211. package/test/contextProvider.test.ts +15 -12
  212. package/test/controller.test.ts +28 -32
  213. package/test/cosmos-query.test.ts +323 -0
  214. package/test/dist/auth.test.d.ts.map +1 -0
  215. package/test/dist/cluster-cosmos.test.d.ts.map +1 -0
  216. package/test/dist/cluster-servicebus.test.d.ts.map +1 -0
  217. package/test/dist/cluster-sqlite.test.d.ts.map +1 -0
  218. package/test/dist/contextProvider.test.d.ts.map +1 -1
  219. package/test/dist/controller.test.d.ts.map +1 -1
  220. package/test/dist/cosmos-query.test.d.ts.map +1 -0
  221. package/test/dist/fixtures.d.ts +29 -11
  222. package/test/dist/fixtures.d.ts.map +1 -1
  223. package/test/dist/fixtures.js +17 -10
  224. package/test/dist/json-lower.test.d.ts.map +1 -0
  225. package/test/dist/query.test.d.ts.map +1 -1
  226. package/test/dist/rawQuery.test.d.ts.map +1 -1
  227. package/test/dist/repository-ext.test.d.ts.map +1 -0
  228. package/test/dist/requires.test.d.ts.map +1 -1
  229. package/test/dist/router-generator.test.d.ts.map +1 -0
  230. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  231. package/test/dist/rpc-context-map-streaming.test.d.ts.map +1 -0
  232. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  233. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  234. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  235. package/test/dist/sql-store.test.d.ts.map +1 -0
  236. package/test/dist/workflow-engine-cosmos.test.d.ts.map +1 -0
  237. package/test/dist/workflow-engine-sqlite.test.d.ts.map +1 -0
  238. package/test/fixtures.ts +16 -9
  239. package/test/json-lower.test.ts +115 -0
  240. package/test/layerUtils.test.ts +2 -2
  241. package/test/query.test.ts +1384 -46
  242. package/test/rawQuery.test.ts +340 -22
  243. package/test/repository-ext.test.ts +456 -0
  244. package/test/requires.test.ts +10 -5
  245. package/test/router-generator.test.ts +187 -0
  246. package/test/routing-interruptibility.test.ts +66 -0
  247. package/test/rpc-context-map-streaming.test.ts +265 -0
  248. package/test/rpc-e2e-invalidation.test.ts +421 -0
  249. package/test/rpc-multi-middleware.test.ts +85 -10
  250. package/test/rpc-stream-fullstack.test.ts +307 -0
  251. package/test/sql-store.test.ts +1905 -0
  252. package/test/validateSample.test.ts +26 -14
  253. package/test/workflow-engine-cosmos.test.ts +345 -0
  254. package/test/workflow-engine-sqlite.test.ts +297 -0
  255. package/tsconfig.examples.json +1 -1
  256. package/tsconfig.json +9 -2
  257. package/tsconfig.src.json +35 -35
  258. package/tsconfig.test.json +2 -2
  259. package/dist/Emailer/service.d.ts +0 -55
  260. package/dist/Emailer/service.d.ts.map +0 -1
  261. package/dist/Emailer/service.js +0 -6
  262. package/dist/Emailer.d.ts +0 -2
  263. package/dist/Emailer.d.ts.map +0 -1
  264. package/dist/Emailer.js +0 -2
  265. package/dist/Model/Repository/ext.d.ts +0 -41
  266. package/dist/Model/Repository/ext.d.ts.map +0 -1
  267. package/dist/Model/Repository/ext.js +0 -65
  268. package/dist/Model/Repository/internal/internal.d.ts +0 -59
  269. package/dist/Model/Repository/internal/internal.d.ts.map +0 -1
  270. package/dist/Model/Repository/internal/internal.js +0 -316
  271. package/dist/Model/Repository/legacy.d.ts +0 -19
  272. package/dist/Model/Repository/legacy.d.ts.map +0 -1
  273. package/dist/Model/Repository/legacy.js +0 -2
  274. package/dist/Model/Repository/makeRepo.d.ts +0 -49
  275. package/dist/Model/Repository/makeRepo.d.ts.map +0 -1
  276. package/dist/Model/Repository/makeRepo.js +0 -24
  277. package/dist/Model/Repository/service.d.ts +0 -89
  278. package/dist/Model/Repository/service.d.ts.map +0 -1
  279. package/dist/Model/Repository/service.js +0 -2
  280. package/dist/Model/Repository/validation.d.ts +0 -42
  281. package/dist/Model/Repository/validation.d.ts.map +0 -1
  282. package/dist/Model/Repository/validation.js +0 -32
  283. package/dist/Model/Repository.d.ts +0 -6
  284. package/dist/Model/Repository.d.ts.map +0 -1
  285. package/dist/Model/Repository.js +0 -6
  286. package/dist/Model/dsl.d.ts +0 -32
  287. package/dist/Model/dsl.d.ts.map +0 -1
  288. package/dist/Model/dsl.js +0 -44
  289. package/dist/Model/filter/filterApi.d.ts +0 -30
  290. package/dist/Model/filter/filterApi.d.ts.map +0 -1
  291. package/dist/Model/filter/filterApi.js +0 -2
  292. package/dist/Model/filter/types/errors.d.ts +0 -29
  293. package/dist/Model/filter/types/errors.d.ts.map +0 -1
  294. package/dist/Model/filter/types/errors.js +0 -2
  295. package/dist/Model/filter/types/fields.d.ts +0 -15
  296. package/dist/Model/filter/types/fields.d.ts.map +0 -1
  297. package/dist/Model/filter/types/fields.js +0 -2
  298. package/dist/Model/filter/types/path/common.d.ts +0 -316
  299. package/dist/Model/filter/types/path/common.d.ts.map +0 -1
  300. package/dist/Model/filter/types/path/common.js +0 -2
  301. package/dist/Model/filter/types/path/eager.d.ts +0 -95
  302. package/dist/Model/filter/types/path/eager.d.ts.map +0 -1
  303. package/dist/Model/filter/types/path/eager.js +0 -31
  304. package/dist/Model/filter/types/path/index.d.ts +0 -4
  305. package/dist/Model/filter/types/path/index.d.ts.map +0 -1
  306. package/dist/Model/filter/types/path/index.js +0 -3
  307. package/dist/Model/filter/types/utils.d.ts +0 -79
  308. package/dist/Model/filter/types/utils.d.ts.map +0 -1
  309. package/dist/Model/filter/types/utils.js +0 -2
  310. package/dist/Model/filter/types/validator.d.ts +0 -30
  311. package/dist/Model/filter/types/validator.d.ts.map +0 -1
  312. package/dist/Model/filter/types/validator.js +0 -2
  313. package/dist/Model/filter/types.d.ts +0 -5
  314. package/dist/Model/filter/types.d.ts.map +0 -1
  315. package/dist/Model/filter/types.js +0 -7
  316. package/dist/Model/query/dsl.d.ts +0 -248
  317. package/dist/Model/query/dsl.d.ts.map +0 -1
  318. package/dist/Model/query/dsl.js +0 -104
  319. package/dist/Model/query/new-kid-interpreter.d.ts +0 -28
  320. package/dist/Model/query/new-kid-interpreter.d.ts.map +0 -1
  321. package/dist/Model/query/new-kid-interpreter.js +0 -165
  322. package/dist/Model/query.d.ts +0 -15
  323. package/dist/Model/query.d.ts.map +0 -1
  324. package/dist/Model/query.js +0 -3
  325. package/dist/Model.d.ts +0 -4
  326. package/dist/Model.d.ts.map +0 -1
  327. package/dist/Model.js +0 -4
  328. package/dist/Operations.d.ts +0 -55
  329. package/dist/Operations.d.ts.map +0 -1
  330. package/dist/Operations.js +0 -102
  331. package/dist/OperationsRepo.d.ts +0 -41
  332. package/dist/OperationsRepo.d.ts.map +0 -1
  333. package/dist/OperationsRepo.js +0 -14
  334. package/dist/QueueMaker/SQLQueue.d.ts +0 -16
  335. package/dist/QueueMaker/SQLQueue.d.ts.map +0 -1
  336. package/dist/QueueMaker/SQLQueue.js +0 -130
  337. package/dist/QueueMaker/memQueue.d.ts +0 -11
  338. package/dist/QueueMaker/memQueue.d.ts.map +0 -1
  339. package/dist/QueueMaker/memQueue.js +0 -76
  340. package/dist/QueueMaker/sbqueue.d.ts +0 -12
  341. package/dist/QueueMaker/sbqueue.d.ts.map +0 -1
  342. package/dist/QueueMaker/sbqueue.js +0 -91
  343. package/dist/QueueMaker/service.d.ts +0 -11
  344. package/dist/QueueMaker/service.d.ts.map +0 -1
  345. package/dist/QueueMaker/service.js +0 -4
  346. package/dist/RequestContext.d.ts +0 -63
  347. package/dist/RequestContext.d.ts.map +0 -1
  348. package/dist/RequestContext.js +0 -49
  349. package/dist/RequestFiberSet.d.ts +0 -36
  350. package/dist/RequestFiberSet.d.ts.map +0 -1
  351. package/dist/RequestFiberSet.js +0 -78
  352. package/dist/Store/ContextMapContainer.d.ts +0 -14
  353. package/dist/Store/ContextMapContainer.d.ts.map +0 -1
  354. package/dist/Store/ContextMapContainer.js +0 -16
  355. package/dist/Store/service.d.ts +0 -108
  356. package/dist/Store/service.d.ts.map +0 -1
  357. package/dist/Store/service.js +0 -71
  358. package/dist/Store.d.ts +0 -2
  359. package/dist/Store.d.ts.map +0 -1
  360. package/dist/Store.js +0 -2
  361. package/dist/adapters/SQL/Model.d.ts.map +0 -1
  362. package/dist/adapters/SQL/Model.js +0 -478
  363. package/dist/adapters/SQL.d.ts.map +0 -1
  364. package/dist/adapters/ServiceBus.d.ts +0 -58
  365. package/dist/adapters/ServiceBus.d.ts.map +0 -1
  366. package/dist/adapters/ServiceBus.js +0 -99
  367. package/dist/adapters/cosmos-client.d.ts.map +0 -1
  368. package/dist/adapters/cosmos-client.js +0 -9
  369. package/dist/adapters/index.d.ts +0 -2
  370. package/dist/adapters/index.d.ts.map +0 -1
  371. package/dist/adapters/index.js +0 -2
  372. package/dist/adapters/logger.d.ts +0 -9
  373. package/dist/adapters/logger.d.ts.map +0 -1
  374. package/dist/adapters/logger.js +0 -3
  375. package/dist/adapters/memQueue.d.ts +0 -13
  376. package/dist/adapters/memQueue.d.ts.map +0 -1
  377. package/dist/adapters/memQueue.js +0 -20
  378. package/dist/adapters/mongo-client.d.ts.map +0 -1
  379. package/dist/adapters/mongo-client.js +0 -13
  380. package/dist/adapters/redis-client.d.ts.map +0 -1
  381. package/dist/adapters/redis-client.js +0 -94
  382. package/dist/api/ContextProvider.d.ts +0 -31
  383. package/dist/api/ContextProvider.d.ts.map +0 -1
  384. package/dist/api/ContextProvider.js +0 -38
  385. package/dist/api/codec.d.ts.map +0 -1
  386. package/dist/api/codec.js +0 -5
  387. package/dist/api/internal/RequestContextMiddleware.d.ts +0 -5
  388. package/dist/api/internal/RequestContextMiddleware.d.ts.map +0 -1
  389. package/dist/api/internal/RequestContextMiddleware.js +0 -35
  390. package/dist/api/internal/auth.d.ts +0 -15
  391. package/dist/api/internal/auth.d.ts.map +0 -1
  392. package/dist/api/internal/auth.js +0 -47
  393. package/dist/api/internal/events.d.ts +0 -9
  394. package/dist/api/internal/events.d.ts.map +0 -1
  395. package/dist/api/internal/events.js +0 -42
  396. package/dist/api/internal/health.d.ts.map +0 -1
  397. package/dist/api/internal/health.js +0 -5
  398. package/dist/api/layerUtils.d.ts.map +0 -1
  399. package/dist/api/layerUtils.js +0 -16
  400. package/dist/api/middlewares.d.ts.map +0 -1
  401. package/dist/api/reportError.d.ts.map +0 -1
  402. package/dist/api/reportError.js +0 -27
  403. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +0 -1
  404. package/dist/api/routing/middleware/middleware.d.ts +0 -9
  405. package/dist/api/routing/middleware/middleware.d.ts.map +0 -1
  406. package/dist/api/routing/middleware/middleware.js +0 -92
  407. package/dist/api/routing/middleware.d.ts.map +0 -1
  408. package/dist/api/routing/schema/jwt.d.ts.map +0 -1
  409. package/dist/api/routing/schema/jwt.js +0 -12
  410. package/dist/api/routing/tsort.d.ts.map +0 -1
  411. package/dist/api/routing/tsort.js +0 -51
  412. package/dist/api/routing/utils.d.ts.map +0 -1
  413. package/dist/api/routing/utils.js +0 -44
  414. package/dist/api/routing.d.ts +0 -138
  415. package/dist/api/routing.d.ts.map +0 -1
  416. package/dist/api/routing.js +0 -166
  417. package/dist/api/setupRequest.d.ts +0 -12
  418. package/dist/api/setupRequest.d.ts.map +0 -1
  419. package/dist/api/setupRequest.js +0 -44
  420. package/dist/api/util.d.ts.map +0 -1
  421. package/dist/api/util.js +0 -14
  422. package/eslint.config.mjs +0 -24
  423. package/src/Emailer/service.ts +0 -52
  424. package/src/Emailer.ts +0 -1
  425. package/src/Model/Repository/ext.ts +0 -283
  426. package/src/Model/Repository/internal/internal.ts +0 -577
  427. package/src/Model/Repository/legacy.ts +0 -27
  428. package/src/Model/Repository/makeRepo.ts +0 -139
  429. package/src/Model/Repository/service.ts +0 -627
  430. package/src/Model/Repository/validation.ts +0 -31
  431. package/src/Model/Repository.ts +0 -5
  432. package/src/Model/dsl.ts +0 -128
  433. package/src/Model/filter/filterApi.ts +0 -60
  434. package/src/Model/filter/types/errors.ts +0 -47
  435. package/src/Model/filter/types/fields.ts +0 -50
  436. package/src/Model/filter/types/path/common.ts +0 -404
  437. package/src/Model/filter/types/path/eager.ts +0 -298
  438. package/src/Model/filter/types/path/index.ts +0 -4
  439. package/src/Model/filter/types/utils.ts +0 -128
  440. package/src/Model/filter/types/validator.ts +0 -46
  441. package/src/Model/filter/types.ts +0 -6
  442. package/src/Model/query/dsl.ts +0 -2110
  443. package/src/Model/query/new-kid-interpreter.ts +0 -210
  444. package/src/Model/query.ts +0 -13
  445. package/src/Model.ts +0 -3
  446. package/src/Operations.ts +0 -235
  447. package/src/OperationsRepo.ts +0 -16
  448. package/src/QueueMaker/SQLQueue.ts +0 -189
  449. package/src/QueueMaker/memQueue.ts +0 -130
  450. package/src/QueueMaker/sbqueue.ts +0 -137
  451. package/src/QueueMaker/service.ts +0 -17
  452. package/src/RequestContext.ts +0 -63
  453. package/src/RequestFiberSet.ts +0 -105
  454. package/src/Store/ContextMapContainer.ts +0 -20
  455. package/src/Store/index.test.ts.bak +0 -112
  456. package/src/Store/service.ts +0 -184
  457. package/src/Store.ts +0 -1
  458. package/src/adapters/SQL.ts +0 -1
  459. package/src/adapters/ServiceBus.ts +0 -209
  460. package/src/adapters/index.ts +0 -0
  461. package/src/adapters/logger.ts +0 -3
  462. package/src/adapters/memQueue.ts +0 -21
  463. package/src/api/internal/auth.ts +0 -68
  464. package/src/api/middlewares.ts +0 -10
  465. package/src/api/routing/middleware/middleware.ts +0 -128
  466. package/src/api/routing/middleware.ts +0 -6
  467. package/src/api/routing.ts +0 -598
  468. package/src/api/setupRequest.ts +0 -84
  469. package/tsconfig.json.bak +0 -12
  470. /package/dist/{adapters/SQL.d.ts → SQL.d.ts} +0 -0
  471. /package/dist/{api/codec.d.ts → codec.d.ts} +0 -0
  472. /package/dist/{api/internal → internal}/health.d.ts +0 -0
  473. /package/dist/{api/middlewares.d.ts → middlewares.d.ts} +0 -0
  474. /package/dist/{api/routing → routing}/schema/jwt.d.ts +0 -0
  475. /package/dist/{api/routing → routing}/tsort.d.ts +0 -0
  476. /package/dist/{api/util.d.ts → util.d.ts} +0 -0
  477. /package/src/{api/codec.ts → codec.ts} +0 -0
  478. /package/src/{api/internal → internal}/health.ts +0 -0
  479. /package/src/{api/routing → routing}/tsort.ts +0 -0
  480. /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, toJsonQueryValue } 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
+ const toJson = json?.toJson ?? toJsonQueryValue
220
+ filter = (json?.jsonifyFilter ?? jsonifyFilter)(filter)
221
+ defaultValues = toJson(defaultValues) as Record<string, unknown>
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
+ }