@effect-app/infra 4.0.0-beta.22 → 4.0.0-beta.221

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 (337) hide show
  1. package/CHANGELOG.md +1648 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +12 -7
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +16 -12
  6. package/dist/Emailer/Sendgrid.d.ts +15 -15
  7. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  8. package/dist/Emailer/Sendgrid.js +20 -16
  9. package/dist/Emailer/fake.d.ts +1 -1
  10. package/dist/Emailer/fake.js +2 -2
  11. package/dist/Emailer/service.d.ts +13 -4
  12. package/dist/Emailer/service.d.ts.map +1 -1
  13. package/dist/Emailer/service.js +4 -3
  14. package/dist/Emailer.d.ts +1 -1
  15. package/dist/MainFiberSet.d.ts +12 -9
  16. package/dist/MainFiberSet.d.ts.map +1 -1
  17. package/dist/MainFiberSet.js +7 -3
  18. package/dist/Model/Repository/Registry.d.ts +21 -0
  19. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  20. package/dist/Model/Repository/Registry.js +18 -0
  21. package/dist/Model/Repository/ext.d.ts +35 -16
  22. package/dist/Model/Repository/ext.d.ts.map +1 -1
  23. package/dist/Model/Repository/ext.js +60 -3
  24. package/dist/Model/Repository/internal/internal.d.ts +9 -6
  25. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  26. package/dist/Model/Repository/internal/internal.js +115 -51
  27. package/dist/Model/Repository/legacy.d.ts +4 -2
  28. package/dist/Model/Repository/legacy.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.d.ts +10 -6
  30. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  31. package/dist/Model/Repository/makeRepo.js +5 -2
  32. package/dist/Model/Repository/service.d.ts +32 -24
  33. package/dist/Model/Repository/service.d.ts.map +1 -1
  34. package/dist/Model/Repository/validation.d.ts +47 -18
  35. package/dist/Model/Repository/validation.d.ts.map +1 -1
  36. package/dist/Model/Repository/validation.js +6 -6
  37. package/dist/Model/Repository.d.ts +2 -1
  38. package/dist/Model/Repository.d.ts.map +1 -1
  39. package/dist/Model/Repository.js +2 -1
  40. package/dist/Model/dsl.d.ts +6 -5
  41. package/dist/Model/dsl.d.ts.map +1 -1
  42. package/dist/Model/dsl.js +2 -3
  43. package/dist/Model/filter/filterApi.d.ts +5 -5
  44. package/dist/Model/filter/filterApi.d.ts.map +1 -1
  45. package/dist/Model/filter/types/errors.d.ts +1 -1
  46. package/dist/Model/filter/types/fields.d.ts +1 -1
  47. package/dist/Model/filter/types/path/common.d.ts +1 -1
  48. package/dist/Model/filter/types/path/eager.d.ts +1 -1
  49. package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
  50. package/dist/Model/filter/types/path/eager.js +1 -1
  51. package/dist/Model/filter/types/path/index.d.ts +1 -1
  52. package/dist/Model/filter/types/utils.d.ts +1 -1
  53. package/dist/Model/filter/types/validator.d.ts +1 -1
  54. package/dist/Model/filter/types.d.ts +1 -1
  55. package/dist/Model/query/dsl.d.ts +142 -17
  56. package/dist/Model/query/dsl.d.ts.map +1 -1
  57. package/dist/Model/query/dsl.js +190 -5
  58. package/dist/Model/query/new-kid-interpreter.d.ts +77 -8
  59. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  60. package/dist/Model/query/new-kid-interpreter.js +127 -6
  61. package/dist/Model/query.d.ts +1 -1
  62. package/dist/Model.d.ts +2 -1
  63. package/dist/Model.d.ts.map +1 -1
  64. package/dist/Model.js +2 -1
  65. package/dist/QueueMaker/SQLQueue.d.ts +7 -8
  66. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  67. package/dist/QueueMaker/SQLQueue.js +135 -117
  68. package/dist/QueueMaker/errors.d.ts +5 -3
  69. package/dist/QueueMaker/errors.d.ts.map +1 -1
  70. package/dist/QueueMaker/errors.js +4 -2
  71. package/dist/QueueMaker/memQueue.d.ts +9 -5
  72. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  73. package/dist/QueueMaker/memQueue.js +81 -65
  74. package/dist/QueueMaker/sbqueue.d.ts +8 -4
  75. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  76. package/dist/QueueMaker/sbqueue.js +57 -55
  77. package/dist/QueueMaker/service.d.ts +4 -2
  78. package/dist/QueueMaker/service.d.ts.map +1 -1
  79. package/dist/QueueMaker/service.js +1 -1
  80. package/dist/RequestContext.d.ts +75 -35
  81. package/dist/RequestContext.d.ts.map +1 -1
  82. package/dist/RequestContext.js +14 -14
  83. package/dist/RequestFiberSet.d.ts +10 -7
  84. package/dist/RequestFiberSet.d.ts.map +1 -1
  85. package/dist/RequestFiberSet.js +8 -3
  86. package/dist/Store/ContextMapContainer.d.ts +22 -3
  87. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  88. package/dist/Store/ContextMapContainer.js +17 -3
  89. package/dist/Store/Cosmos/query.d.ts +7 -2
  90. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  91. package/dist/Store/Cosmos/query.js +115 -35
  92. package/dist/Store/Cosmos.d.ts +2 -2
  93. package/dist/Store/Cosmos.d.ts.map +1 -1
  94. package/dist/Store/Cosmos.js +343 -244
  95. package/dist/Store/Disk.d.ts +3 -3
  96. package/dist/Store/Disk.d.ts.map +1 -1
  97. package/dist/Store/Disk.js +76 -36
  98. package/dist/Store/Memory.d.ts +7 -4
  99. package/dist/Store/Memory.d.ts.map +1 -1
  100. package/dist/Store/Memory.js +251 -58
  101. package/dist/Store/SQL/Pg.d.ts +4 -0
  102. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  103. package/dist/Store/SQL/Pg.js +233 -0
  104. package/dist/Store/SQL/query.d.ts +43 -0
  105. package/dist/Store/SQL/query.d.ts.map +1 -0
  106. package/dist/Store/SQL/query.js +478 -0
  107. package/dist/Store/SQL.d.ts +21 -0
  108. package/dist/Store/SQL.d.ts.map +1 -0
  109. package/dist/Store/SQL.js +450 -0
  110. package/dist/Store/codeFilter.d.ts +2 -2
  111. package/dist/Store/codeFilter.d.ts.map +1 -1
  112. package/dist/Store/codeFilter.js +6 -3
  113. package/dist/Store/index.d.ts +6 -3
  114. package/dist/Store/index.d.ts.map +1 -1
  115. package/dist/Store/index.js +18 -4
  116. package/dist/Store/service.d.ts +26 -8
  117. package/dist/Store/service.d.ts.map +1 -1
  118. package/dist/Store/service.js +25 -6
  119. package/dist/Store/utils.d.ts +3 -2
  120. package/dist/Store/utils.d.ts.map +1 -1
  121. package/dist/Store/utils.js +5 -5
  122. package/dist/Store.d.ts +1 -1
  123. package/dist/adapters/SQL/Model.d.ts +32 -43
  124. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  125. package/dist/adapters/SQL/Model.js +30 -39
  126. package/dist/adapters/SQL.d.ts +1 -1
  127. package/dist/adapters/ServiceBus.d.ts +14 -11
  128. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  129. package/dist/adapters/ServiceBus.js +30 -21
  130. package/dist/adapters/cosmos-client.d.ts +5 -3
  131. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  132. package/dist/adapters/cosmos-client.js +5 -3
  133. package/dist/adapters/index.d.ts +8 -2
  134. package/dist/adapters/index.d.ts.map +1 -1
  135. package/dist/adapters/index.js +8 -2
  136. package/dist/adapters/logger.d.ts +2 -2
  137. package/dist/adapters/logger.d.ts.map +1 -1
  138. package/dist/adapters/memQueue.d.ts +5 -3
  139. package/dist/adapters/memQueue.d.ts.map +1 -1
  140. package/dist/adapters/memQueue.js +6 -5
  141. package/dist/adapters/mongo-client.d.ts +4 -3
  142. package/dist/adapters/mongo-client.d.ts.map +1 -1
  143. package/dist/adapters/mongo-client.js +5 -3
  144. package/dist/adapters/redis-client.d.ts +6 -3
  145. package/dist/adapters/redis-client.d.ts.map +1 -1
  146. package/dist/adapters/redis-client.js +7 -3
  147. package/dist/api/ContextProvider.d.ts +12 -8
  148. package/dist/api/ContextProvider.d.ts.map +1 -1
  149. package/dist/api/ContextProvider.js +9 -7
  150. package/dist/api/codec.d.ts +1 -1
  151. package/dist/api/internal/RequestContextMiddleware.d.ts +3 -3
  152. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  153. package/dist/api/internal/RequestContextMiddleware.js +10 -6
  154. package/dist/api/internal/auth.d.ts +45 -7
  155. package/dist/api/internal/auth.d.ts.map +1 -1
  156. package/dist/api/internal/auth.js +162 -29
  157. package/dist/api/internal/events.d.ts +6 -4
  158. package/dist/api/internal/events.d.ts.map +1 -1
  159. package/dist/api/internal/events.js +16 -9
  160. package/dist/api/internal/health.d.ts +1 -1
  161. package/dist/api/layerUtils.d.ts +10 -6
  162. package/dist/api/layerUtils.d.ts.map +1 -1
  163. package/dist/api/layerUtils.js +7 -6
  164. package/dist/api/middlewares.d.ts +1 -1
  165. package/dist/api/reportError.d.ts +2 -2
  166. package/dist/api/reportError.d.ts.map +1 -1
  167. package/dist/api/reportError.js +3 -2
  168. package/dist/api/routing/middleware/RouterMiddleware.d.ts +5 -4
  169. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  170. package/dist/api/routing/middleware/middleware.d.ts +42 -3
  171. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  172. package/dist/api/routing/middleware/middleware.js +53 -17
  173. package/dist/api/routing/middleware.d.ts +1 -2
  174. package/dist/api/routing/middleware.d.ts.map +1 -1
  175. package/dist/api/routing/middleware.js +1 -2
  176. package/dist/api/routing/schema/jwt.d.ts +1 -1
  177. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  178. package/dist/api/routing/schema/jwt.js +3 -2
  179. package/dist/api/routing/tsort.d.ts +1 -1
  180. package/dist/api/routing/tsort.d.ts.map +1 -1
  181. package/dist/api/routing/utils.d.ts +4 -4
  182. package/dist/api/routing/utils.d.ts.map +1 -1
  183. package/dist/api/routing/utils.js +3 -2
  184. package/dist/api/routing.d.ts +84 -37
  185. package/dist/api/routing.d.ts.map +1 -1
  186. package/dist/api/routing.js +115 -45
  187. package/dist/api/setupRequest.d.ts +10 -6
  188. package/dist/api/setupRequest.d.ts.map +1 -1
  189. package/dist/api/setupRequest.js +15 -7
  190. package/dist/api/util.d.ts +1 -1
  191. package/dist/arbs.d.ts +2 -2
  192. package/dist/arbs.d.ts.map +1 -1
  193. package/dist/arbs.js +5 -3
  194. package/dist/errorReporter.d.ts +7 -5
  195. package/dist/errorReporter.d.ts.map +1 -1
  196. package/dist/errorReporter.js +22 -26
  197. package/dist/errors.d.ts +1 -1
  198. package/dist/fileUtil.d.ts +2 -2
  199. package/dist/fileUtil.d.ts.map +1 -1
  200. package/dist/fileUtil.js +2 -2
  201. package/dist/index.d.ts +1 -1
  202. package/dist/logger/jsonLogger.d.ts +2 -2
  203. package/dist/logger/jsonLogger.d.ts.map +1 -1
  204. package/dist/logger/jsonLogger.js +4 -2
  205. package/dist/logger/logFmtLogger.d.ts +2 -2
  206. package/dist/logger/logFmtLogger.d.ts.map +1 -1
  207. package/dist/logger/logFmtLogger.js +2 -2
  208. package/dist/logger/shared.d.ts +2 -2
  209. package/dist/logger/shared.d.ts.map +1 -1
  210. package/dist/logger/shared.js +3 -3
  211. package/dist/logger.d.ts +1 -1
  212. package/dist/logger.d.ts.map +1 -1
  213. package/dist/otel.d.ts +75 -0
  214. package/dist/otel.d.ts.map +1 -0
  215. package/dist/otel.js +65 -0
  216. package/dist/rateLimit.d.ts +12 -4
  217. package/dist/rateLimit.d.ts.map +1 -1
  218. package/dist/rateLimit.js +7 -12
  219. package/dist/test.d.ts +3 -3
  220. package/dist/test.d.ts.map +1 -1
  221. package/dist/test.js +2 -2
  222. package/dist/vitest.d.ts +1 -1
  223. package/examples/query.ts +46 -38
  224. package/package.json +46 -37
  225. package/src/CUPS.ts +15 -11
  226. package/src/Emailer/Sendgrid.ts +21 -15
  227. package/src/Emailer/fake.ts +1 -1
  228. package/src/Emailer/service.ts +13 -3
  229. package/src/MainFiberSet.ts +9 -6
  230. package/src/Model/Repository/Registry.ts +34 -0
  231. package/src/Model/Repository/ext.ts +103 -11
  232. package/src/Model/Repository/internal/internal.ts +231 -149
  233. package/src/Model/Repository/legacy.ts +3 -1
  234. package/src/Model/Repository/makeRepo.ts +15 -10
  235. package/src/Model/Repository/service.ts +35 -23
  236. package/src/Model/Repository/validation.ts +5 -5
  237. package/src/Model/Repository.ts +1 -0
  238. package/src/Model/dsl.ts +5 -4
  239. package/src/Model/filter/types/path/eager.ts +1 -2
  240. package/src/Model/query/dsl.ts +353 -19
  241. package/src/Model/query/new-kid-interpreter.ts +211 -6
  242. package/src/Model.ts +1 -0
  243. package/src/QueueMaker/SQLQueue.ts +150 -153
  244. package/src/QueueMaker/errors.ts +3 -1
  245. package/src/QueueMaker/memQueue.ts +111 -105
  246. package/src/QueueMaker/sbqueue.ts +76 -88
  247. package/src/QueueMaker/service.ts +3 -1
  248. package/src/RequestContext.ts +15 -16
  249. package/src/RequestFiberSet.ts +8 -2
  250. package/src/Store/ContextMapContainer.ts +45 -2
  251. package/src/Store/Cosmos/query.ts +143 -44
  252. package/src/Store/Cosmos.ts +491 -350
  253. package/src/Store/Disk.ts +106 -66
  254. package/src/Store/Memory.ts +285 -87
  255. package/src/Store/SQL/Pg.ts +364 -0
  256. package/src/Store/SQL/query.ts +540 -0
  257. package/src/Store/SQL.ts +736 -0
  258. package/src/Store/codeFilter.ts +5 -2
  259. package/src/Store/index.ts +20 -3
  260. package/src/Store/service.ts +45 -10
  261. package/src/Store/utils.ts +25 -23
  262. package/src/adapters/SQL/Model.ts +42 -41
  263. package/src/adapters/ServiceBus.ts +131 -121
  264. package/src/adapters/cosmos-client.ts +4 -2
  265. package/src/adapters/index.ts +7 -0
  266. package/src/adapters/memQueue.ts +5 -4
  267. package/src/adapters/mongo-client.ts +4 -2
  268. package/src/adapters/redis-client.ts +6 -2
  269. package/src/api/ContextProvider.ts +17 -13
  270. package/src/api/internal/RequestContextMiddleware.ts +16 -5
  271. package/src/api/internal/auth.ts +248 -44
  272. package/src/api/internal/events.ts +19 -10
  273. package/src/api/layerUtils.ts +12 -8
  274. package/src/api/reportError.ts +2 -1
  275. package/src/api/routing/middleware/RouterMiddleware.ts +5 -4
  276. package/src/api/routing/middleware/middleware.ts +60 -15
  277. package/src/api/routing/middleware.ts +0 -2
  278. package/src/api/routing/schema/jwt.ts +2 -1
  279. package/src/api/routing/utils.ts +2 -1
  280. package/src/api/routing.ts +304 -131
  281. package/src/api/setupRequest.ts +31 -8
  282. package/src/arbs.ts +5 -3
  283. package/src/errorReporter.ts +65 -75
  284. package/src/fileUtil.ts +1 -1
  285. package/src/logger/jsonLogger.ts +3 -1
  286. package/src/logger/logFmtLogger.ts +1 -1
  287. package/src/logger/shared.ts +3 -2
  288. package/src/otel.ts +152 -0
  289. package/src/rateLimit.ts +34 -23
  290. package/src/test.ts +2 -2
  291. package/test/auth.test.ts +101 -0
  292. package/test/contextProvider.test.ts +14 -11
  293. package/test/controller.test.ts +25 -29
  294. package/test/dist/auth.test.d.ts.map +1 -0
  295. package/test/dist/contextProvider.test.d.ts.map +1 -1
  296. package/test/dist/controller.test.d.ts.map +1 -1
  297. package/test/dist/date-query.test.d.ts.map +1 -0
  298. package/test/dist/fixtures.d.ts +30 -12
  299. package/test/dist/fixtures.d.ts.map +1 -1
  300. package/test/dist/fixtures.js +17 -10
  301. package/test/dist/query.test.d.ts.map +1 -1
  302. package/test/dist/rawQuery.test.d.ts.map +1 -1
  303. package/test/dist/repository-ext.test.d.ts.map +1 -0
  304. package/test/dist/requires.test.d.ts.map +1 -1
  305. package/test/dist/router-generator.test.d.ts.map +1 -0
  306. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  307. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  308. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  309. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  310. package/test/dist/sql-store.test.d.ts.map +1 -0
  311. package/test/fixtures.ts +16 -9
  312. package/test/layerUtils.test.ts +1 -1
  313. package/test/query.test.ts +819 -38
  314. package/test/rawQuery.test.ts +312 -20
  315. package/test/repository-ext.test.ts +62 -0
  316. package/test/requires.test.ts +10 -5
  317. package/test/router-generator.test.ts +187 -0
  318. package/test/routing-interruptibility.test.ts +66 -0
  319. package/test/rpc-e2e-invalidation.test.ts +256 -0
  320. package/test/rpc-multi-middleware.test.ts +84 -9
  321. package/test/rpc-stream-fullstack.test.ts +304 -0
  322. package/test/sql-store.test.ts +1592 -0
  323. package/test/validateSample.test.ts +17 -12
  324. package/tsconfig.examples.json +1 -1
  325. package/tsconfig.json +0 -1
  326. package/tsconfig.json.bak +2 -2
  327. package/tsconfig.src.json +35 -35
  328. package/tsconfig.test.json +2 -2
  329. package/dist/Operations.d.ts +0 -55
  330. package/dist/Operations.d.ts.map +0 -1
  331. package/dist/Operations.js +0 -102
  332. package/dist/OperationsRepo.d.ts +0 -41
  333. package/dist/OperationsRepo.d.ts.map +0 -1
  334. package/dist/OperationsRepo.js +0 -14
  335. package/eslint.config.mjs +0 -24
  336. package/src/Operations.ts +0 -235
  337. package/src/OperationsRepo.ts +0 -16
