@effect-app/infra 4.0.0-beta.21 → 4.0.0-beta.211

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 (309) hide show
  1. package/CHANGELOG.md +1556 -0
  2. package/_check.sh +1 -1
  3. package/dist/CUPS.d.ts +7 -7
  4. package/dist/CUPS.d.ts.map +1 -1
  5. package/dist/CUPS.js +10 -12
  6. package/dist/Emailer/Sendgrid.d.ts +14 -14
  7. package/dist/Emailer/Sendgrid.d.ts.map +1 -1
  8. package/dist/Emailer/Sendgrid.js +16 -15
  9. package/dist/Emailer/fake.d.ts +1 -1
  10. package/dist/Emailer/service.d.ts +10 -4
  11. package/dist/Emailer/service.d.ts.map +1 -1
  12. package/dist/Emailer/service.js +3 -3
  13. package/dist/Emailer.d.ts +1 -1
  14. package/dist/MainFiberSet.d.ts +9 -9
  15. package/dist/MainFiberSet.d.ts.map +1 -1
  16. package/dist/MainFiberSet.js +3 -3
  17. package/dist/Model/Repository/Registry.d.ts +20 -0
  18. package/dist/Model/Repository/Registry.d.ts.map +1 -0
  19. package/dist/Model/Repository/Registry.js +17 -0
  20. package/dist/Model/Repository/ext.d.ts +33 -15
  21. package/dist/Model/Repository/ext.d.ts.map +1 -1
  22. package/dist/Model/Repository/ext.js +54 -2
  23. package/dist/Model/Repository/internal/internal.d.ts +6 -6
  24. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  25. package/dist/Model/Repository/internal/internal.js +98 -50
  26. package/dist/Model/Repository/legacy.d.ts +1 -1
  27. package/dist/Model/Repository/makeRepo.d.ts +7 -6
  28. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.js +5 -1
  30. package/dist/Model/Repository/service.d.ts +28 -23
  31. package/dist/Model/Repository/service.d.ts.map +1 -1
  32. package/dist/Model/Repository/validation.d.ts +46 -17
  33. package/dist/Model/Repository/validation.d.ts.map +1 -1
  34. package/dist/Model/Repository/validation.js +5 -5
  35. package/dist/Model/Repository.d.ts +2 -1
  36. package/dist/Model/Repository.d.ts.map +1 -1
  37. package/dist/Model/Repository.js +2 -1
  38. package/dist/Model/dsl.d.ts +4 -4
  39. package/dist/Model/dsl.d.ts.map +1 -1
  40. package/dist/Model/filter/filterApi.d.ts +5 -5
  41. package/dist/Model/filter/filterApi.d.ts.map +1 -1
  42. package/dist/Model/filter/types/errors.d.ts +1 -1
  43. package/dist/Model/filter/types/fields.d.ts +1 -1
  44. package/dist/Model/filter/types/path/common.d.ts +1 -1
  45. package/dist/Model/filter/types/path/eager.d.ts +1 -1
  46. package/dist/Model/filter/types/path/eager.d.ts.map +1 -1
  47. package/dist/Model/filter/types/path/eager.js +1 -1
  48. package/dist/Model/filter/types/path/index.d.ts +1 -1
  49. package/dist/Model/filter/types/utils.d.ts +1 -1
  50. package/dist/Model/filter/types/validator.d.ts +1 -1
  51. package/dist/Model/filter/types.d.ts +1 -1
  52. package/dist/Model/query/dsl.d.ts +16 -16
  53. package/dist/Model/query/dsl.d.ts.map +1 -1
  54. package/dist/Model/query/new-kid-interpreter.d.ts +6 -6
  55. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  56. package/dist/Model/query/new-kid-interpreter.js +3 -3
  57. package/dist/Model/query.d.ts +1 -1
  58. package/dist/Model.d.ts +2 -1
  59. package/dist/Model.d.ts.map +1 -1
  60. package/dist/Model.js +2 -1
  61. package/dist/QueueMaker/SQLQueue.d.ts +5 -7
  62. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  63. package/dist/QueueMaker/SQLQueue.js +130 -116
  64. package/dist/QueueMaker/errors.d.ts +2 -2
  65. package/dist/QueueMaker/errors.d.ts.map +1 -1
  66. package/dist/QueueMaker/memQueue.d.ts +7 -4
  67. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  68. package/dist/QueueMaker/memQueue.js +75 -63
  69. package/dist/QueueMaker/sbqueue.d.ts +6 -3
  70. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  71. package/dist/QueueMaker/sbqueue.js +52 -53
  72. package/dist/QueueMaker/service.d.ts +1 -1
  73. package/dist/RequestContext.d.ts +74 -35
  74. package/dist/RequestContext.d.ts.map +1 -1
  75. package/dist/RequestContext.js +13 -14
  76. package/dist/RequestFiberSet.d.ts +7 -7
  77. package/dist/RequestFiberSet.d.ts.map +1 -1
  78. package/dist/RequestFiberSet.js +3 -3
  79. package/dist/Store/ContextMapContainer.d.ts +19 -3
  80. package/dist/Store/ContextMapContainer.d.ts.map +1 -1
  81. package/dist/Store/ContextMapContainer.js +13 -3
  82. package/dist/Store/Cosmos/query.d.ts +1 -1
  83. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  84. package/dist/Store/Cosmos/query.js +10 -12
  85. package/dist/Store/Cosmos.d.ts +1 -1
  86. package/dist/Store/Cosmos.d.ts.map +1 -1
  87. package/dist/Store/Cosmos.js +335 -243
  88. package/dist/Store/Disk.d.ts +2 -2
  89. package/dist/Store/Disk.d.ts.map +1 -1
  90. package/dist/Store/Disk.js +72 -35
  91. package/dist/Store/Memory.d.ts +6 -4
  92. package/dist/Store/Memory.d.ts.map +1 -1
  93. package/dist/Store/Memory.js +90 -57
  94. package/dist/Store/SQL/Pg.d.ts +4 -0
  95. package/dist/Store/SQL/Pg.d.ts.map +1 -0
  96. package/dist/Store/SQL/Pg.js +231 -0
  97. package/dist/Store/SQL/query.d.ts +38 -0
  98. package/dist/Store/SQL/query.d.ts.map +1 -0
  99. package/dist/Store/SQL/query.js +367 -0
  100. package/dist/Store/SQL.d.ts +20 -0
  101. package/dist/Store/SQL.d.ts.map +1 -0
  102. package/dist/Store/SQL.js +464 -0
  103. package/dist/Store/codeFilter.d.ts +1 -1
  104. package/dist/Store/codeFilter.d.ts.map +1 -1
  105. package/dist/Store/codeFilter.js +4 -2
  106. package/dist/Store/index.d.ts +5 -2
  107. package/dist/Store/index.d.ts.map +1 -1
  108. package/dist/Store/index.js +15 -3
  109. package/dist/Store/service.d.ts +18 -7
  110. package/dist/Store/service.d.ts.map +1 -1
  111. package/dist/Store/service.js +24 -6
  112. package/dist/Store/utils.d.ts +1 -1
  113. package/dist/Store/utils.d.ts.map +1 -1
  114. package/dist/Store/utils.js +3 -4
  115. package/dist/Store.d.ts +1 -1
  116. package/dist/adapters/SQL/Model.d.ts +31 -42
  117. package/dist/adapters/SQL/Model.d.ts.map +1 -1
  118. package/dist/adapters/SQL/Model.js +29 -38
  119. package/dist/adapters/SQL.d.ts +1 -1
  120. package/dist/adapters/ServiceBus.d.ts +11 -11
  121. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  122. package/dist/adapters/ServiceBus.js +25 -21
  123. package/dist/adapters/cosmos-client.d.ts +3 -3
  124. package/dist/adapters/cosmos-client.d.ts.map +1 -1
  125. package/dist/adapters/cosmos-client.js +3 -3
  126. package/dist/adapters/index.d.ts +8 -2
  127. package/dist/adapters/index.d.ts.map +1 -1
  128. package/dist/adapters/index.js +8 -2
  129. package/dist/adapters/logger.d.ts +2 -2
  130. package/dist/adapters/logger.d.ts.map +1 -1
  131. package/dist/adapters/memQueue.d.ts +3 -3
  132. package/dist/adapters/memQueue.d.ts.map +1 -1
  133. package/dist/adapters/memQueue.js +3 -3
  134. package/dist/adapters/mongo-client.d.ts +3 -3
  135. package/dist/adapters/mongo-client.d.ts.map +1 -1
  136. package/dist/adapters/mongo-client.js +3 -3
  137. package/dist/adapters/redis-client.d.ts +3 -3
  138. package/dist/adapters/redis-client.d.ts.map +1 -1
  139. package/dist/adapters/redis-client.js +3 -3
  140. package/dist/api/ContextProvider.d.ts +8 -8
  141. package/dist/api/ContextProvider.d.ts.map +1 -1
  142. package/dist/api/ContextProvider.js +6 -6
  143. package/dist/api/codec.d.ts +1 -1
  144. package/dist/api/internal/RequestContextMiddleware.d.ts +2 -2
  145. package/dist/api/internal/RequestContextMiddleware.d.ts.map +1 -1
  146. package/dist/api/internal/RequestContextMiddleware.js +2 -2
  147. package/dist/api/internal/auth.d.ts +44 -6
  148. package/dist/api/internal/auth.d.ts.map +1 -1
  149. package/dist/api/internal/auth.js +160 -29
  150. package/dist/api/internal/events.d.ts +3 -3
  151. package/dist/api/internal/events.d.ts.map +1 -1
  152. package/dist/api/internal/events.js +10 -8
  153. package/dist/api/internal/health.d.ts +1 -1
  154. package/dist/api/layerUtils.d.ts +6 -6
  155. package/dist/api/layerUtils.d.ts.map +1 -1
  156. package/dist/api/layerUtils.js +5 -5
  157. package/dist/api/middlewares.d.ts +1 -1
  158. package/dist/api/reportError.d.ts +1 -1
  159. package/dist/api/routing/middleware/RouterMiddleware.d.ts +4 -4
  160. package/dist/api/routing/middleware/RouterMiddleware.d.ts.map +1 -1
  161. package/dist/api/routing/middleware/middleware.d.ts +39 -3
  162. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  163. package/dist/api/routing/middleware/middleware.js +48 -16
  164. package/dist/api/routing/middleware.d.ts +1 -2
  165. package/dist/api/routing/middleware.d.ts.map +1 -1
  166. package/dist/api/routing/middleware.js +1 -2
  167. package/dist/api/routing/schema/jwt.d.ts +1 -1
  168. package/dist/api/routing/schema/jwt.d.ts.map +1 -1
  169. package/dist/api/routing/tsort.d.ts +1 -1
  170. package/dist/api/routing/tsort.d.ts.map +1 -1
  171. package/dist/api/routing/utils.d.ts +3 -3
  172. package/dist/api/routing/utils.d.ts.map +1 -1
  173. package/dist/api/routing.d.ts +80 -37
  174. package/dist/api/routing.d.ts.map +1 -1
  175. package/dist/api/routing.js +112 -40
  176. package/dist/api/setupRequest.d.ts +8 -5
  177. package/dist/api/setupRequest.d.ts.map +1 -1
  178. package/dist/api/setupRequest.js +12 -7
  179. package/dist/api/util.d.ts +1 -1
  180. package/dist/arbs.d.ts +1 -1
  181. package/dist/arbs.d.ts.map +1 -1
  182. package/dist/arbs.js +5 -3
  183. package/dist/errorReporter.d.ts +4 -4
  184. package/dist/errorReporter.d.ts.map +1 -1
  185. package/dist/errorReporter.js +20 -25
  186. package/dist/errors.d.ts +1 -1
  187. package/dist/fileUtil.d.ts +1 -1
  188. package/dist/fileUtil.d.ts.map +1 -1
  189. package/dist/index.d.ts +1 -1
  190. package/dist/logger/jsonLogger.d.ts +1 -1
  191. package/dist/logger/logFmtLogger.d.ts +1 -1
  192. package/dist/logger/shared.d.ts +1 -1
  193. package/dist/logger/shared.js +2 -2
  194. package/dist/logger.d.ts +1 -1
  195. package/dist/logger.d.ts.map +1 -1
  196. package/dist/otel.d.ts +75 -0
  197. package/dist/otel.d.ts.map +1 -0
  198. package/dist/otel.js +65 -0
  199. package/dist/rateLimit.d.ts +9 -3
  200. package/dist/rateLimit.d.ts.map +1 -1
  201. package/dist/rateLimit.js +5 -11
  202. package/dist/test.d.ts +2 -2
  203. package/dist/test.d.ts.map +1 -1
  204. package/dist/test.js +1 -1
  205. package/dist/vitest.d.ts +1 -1
  206. package/examples/query.ts +39 -35
  207. package/package.json +45 -37
  208. package/src/CUPS.ts +9 -11
  209. package/src/Emailer/Sendgrid.ts +17 -14
  210. package/src/Emailer/service.ts +9 -3
  211. package/src/MainFiberSet.ts +5 -6
  212. package/src/Model/Repository/Registry.ts +33 -0
  213. package/src/Model/Repository/ext.ts +96 -10
  214. package/src/Model/Repository/internal/internal.ts +213 -148
  215. package/src/Model/Repository/makeRepo.ts +12 -10
  216. package/src/Model/Repository/service.ts +31 -22
  217. package/src/Model/Repository/validation.ts +4 -4
  218. package/src/Model/Repository.ts +1 -0
  219. package/src/Model/dsl.ts +3 -3
  220. package/src/Model/filter/types/path/eager.ts +1 -2
  221. package/src/Model/query/dsl.ts +18 -18
  222. package/src/Model/query/new-kid-interpreter.ts +2 -2
  223. package/src/Model.ts +1 -0
  224. package/src/QueueMaker/SQLQueue.ts +144 -152
  225. package/src/QueueMaker/memQueue.ts +104 -103
  226. package/src/QueueMaker/sbqueue.ts +70 -86
  227. package/src/RequestContext.ts +14 -16
  228. package/src/RequestFiberSet.ts +2 -2
  229. package/src/Store/ContextMapContainer.ts +41 -2
  230. package/src/Store/Cosmos/query.ts +16 -20
  231. package/src/Store/Cosmos.ts +473 -348
  232. package/src/Store/Disk.ts +102 -65
  233. package/src/Store/Memory.ts +118 -83
  234. package/src/Store/SQL/Pg.ts +352 -0
  235. package/src/Store/SQL/query.ts +409 -0
  236. package/src/Store/SQL.ts +734 -0
  237. package/src/Store/codeFilter.ts +3 -1
  238. package/src/Store/index.ts +17 -2
  239. package/src/Store/service.ts +32 -8
  240. package/src/Store/utils.ts +23 -22
  241. package/src/adapters/SQL/Model.ts +41 -40
  242. package/src/adapters/ServiceBus.ts +125 -121
  243. package/src/adapters/cosmos-client.ts +2 -2
  244. package/src/adapters/index.ts +7 -0
  245. package/src/adapters/memQueue.ts +2 -2
  246. package/src/adapters/mongo-client.ts +2 -2
  247. package/src/adapters/redis-client.ts +2 -2
  248. package/src/api/ContextProvider.ts +12 -13
  249. package/src/api/internal/RequestContextMiddleware.ts +1 -1
  250. package/src/api/internal/auth.ts +246 -44
  251. package/src/api/internal/events.ts +13 -9
  252. package/src/api/layerUtils.ts +8 -8
  253. package/src/api/routing/middleware/RouterMiddleware.ts +4 -4
  254. package/src/api/routing/middleware/middleware.ts +55 -14
  255. package/src/api/routing/middleware.ts +0 -2
  256. package/src/api/routing.ts +298 -128
  257. package/src/api/setupRequest.ts +28 -8
  258. package/src/arbs.ts +4 -2
  259. package/src/errorReporter.ts +62 -74
  260. package/src/logger/shared.ts +1 -1
  261. package/src/otel.ts +152 -0
  262. package/src/rateLimit.ts +30 -22
  263. package/src/test.ts +1 -1
  264. package/test/auth.test.ts +101 -0
  265. package/test/contextProvider.test.ts +11 -11
  266. package/test/controller.test.ts +21 -30
  267. package/test/dist/auth.test.d.ts.map +1 -0
  268. package/test/dist/contextProvider.test.d.ts.map +1 -1
  269. package/test/dist/controller.test.d.ts.map +1 -1
  270. package/test/dist/date-query.test.d.ts.map +1 -0
  271. package/test/dist/fixtures.d.ts +26 -12
  272. package/test/dist/fixtures.d.ts.map +1 -1
  273. package/test/dist/fixtures.js +12 -10
  274. package/test/dist/query.test.d.ts.map +1 -1
  275. package/test/dist/rawQuery.test.d.ts.map +1 -1
  276. package/test/dist/repository-ext.test.d.ts.map +1 -0
  277. package/test/dist/requires.test.d.ts.map +1 -1
  278. package/test/dist/router-generator.test.d.ts.map +1 -0
  279. package/test/dist/routing-interruptibility.test.d.ts.map +1 -0
  280. package/test/dist/rpc-e2e-invalidation.test.d.ts.map +1 -0
  281. package/test/dist/rpc-multi-middleware.test.d.ts.map +1 -1
  282. package/test/dist/rpc-stream-fullstack.test.d.ts.map +1 -0
  283. package/test/dist/sql-store.test.d.ts.map +1 -0
  284. package/test/fixtures.ts +11 -9
  285. package/test/query.test.ts +216 -34
  286. package/test/rawQuery.test.ts +23 -19
  287. package/test/repository-ext.test.ts +60 -0
  288. package/test/requires.test.ts +6 -6
  289. package/test/router-generator.test.ts +183 -0
  290. package/test/routing-interruptibility.test.ts +63 -0
  291. package/test/rpc-e2e-invalidation.test.ts +251 -0
  292. package/test/rpc-multi-middleware.test.ts +78 -9
  293. package/test/rpc-stream-fullstack.test.ts +300 -0
  294. package/test/sql-store.test.ts +1064 -0
  295. package/test/validateSample.test.ts +15 -12
  296. package/tsconfig.examples.json +1 -1
  297. package/tsconfig.json +0 -1
  298. package/tsconfig.json.bak +2 -2
  299. package/tsconfig.src.json +35 -35
  300. package/tsconfig.test.json +2 -2
  301. package/dist/Operations.d.ts +0 -55
  302. package/dist/Operations.d.ts.map +0 -1
  303. package/dist/Operations.js +0 -102
  304. package/dist/OperationsRepo.d.ts +0 -41
  305. package/dist/OperationsRepo.d.ts.map +0 -1
  306. package/dist/OperationsRepo.js +0 -14
  307. package/eslint.config.mjs +0 -24
  308. package/src/Operations.ts +0 -235
  309. package/src/OperationsRepo.ts +0 -16