@@ -1,9 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
3
- import { Array, Option } from "effect-app"
4
- import { assertUnreachable, get } from "effect-app/utils"
3
+ import * as Array from "effect-app/Array"
4
+ import * as Option from "effect-app/Option"
5
+ import { assertUnreachable } from "effect-app/utils"
5
6
  import type { FilterR, FilterResult } from "../Model/filter/filterApi.js"
6
7
  import type { FieldValues } from "../Model/filter/types.js"
8
+ import { get } from "./Memory.js"
7
9
  import type { Filter } from "./service.js"
8
10
  import { compare, greaterThan, greaterThanExclusive, lowerThan, lowerThanExclusive } from "./utils.js"
9
11
 
@@ -186,6 +188,7 @@ export const codeFilter3_ = <E>(state: readonly FilterResult[], sut: E): boolean
186
188
  const statements: any[] = [] // must be defined here to be used by eval.
187
189
  // always put everything inside a root scope.
188
190
  const s = codeFilter3__([{ t: "where-scope", result: state, relation: "some" }], sut, statements, null, false)
191
+ // oxlint-disable-next-line no-eval
189
192
  return eval(s)
190
193
  }
191
194
 
@@ -1,12 +1,21 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Effect, Layer, Redacted } from "effect-app"
2
+ import * as Effect from "effect-app/Effect"
3
+ import * as Layer from "effect-app/Layer"
4
+ import * as Redacted from "effect/Redacted"
5
+ import type { SqlClient } from "effect/unstable/sql"
3
6
  import { CosmosStoreLayer } from "./Cosmos.js"
4
7
  import { DiskStoreLayer } from "./Disk.js"
5
8
  import { MemoryStoreLive } from "./Memory.js"
6
9
  // import { RedisStoreLayer } from "./Redis.js"
10
+ import { RepositoryRegistryLive } from "../Model.js"
7
11
  import type { StorageConfig } from "./service.js"
12
+ import { SQLiteStoreLayer } from "./SQL.js"
13
+ import { PgStoreLayer } from "./SQL/Pg.js"
8
14
 
9
- export function StoreMakerLayer(cfg: StorageConfig) {
15
+ export function StoreMakerLayer(
16
+ cfg: StorageConfig,
17
+ options?: { makeSqlClientLayer?: (namespace: string) => Layer.Layer<SqlClient.SqlClient> }
18
+ ) {
10
19
  return Effect
11
20
  .sync(() => {
12
21
  const storageUrl = Redacted.value(cfg.url)
@@ -19,6 +28,14 @@ export function StoreMakerLayer(cfg: StorageConfig) {
19
28
  console.log("Using disk store at " + dir)
20
29
  return DiskStoreLayer(cfg, dir)
21
30
  }
31
+ if (storageUrl.startsWith("sqlite://")) {
32
+ console.log("Using SQLite store")
33
+ return SQLiteStoreLayer(cfg, options)
34
+ }
35
+ if (storageUrl.startsWith("pg://")) {
36
+ console.log("Using PostgreSQL store")
37
+ return PgStoreLayer(cfg)
38
+ }
22
39
  // if (storageUrl.startsWith("redis://")) {
23
40
  // console.log("Using Redis store")
24
41
  // return RedisStoreLayer(cfg)
@@ -27,7 +44,7 @@ export function StoreMakerLayer(cfg: StorageConfig) {
27
44
  console.log("Using Cosmos DB store")
28
45
  return CosmosStoreLayer(cfg)
29
46
  })
30
- .pipe(Layer.unwrap)
47
+ .pipe(Layer.unwrap, Layer.merge(RepositoryRegistryLive))
31
48
  }
32
49
 
33
50
  export * from "./service.js"
@@ -1,17 +1,22 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import type { UniqueKey } from "@azure/cosmos"
3
- import { Effect, type NonEmptyReadonlyArray, type Option, type Redacted, ServiceMap } from "effect-app"
3
+ import type { NonEmptyReadonlyArray } from "effect-app/Array"
4
+ import * as Context from "effect-app/Context"
5
+ import * as Effect from "effect-app/Effect"
6
+ import type * as Option from "effect-app/Option"
7
+ import type * as Redacted from "effect/Redacted"
8
+ import * as Semaphore from "effect/Semaphore"
4
9
  import type { OptimisticConcurrencyException } from "../errors.js"
5
10
  import type { FilterResult } from "../Model/filter/filterApi.js"
6
11
  import type { FieldValues } from "../Model/filter/types.js"
7
12
  import type { FieldPath } from "../Model/filter/types/path/index.js"
8
- import { type RawQuery } from "../Model/query.js"
13
+ import type { ComputedProjectionIrExpression, RawQuery } from "../Model/query.js"
9
14
 
10
15
  export interface StoreConfig<E> {
11
16
  partitionValue: (e?: E) => string
12
17
  /**
13
- * Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database
14
- * currently only supported in disk/memory. CosmosDB is TODO.
18
+ * Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database.
19
+ * Memory/Disk use separate store instances per namespace. CosmosDB uses namespace-prefixed partition keys. SQL uses a `_namespace` column.
15
20
  */
16
21
  allowNamespace?: (namespace: string) => boolean
17
22
  /**
@@ -60,7 +65,14 @@ export interface O<TFieldValues extends FieldValues> {
60
65
  export interface FilterArgs<Encoded extends FieldValues, U extends keyof Encoded = never> {
61
66
  t: Encoded
62
67
  filter?: Filter | undefined
63
- select?: NonEmptyReadonlyArray<U | { key: string; subKeys: readonly string[] }> | undefined
68
+ select?:
69
+ | NonEmptyReadonlyArray<
70
+ U | { key: string; subKeys: readonly string[] } | {
71
+ key: string
72
+ computed: ComputedProjectionIrExpression
73
+ }
74
+ >
75
+ | undefined
64
76
  order?: NonEmptyReadonlyArray<O<NoInfer<Encoded>>>
65
77
  limit?: number | undefined
66
78
  skip?: number | undefined
@@ -87,9 +99,14 @@ export interface Store<
87
99
  ) => Effect.Effect<NonEmptyReadonlyArray<PM>, OptimisticConcurrencyException>
88
100
  batchRemove: (ids: NonEmptyReadonlyArray<Encoded[IdKey]>, partitionKey?: string) => Effect.Effect<void>
89
101
  queryRaw: <Out>(query: RawQuery<Encoded, Out>) => Effect.Effect<readonly Out[]>
102
+ /**
103
+ * Explicitly seed a namespace. Primary is seeded eagerly on initialization.
104
+ * Non-primary namespaces must be seeded explicitly before use.
105
+ */
106
+ seedNamespace: (namespace: string) => Effect.Effect<void>
90
107
  }
91
108
 
92
- export class StoreMaker extends ServiceMap.Opaque<StoreMaker, {
109
+ export class StoreMaker extends Context.Opaque<StoreMaker, {
93
110
  make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
94
111
  name: string,
95
112
  idKey: IdKey,
@@ -161,16 +178,34 @@ export const makeContextMap = () => {
161
178
  // }
162
179
  // }
163
180
 
181
+ const store = new Map<symbol, unknown>()
182
+ const sem = Semaphore.makeUnsafe(1)
183
+
164
184
  return {
165
185
  get: getEtag,
166
- set: setEtag
167
- // parserEnv
186
+ set: setEtag,
187
+ getOrCreateStore: <T>(key: symbol, make: () => T): T => {
188
+ let value = store.get(key) as T | undefined
189
+ if (value === undefined) {
190
+ value = make()
191
+ store.set(key, value)
192
+ }
193
+ return value
194
+ },
195
+ getOrCreateStoreEffect: <T, E, R>(key: symbol, make: Effect.Effect<T, E, R>): Effect.Effect<T, E, R> =>
196
+ sem.withPermits(1)(Effect.uninterruptible(Effect.gen(function*() {
197
+ const value = store.get(key) as T | undefined
198
+ if (value !== undefined) return value
199
+ const v = yield* make
200
+ store.set(key, v)
201
+ return v
202
+ })))
168
203
  }
169
204
  }
170
205
 
171
206
  const makeMap = Effect.sync(() => makeContextMap())
172
207
 
173
- export class ContextMap extends ServiceMap.Opaque<ContextMap>()("effect-app/ContextMap", { make: makeMap }) {
208
+ export class ContextMap extends Context.Opaque<ContextMap>()("effect-app/ContextMap", { make: makeMap }) {
174
209
  }
175
210
 
176
211
  export type PersistenceModelType<Encoded extends object> = Encoded & {
@@ -178,7 +213,7 @@ export type PersistenceModelType<Encoded extends object> = Encoded & {
178
213
  }
179
214
 
180
215
  export interface StorageConfig {
181
- url: Redacted.Redacted<string>
216
+ url: Redacted.Redacted
182
217
  prefix: string
183
218
  dbName: string
184
219
  }
@@ -1,5 +1,6 @@
1
1
  import crypto from "crypto"
2
- import { Effect, Option } from "effect-app"
2
+ import * as Effect from "effect-app/Effect"
3
+ import * as Option from "effect-app/Option"
3
4
  import { OptimisticConcurrencyException } from "../errors.js"
4
5
  import type { PersistenceModelType, SupportedValues2 } from "./service.js"
5
6
 
@@ -12,33 +13,34 @@ export const makeETag = <E extends PersistenceModelType<{}>>(
12
13
  _etag: crypto.createHash("sha256").update(JSON.stringify(e)).digest("hex")
13
14
  }) as any
14
15
 
15
- export const makeUpdateETag =
16
- (type: string) =>
17
- <IdKey extends keyof E, E extends PersistenceModelType<{}>>(e: E, idKey: IdKey, current: Option.Option<E>) =>
18
- Effect.gen(function*() {
19
- if (e._etag) {
20
- if (Option.isNone(current)) {
21
- return yield* new OptimisticConcurrencyException({
22
- type,
23
- id: e[idKey] as string,
24
- current: "",
25
- found: e._etag,
26
- code: 409
27
- })
28
- }
29
- }
30
- if (Option.isSome(current) && current.value._etag !== e._etag) {
16
+ export const makeUpdateETag = (type: string) =>
17
+ Effect.fnUntraced(function*<IdKey extends keyof E, E extends PersistenceModelType<{}>>(
18
+ e: E,
19
+ idKey: IdKey,
20
+ current: Option.Option<E>
21
+ ) {
22
+ if (e._etag) {
23
+ if (Option.isNone(current)) {
31
24
  return yield* new OptimisticConcurrencyException({
32
25
  type,
33
- id: current.value[idKey] as string,
34
- current: current.value._etag,
26
+ id: e[idKey] as string,
27
+ current: "",
35
28
  found: e._etag,
36
- code: 412
29
+ code: 409
37
30
  })
38
31
  }
39
- const newE = makeETag(e)
40
- return newE
41
- })
32
+ }
33
+ if (Option.isSome(current) && current.value._etag !== e._etag) {
34
+ return yield* new OptimisticConcurrencyException({
35
+ type,
36
+ id: current.value[idKey] as string,
37
+ current: current.value._etag,
38
+ found: e._etag,
39
+ code: 412
40
+ })
41
+ }
42
+ return makeETag(e)
43
+ })
42
44
 
43
45
  export function lowercaseIfString<T>(val: T) {
44
46
  if (typeof val === "string") {
@@ -24,6 +24,7 @@ import * as VariantSchema from "effect/unstable/schema/VariantSchema"
24
24
  import { SqlClient } from "effect/unstable/sql/SqlClient"
25
25
  import * as SqlResolver from "effect/unstable/sql/SqlResolver"
26
26
  import * as SqlSchema from "effect/unstable/sql/SqlSchema"
27
+ import { type DbSystem, withDbSpan } from "../../otel.js"
27
28
 
28
29
  const {
29
30
  Class,
@@ -73,7 +74,7 @@ export {
73
74
  * @since 1.0.0
74
75
  * @category constructors
75
76
  * @example
76
- * import { Schema } from "effect"
77
+ * import * as Schema from "effect/Schema"
77
78
  * import { Model } from "effect/unstable/schema"
78
79
  *
79
80
  * export const GroupId = Schema.Number.pipe(Schema.brand("GroupId"))
@@ -545,9 +546,15 @@ export const DateTimeUpdateFromNumber: DateTimeUpdateFromNumber = Field({
545
546
  */
546
547
  export interface JsonFromString<S extends Schema.Top> extends
547
548
  VariantSchema.Field<{
548
- readonly select: Schema.fromJsonString<S>
549
- readonly insert: Schema.fromJsonString<S>
550
- readonly update: Schema.fromJsonString<S>
549
+ readonly select: Schema.fromJsonString<
550
+ Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
551
+ >
552
+ readonly insert: Schema.fromJsonString<
553
+ Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
554
+ >
555
+ readonly update: Schema.fromJsonString<
556
+ Schema.Codec<S["Type"], Schema.Json, S["DecodingServices"], S["EncodingServices"]>
557
+ >
551
558
  readonly json: S
552
559
  readonly jsonCreate: S
553
560
  readonly jsonUpdate: S
@@ -565,7 +572,7 @@ export interface JsonFromString<S extends Schema.Top> extends
565
572
  export const JsonFromString = <S extends Schema.Top>(
566
573
  schema: S
567
574
  ): JsonFromString<S> => {
568
- const parsed = Schema.fromJsonString(schema)
575
+ const parsed = Schema.fromJsonString(Schema.toCodecJson(schema))
569
576
  return Field({
570
577
  select: parsed,
571
578
  insert: parsed,
@@ -590,6 +597,7 @@ export const makeRepository = <
590
597
  readonly spanPrefix: string
591
598
  readonly idColumn: Id
592
599
  readonly versionColumn?: string | undefined
600
+ readonly dbSystem?: DbSystem | undefined
593
601
  }): Effect.Effect<
594
602
  {
595
603
  readonly insert: (
@@ -623,6 +631,15 @@ export const makeRepository = <
623
631
  const idSchema = Model.fields[options.idColumn] as Schema.Top
624
632
  const idColumn = options.idColumn as string
625
633
  const versionColumn = options.versionColumn
634
+ const system: DbSystem = options.dbSystem ?? "other_sql"
635
+ const opSpan = (operation: string, idValue?: unknown) =>
636
+ withDbSpan({
637
+ operation,
638
+ system,
639
+ collection: options.tableName,
640
+ entity: options.spanPrefix,
641
+ ...(idValue !== undefined && { extra: { "app.entity.id": idValue } })
642
+ })
626
643
 
627
644
  const insertSchema = SqlSchema.findOne({
628
645
  Request: Model.insert,
@@ -644,9 +661,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
644
661
  ): Effect.Effect<S["Type"], Schema.SchemaError, S["DecodingServices"] | S["insert"]["EncodingServices"]> =>
645
662
  insertSchema(insert).pipe(
646
663
  Effect.catchTag("NoSuchElementError", Effect.die),
647
- Effect.withSpan(`${options.spanPrefix}.insert`, {}, {
648
- captureStackTrace: false
649
- })
664
+ opSpan("insert")
650
665
  ) as any
651
666
 
652
667
  const insertVoidSchema = SqlSchema.void({
@@ -657,9 +672,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
657
672
  insert: S["insert"]["Type"]
658
673
  ): Effect.Effect<void, Schema.SchemaError, S["insert"]["EncodingServices"]> =>
659
674
  insertVoidSchema(insert).pipe(
660
- Effect.withSpan(`${options.spanPrefix}.insertVoid`, {}, {
661
- captureStackTrace: false
662
- })
675
+ opSpan("insertVoid")
663
676
  ) as any
664
677
 
665
678
  const updateSchema = SqlSchema.findOne({
@@ -706,11 +719,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
706
719
  ): Effect.Effect<S["Type"], Schema.SchemaError, S["DecodingServices"] | S["update"]["EncodingServices"]> =>
707
720
  updateSchema(update).pipe(
708
721
  Effect.catchTag("NoSuchElementError", Effect.die),
709
- Effect.withSpan(`${options.spanPrefix}.update`, {
710
- attributes: { id: (update as any)[idColumn] }
711
- }, {
712
- captureStackTrace: false
713
- })
722
+ opSpan("update", (update as any)[idColumn])
714
723
  ) as any
715
724
 
716
725
  const updateVoidSchema = SqlSchema.void({
@@ -729,11 +738,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
729
738
  update: S["update"]["Type"]
730
739
  ): Effect.Effect<void, Schema.SchemaError, S["update"]["EncodingServices"]> =>
731
740
  updateVoidSchema(update).pipe(
732
- Effect.withSpan(`${options.spanPrefix}.updateVoid`, {
733
- attributes: { id: (update as any)[idColumn] }
734
- }, {
735
- captureStackTrace: false
736
- })
741
+ opSpan("updateVoid", (update as any)[idColumn])
737
742
  ) as any
738
743
 
739
744
  const findByIdSchema = SqlSchema.findOneOption({
@@ -749,9 +754,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
749
754
  S["DecodingServices"] | S["fields"][Id]["EncodingServices"]
750
755
  > =>
751
756
  findByIdSchema(id).pipe(
752
- Effect.withSpan(`${options.spanPrefix}.findById`, { attributes: { id } }, {
753
- captureStackTrace: false
754
- })
757
+ opSpan("findById", id)
755
758
  ) as any
756
759
 
757
760
  const deleteSchema = SqlSchema.void({
@@ -762,11 +765,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = ${request[idCol
762
765
  id: S["fields"][Id]["Type"]
763
766
  ): Effect.Effect<void, Schema.SchemaError, S["fields"][Id]["EncodingServices"]> =>
764
767
  deleteSchema(id).pipe(
765
- Effect.withSpan(`${options.spanPrefix}.delete`, {
766
- attributes: { id }
767
- }, {
768
- captureStackTrace: false
769
- })
768
+ opSpan("delete", id)
770
769
  ) as any
771
770
 
772
771
  return { insert, insertVoid, update, updateVoid, findById, delete: delete_ } as const
@@ -789,6 +788,7 @@ export const makeDataLoaders = <
789
788
  readonly idColumn: Id
790
789
  readonly window: Input
791
790
  readonly maxBatchSize?: number | undefined
791
+ readonly dbSystem?: DbSystem | undefined
792
792
  }
793
793
  ): Effect.Effect<
794
794
  {
@@ -821,6 +821,15 @@ export const makeDataLoaders = <
821
821
  const idSchema = Model.fields[options.idColumn] as Schema.Top
822
822
  const idColumn = options.idColumn as string
823
823
  const setMaxBatchSize = options.maxBatchSize ? RequestResolver.batchN(options.maxBatchSize) : identity
824
+ const system: DbSystem = options.dbSystem ?? "other_sql"
825
+ const opSpan = (operation: string, idValue?: unknown) =>
826
+ withDbSpan({
827
+ operation,
828
+ system,
829
+ collection: options.tableName,
830
+ entity: options.spanPrefix,
831
+ ...(idValue !== undefined && { extra: { "app.entity.id": idValue } })
832
+ })
824
833
 
825
834
  const insertResolver = SqlResolver
826
835
  .ordered({
@@ -854,9 +863,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
854
863
  > =>
855
864
  insertExecute(insert).pipe(
856
865
  Effect.catchTag("ResultLengthMismatch", Effect.die),
857
- Effect.withSpan(`${options.spanPrefix}.insert`, {}, {
858
- captureStackTrace: false
859
- })
866
+ opSpan("insert")
860
867
  ) as any
861
868
 
862
869
  const insertVoidResolver = SqlResolver
@@ -874,9 +881,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
874
881
  insert: S["insert"]["Type"]
875
882
  ): Effect.Effect<void, Schema.SchemaError, S["insert"]["EncodingServices"]> =>
876
883
  insertVoidExecute(insert).pipe(
877
- Effect.withSpan(`${options.spanPrefix}.insertVoid`, {}, {
878
- captureStackTrace: false
879
- })
884
+ opSpan("insertVoid")
880
885
  ) as any
881
886
 
882
887
  const findByIdResolver = SqlResolver
@@ -902,9 +907,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
902
907
  S["DecodingServices"] | S["fields"][Id]["EncodingServices"]
903
908
  > =>
904
909
  findByIdExecute(id).pipe(
905
- Effect.withSpan(`${options.spanPrefix}.findById`, { attributes: { id } }, {
906
- captureStackTrace: false
907
- })
910
+ opSpan("findById", id)
908
911
  ) as any
909
912
 
910
913
  const deleteResolver = SqlResolver
@@ -922,9 +925,7 @@ select * from ${sql(options.tableName)} where ${sql(idColumn)} = LAST_INSERT_ID(
922
925
  id: S["fields"][Id]["Type"]
923
926
  ): Effect.Effect<void, Schema.SchemaError, S["fields"][Id]["EncodingServices"]> =>
924
927
  deleteExecute(id).pipe(
925
- Effect.withSpan(`${options.spanPrefix}.delete`, { attributes: { id } }, {
926
- captureStackTrace: false
927
- })
928
+ opSpan("delete", id)
928
929
  ) as any
929
930
 
930
931
  return { insert, insertVoid, findById, delete: delete_ } as const