@@ -1,9 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
3
3
  import { Array, Option } from "effect-app"
4
- import { assertUnreachable, get } from "effect-app/utils"
4
+ import { assertUnreachable } from "effect-app/utils"
5
5
  import type { FilterR, FilterResult } from "../Model/filter/filterApi.js"
6
6
  import type { FieldValues } from "../Model/filter/types.js"
7
+ import { get } from "./Memory.js"
7
8
  import type { Filter } from "./service.js"
8
9
  import { compare, greaterThan, greaterThanExclusive, lowerThan, lowerThanExclusive } from "./utils.js"
9
10
 
@@ -186,6 +187,7 @@ export const codeFilter3_ = <E>(state: readonly FilterResult[], sut: E): boolean
186
187
  const statements: any[] = [] // must be defined here to be used by eval.
187
188
  // always put everything inside a root scope.
188
189
  const s = codeFilter3__([{ t: "where-scope", result: state, relation: "some" }], sut, statements, null, false)
190
+ // oxlint-disable-next-line no-eval
189
191
  return eval(s)
190
192
  }
191
193
 
@@ -1,12 +1,19 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import { Effect, Layer, Redacted } from "effect-app"
3
+ import type { SqlClient } from "effect/unstable/sql"
3
4
  import { CosmosStoreLayer } from "./Cosmos.js"
4
5
  import { DiskStoreLayer } from "./Disk.js"
5
6
  import { MemoryStoreLive } from "./Memory.js"
6
7
  // import { RedisStoreLayer } from "./Redis.js"
8
+ import { RepositoryRegistryLive } from "../Model.js"
7
9
  import type { StorageConfig } from "./service.js"
10
+ import { SQLiteStoreLayer } from "./SQL.js"
11
+ import { PgStoreLayer } from "./SQL/Pg.js"
8
12
 
9
- export function StoreMakerLayer(cfg: StorageConfig) {
13
+ export function StoreMakerLayer(
14
+ cfg: StorageConfig,
15
+ options?: { makeSqlClientLayer?: (namespace: string) => Layer.Layer<SqlClient.SqlClient> }
16
+ ) {
10
17
  return Effect
11
18
  .sync(() => {
12
19
  const storageUrl = Redacted.value(cfg.url)
@@ -19,6 +26,14 @@ export function StoreMakerLayer(cfg: StorageConfig) {
19
26
  console.log("Using disk store at " + dir)
20
27
  return DiskStoreLayer(cfg, dir)
21
28
  }
29
+ if (storageUrl.startsWith("sqlite://")) {
30
+ console.log("Using SQLite store")
31
+ return SQLiteStoreLayer(cfg, options)
32
+ }
33
+ if (storageUrl.startsWith("pg://")) {
34
+ console.log("Using PostgreSQL store")
35
+ return PgStoreLayer(cfg)
36
+ }
22
37
  // if (storageUrl.startsWith("redis://")) {
23
38
  // console.log("Using Redis store")
24
39
  // return RedisStoreLayer(cfg)
@@ -27,7 +42,7 @@ export function StoreMakerLayer(cfg: StorageConfig) {
27
42
  console.log("Using Cosmos DB store")
28
43
  return CosmosStoreLayer(cfg)
29
44
  })
30
- .pipe(Layer.unwrap)
45
+ .pipe(Layer.unwrap, Layer.merge(RepositoryRegistryLive))
31
46
  }
32
47
 
33
48
  export * from "./service.js"
@@ -1,6 +1,7 @@
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 { Context, Effect, type NonEmptyReadonlyArray, type Option, type Redacted } from "effect-app"
4
+ import * as Semaphore from "effect/Semaphore"
4
5
  import type { OptimisticConcurrencyException } from "../errors.js"
5
6
  import type { FilterResult } from "../Model/filter/filterApi.js"
6
7
  import type { FieldValues } from "../Model/filter/types.js"
@@ -10,8 +11,8 @@ import { type RawQuery } from "../Model/query.js"
10
11
  export interface StoreConfig<E> {
11
12
  partitionValue: (e?: E) => string
12
13
  /**
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.
14
+ * Primarily used for testing, creating namespaces in the database to separate data e.g to run multiple tests in isolation within the same database.
15
+ * Memory/Disk use separate store instances per namespace. CosmosDB uses namespace-prefixed partition keys. SQL uses a `_namespace` column.
15
16
  */
16
17
  allowNamespace?: (namespace: string) => boolean
17
18
  /**
@@ -87,9 +88,14 @@ export interface Store<
87
88
  ) => Effect.Effect<NonEmptyReadonlyArray<PM>, OptimisticConcurrencyException>
88
89
  batchRemove: (ids: NonEmptyReadonlyArray<Encoded[IdKey]>, partitionKey?: string) => Effect.Effect<void>
89
90
  queryRaw: <Out>(query: RawQuery<Encoded, Out>) => Effect.Effect<readonly Out[]>
91
+ /**
92
+ * Explicitly seed a namespace. Primary is seeded eagerly on initialization.
93
+ * Non-primary namespaces must be seeded explicitly before use.
94
+ */
95
+ seedNamespace: (namespace: string) => Effect.Effect<void>
90
96
  }
91
97
 
92
- export class StoreMaker extends ServiceMap.Opaque<StoreMaker, {
98
+ export class StoreMaker extends Context.Opaque<StoreMaker, {
93
99
  make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
94
100
  name: string,
95
101
  idKey: IdKey,
@@ -161,16 +167,34 @@ export const makeContextMap = () => {
161
167
  // }
162
168
  // }
163
169
 
170
+ const store = new Map<symbol, unknown>()
171
+ const sem = Semaphore.makeUnsafe(1)
172
+
164
173
  return {
165
174
  get: getEtag,
166
- set: setEtag
167
- // parserEnv
175
+ set: setEtag,
176
+ getOrCreateStore: <T>(key: symbol, make: () => T): T => {
177
+ let value = store.get(key) as T | undefined
178
+ if (value === undefined) {
179
+ value = make()
180
+ store.set(key, value)
181
+ }
182
+ return value
183
+ },
184
+ getOrCreateStoreEffect: <T, E, R>(key: symbol, make: Effect.Effect<T, E, R>): Effect.Effect<T, E, R> =>
185
+ sem.withPermits(1)(Effect.uninterruptible(Effect.gen(function*() {
186
+ const value = store.get(key) as T | undefined
187
+ if (value !== undefined) return value
188
+ const v = yield* make
189
+ store.set(key, v)
190
+ return v
191
+ })))
168
192
  }
169
193
  }
170
194
 
171
195
  const makeMap = Effect.sync(() => makeContextMap())
172
196
 
173
- export class ContextMap extends ServiceMap.Opaque<ContextMap>()("effect-app/ContextMap", { make: makeMap }) {
197
+ export class ContextMap extends Context.Opaque<ContextMap>()("effect-app/ContextMap", { make: makeMap }) {
174
198
  }
175
199
 
176
200
  export type PersistenceModelType<Encoded extends object> = Encoded & {
@@ -178,7 +202,7 @@ export type PersistenceModelType<Encoded extends object> = Encoded & {
178
202
  }
179
203
 
180
204
  export interface StorageConfig {
181
- url: Redacted.Redacted<string>
205
+ url: Redacted.Redacted
182
206
  prefix: string
183
207
  dbName: string
184
208
  }
@@ -12,33 +12,34 @@ export const makeETag = <E extends PersistenceModelType<{}>>(
12
12
  _etag: crypto.createHash("sha256").update(JSON.stringify(e)).digest("hex")
13
13
  }) as any
14
14
 
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) {
15
+ export const makeUpdateETag = (type: string) =>
16
+ Effect.fnUntraced(function*<IdKey extends keyof E, E extends PersistenceModelType<{}>>(
17
+ e: E,
18
+ idKey: IdKey,
19
+ current: Option.Option<E>
20
+ ) {
21
+ if (e._etag) {
22
+ if (Option.isNone(current)) {
31
23
  return yield* new OptimisticConcurrencyException({
32
24
  type,
33
- id: current.value[idKey] as string,
34
- current: current.value._etag,
25
+ id: e[idKey] as string,
26
+ current: "",
35
27
  found: e._etag,
36
- code: 412
28
+ code: 409
37
29
  })
38
30
  }
39
- const newE = makeETag(e)
40
- return newE
41
- })
31
+ }
32
+ if (Option.isSome(current) && current.value._etag !== e._etag) {
33
+ return yield* new OptimisticConcurrencyException({
34
+ type,
35
+ id: current.value[idKey] as string,
36
+ current: current.value._etag,
37
+ found: e._etag,
38
+ code: 412
39
+ })
40
+ }
41
+ return makeETag(e)
42
+ })
42
43
 
43
44
  export function lowercaseIfString<T>(val: T) {
44
45
  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,
@@ -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