@effect-app/infra 4.0.0-beta.121 → 4.0.0-beta.123

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 (74) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/CUPS.d.ts.map +1 -1
  3. package/dist/CUPS.js +8 -10
  4. package/dist/Model/Repository/ext.d.ts +15 -3
  5. package/dist/Model/Repository/ext.d.ts.map +1 -1
  6. package/dist/Model/Repository/ext.js +25 -2
  7. package/dist/Model/Repository/internal/internal.d.ts +1 -1
  8. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  9. package/dist/Model/Repository/internal/internal.js +9 -8
  10. package/dist/Model/Repository/makeRepo.d.ts +3 -3
  11. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  12. package/dist/Model/Repository/service.d.ts +21 -21
  13. package/dist/Model/Repository/service.d.ts.map +1 -1
  14. package/dist/Model/query/new-kid-interpreter.d.ts +2 -2
  15. package/dist/Operations.d.ts +2 -2
  16. package/dist/Operations.d.ts.map +1 -1
  17. package/dist/Operations.js +54 -57
  18. package/dist/OperationsRepo.d.ts +2 -2
  19. package/dist/QueueMaker/SQLQueue.d.ts +2 -3
  20. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  21. package/dist/QueueMaker/SQLQueue.js +104 -115
  22. package/dist/QueueMaker/memQueue.d.ts +2 -2
  23. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  24. package/dist/QueueMaker/memQueue.js +51 -62
  25. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  26. package/dist/QueueMaker/sbqueue.js +34 -50
  27. package/dist/Store/ContextMapContainer.d.ts +1 -1
  28. package/dist/Store/Cosmos.d.ts.map +1 -1
  29. package/dist/Store/Cosmos.js +304 -306
  30. package/dist/Store/Disk.d.ts +1 -1
  31. package/dist/Store/Disk.d.ts.map +1 -1
  32. package/dist/Store/Disk.js +2 -2
  33. package/dist/Store/Memory.d.ts +1 -1
  34. package/dist/Store/Memory.d.ts.map +1 -1
  35. package/dist/Store/Memory.js +2 -2
  36. package/dist/Store/SQL/Pg.d.ts.map +1 -1
  37. package/dist/Store/SQL/Pg.js +147 -149
  38. package/dist/Store/SQL.d.ts.map +1 -1
  39. package/dist/Store/SQL.js +6 -6
  40. package/dist/Store/utils.d.ts.map +1 -1
  41. package/dist/Store/utils.js +3 -4
  42. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  43. package/dist/adapters/ServiceBus.js +7 -9
  44. package/dist/api/internal/auth.d.ts.map +1 -1
  45. package/dist/api/internal/auth.js +1 -1
  46. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  47. package/dist/api/routing/middleware/middleware.js +2 -2
  48. package/dist/errorReporter.d.ts +3 -3
  49. package/dist/errorReporter.d.ts.map +1 -1
  50. package/dist/errorReporter.js +16 -23
  51. package/package.json +14 -14
  52. package/src/CUPS.ts +7 -9
  53. package/src/Model/Repository/ext.ts +71 -6
  54. package/src/Model/Repository/internal/internal.ts +13 -25
  55. package/src/Model/Repository/makeRepo.ts +4 -4
  56. package/src/Model/Repository/service.ts +22 -21
  57. package/src/Operations.ts +76 -111
  58. package/src/QueueMaker/SQLQueue.ts +119 -150
  59. package/src/QueueMaker/memQueue.ts +81 -102
  60. package/src/QueueMaker/sbqueue.ts +51 -81
  61. package/src/Store/Cosmos.ts +481 -484
  62. package/src/Store/Disk.ts +52 -53
  63. package/src/Store/Memory.ts +49 -50
  64. package/src/Store/SQL/Pg.ts +247 -250
  65. package/src/Store/SQL.ts +420 -426
  66. package/src/Store/utils.ts +23 -22
  67. package/src/adapters/ServiceBus.ts +106 -110
  68. package/src/api/internal/auth.ts +8 -6
  69. package/src/api/routing/middleware/middleware.ts +10 -11
  70. package/src/errorReporter.ts +58 -72
  71. package/test/dist/auth.test.d.ts.map +1 -0
  72. package/test/dist/fixtures.d.ts +1 -1
  73. package/test/dist/repository-ext.test.d.ts.map +1 -0
  74. package/test/repository-ext.test.ts +58 -0
@@ -37,283 +37,280 @@ const parseSelectRow = (
37
37
  return result
38
38
  }
39
39
 
40
- function makePgStore({ prefix }: StorageConfig) {
41
- return Effect.gen(function*() {
42
- const sql = yield* SqlClient.SqlClient
43
- return {
44
- make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
45
- name: string,
46
- idKey: IdKey,
47
- seed?: Effect.Effect<Iterable<Encoded>, E, R>,
48
- config?: StoreConfig<Encoded>
49
- ) =>
50
- Effect.gen(function*() {
51
- type PM = PersistenceModelType<Encoded>
52
- const tableName = `${prefix}${name}`
53
- const defaultValues = config?.defaultValues ?? {}
40
+ const makePgStore = Effect.fnUntraced(function*({ prefix }: StorageConfig) {
41
+ const sql = yield* SqlClient.SqlClient
42
+ return {
43
+ make: Effect.fnUntraced(function*<IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
44
+ name: string,
45
+ idKey: IdKey,
46
+ seed?: Effect.Effect<Iterable<Encoded>, E, R>,
47
+ config?: StoreConfig<Encoded>
48
+ ) {
49
+ type PM = PersistenceModelType<Encoded>
50
+ const tableName = `${prefix}${name}`
51
+ const defaultValues = config?.defaultValues ?? {}
54
52
 
55
- const resolveNamespace = !config?.allowNamespace
56
- ? Effect.succeed("primary")
57
- : storeId.asEffect().pipe(Effect.map((namespace) => {
58
- if (namespace !== "primary" && !config.allowNamespace!(namespace)) {
59
- throw new Error(`Namespace ${namespace} not allowed!`)
60
- }
61
- return namespace
62
- }))
53
+ const resolveNamespace = !config?.allowNamespace
54
+ ? Effect.succeed("primary")
55
+ : storeId.asEffect().pipe(Effect.map((namespace) => {
56
+ if (namespace !== "primary" && !config.allowNamespace!(namespace)) {
57
+ throw new Error(`Namespace ${namespace} not allowed!`)
58
+ }
59
+ return namespace
60
+ }))
63
61
 
64
- const ensureTable = sql
65
- .unsafe(
66
- `CREATE TABLE IF NOT EXISTS "${tableName}" (id TEXT NOT NULL, _namespace TEXT NOT NULL DEFAULT 'primary', _etag TEXT, data JSONB NOT NULL, PRIMARY KEY (id, _namespace))`
67
- )
68
- .pipe(
69
- Effect.andThen(
70
- sql.unsafe(
71
- `CREATE TABLE IF NOT EXISTS "_migrations" (id TEXT NOT NULL, version TEXT NOT NULL, PRIMARY KEY (id, version))`
72
- )
73
- ),
74
- Effect.orDie,
75
- Effect.asVoid
62
+ const ensureTable = sql
63
+ .unsafe(
64
+ `CREATE TABLE IF NOT EXISTS "${tableName}" (id TEXT NOT NULL, _namespace TEXT NOT NULL DEFAULT 'primary', _etag TEXT, data JSONB NOT NULL, PRIMARY KEY (id, _namespace))`
65
+ )
66
+ .pipe(
67
+ Effect.andThen(
68
+ sql.unsafe(
69
+ `CREATE TABLE IF NOT EXISTS "_migrations" (id TEXT NOT NULL, version TEXT NOT NULL, PRIMARY KEY (id, version))`
76
70
  )
71
+ ),
72
+ Effect.orDie,
73
+ Effect.asVoid
74
+ )
77
75
 
78
- const toRow = (e: PM) => {
79
- const newE = makeETag(e)
80
- const id = newE[idKey] as string
81
- const { _etag, [idKey]: _id, ...rest } = newE as any
82
- const data = JSON.stringify(rest)
83
- return { id, _etag: newE._etag!, data, item: newE }
84
- }
76
+ const toRow = (e: PM) => {
77
+ const newE = makeETag(e)
78
+ const id = newE[idKey] as string
79
+ const { _etag, [idKey]: _id, ...rest } = newE as any
80
+ const data = JSON.stringify(rest)
81
+ return { id, _etag: newE._etag!, data, item: newE }
82
+ }
85
83
 
86
- const exec = (query: string, params?: readonly unknown[]) =>
87
- sql.unsafe(query, params as any).pipe(Effect.orDie)
84
+ const exec = (query: string, params?: readonly unknown[]) => sql.unsafe(query, params as any).pipe(Effect.orDie)
88
85
 
89
- const setInternal = (e: PM, ns: string) =>
90
- Effect.gen(function*() {
91
- const row = toRow(e)
92
- if (e._etag) {
93
- yield* exec(
94
- `UPDATE "${tableName}" SET _etag = $1, data = $2 WHERE id = $3 AND _etag = $4 AND _namespace = $5`,
95
- [row._etag, row.data, row.id, e._etag, ns]
96
- )
97
- const existing = yield* exec(
98
- `SELECT _etag FROM "${tableName}" WHERE id = $1 AND _namespace = $2`,
99
- [row.id, ns]
100
- )
101
- const current = (existing as any[])[0]
102
- if (!current || current._etag !== row._etag) {
103
- if (current) {
104
- return yield* new OptimisticConcurrencyException({
105
- type: name,
106
- id: row.id,
107
- current: current._etag,
108
- found: e._etag,
109
- code: 412
110
- })
111
- }
112
- return yield* new OptimisticConcurrencyException({
113
- type: name,
114
- id: row.id,
115
- current: "",
116
- found: e._etag,
117
- code: 404
118
- })
119
- }
120
- } else {
121
- yield* exec(
122
- `INSERT INTO "${tableName}" (id, _namespace, _etag, data) VALUES ($1, $2, $3, $4)`,
123
- [row.id, ns, row._etag, row.data]
124
- )
125
- }
126
- return row.item
86
+ const setInternal = Effect.fnUntraced(function*(e: PM, ns: string) {
87
+ const row = toRow(e)
88
+ if (e._etag) {
89
+ yield* exec(
90
+ `UPDATE "${tableName}" SET _etag = $1, data = $2 WHERE id = $3 AND _etag = $4 AND _namespace = $5`,
91
+ [row._etag, row.data, row.id, e._etag, ns]
92
+ )
93
+ const existing = yield* exec(
94
+ `SELECT _etag FROM "${tableName}" WHERE id = $1 AND _namespace = $2`,
95
+ [row.id, ns]
96
+ )
97
+ const current = (existing as any[])[0]
98
+ if (!current || current._etag !== row._etag) {
99
+ if (current) {
100
+ return yield* new OptimisticConcurrencyException({
101
+ type: name,
102
+ id: row.id,
103
+ current: current._etag,
104
+ found: e._etag,
105
+ code: 412
106
+ })
107
+ }
108
+ return yield* new OptimisticConcurrencyException({
109
+ type: name,
110
+ id: row.id,
111
+ current: "",
112
+ found: e._etag,
113
+ code: 404
127
114
  })
115
+ }
116
+ } else {
117
+ yield* exec(
118
+ `INSERT INTO "${tableName}" (id, _namespace, _etag, data) VALUES ($1, $2, $3, $4)`,
119
+ [row.id, ns, row._etag, row.data]
120
+ )
121
+ }
122
+ return row.item
123
+ })
124
+
125
+ const bulkSetInternal = (items: NonEmptyReadonlyArray<PM>, ns: string) =>
126
+ sql
127
+ .withTransaction(Effect.forEach(items, (e) => setInternal(e, ns)))
128
+ .pipe(
129
+ Effect.orDie,
130
+ Effect.map((_) => _ as unknown as NonEmptyReadonlyArray<PM>)
131
+ )
128
132
 
129
- const bulkSetInternal = (items: NonEmptyReadonlyArray<PM>, ns: string) =>
130
- sql
131
- .withTransaction(Effect.forEach(items, (e) => setInternal(e, ns)))
133
+ const ctx = yield* Effect.context<R>()
134
+ const seedCache = new Map<string, Effect.Effect<void>>()
135
+ const makeSeedEffect = Effect.fnUntraced(function*(ns: string) {
136
+ yield* ensureTable
137
+ if (!seed) return
138
+ const existing = yield* exec(
139
+ `SELECT id FROM "_migrations" WHERE id = $1 AND version = $2`,
140
+ [`${tableName}::${ns}`, tableName]
141
+ )
142
+ if ((existing as any[]).length > 0) return
143
+ yield* InfraLogger.logInfo(`Seeding data for ${name} (namespace: ${ns})`)
144
+ const items = yield* seed.pipe(Effect.provide(ctx), Effect.orDie)
145
+ const ne = toNonEmptyArray([...items])
146
+ if (Option.isSome(ne)) yield* bulkSetInternal(ne.value, ns)
147
+ yield* exec(
148
+ `INSERT INTO "_migrations" (id, version) VALUES ($1, $2)`,
149
+ [`${tableName}::${ns}`, tableName]
150
+ )
151
+ })
152
+ const seedNamespace = (ns: string) => {
153
+ let cached = seedCache.get(ns)
154
+ if (!cached) {
155
+ cached = Effect.cached(Effect.uninterruptible(makeSeedEffect(ns))).pipe(Effect.runSync)
156
+ seedCache.set(ns, cached)
157
+ }
158
+ return cached
159
+ }
160
+ const s: Store<IdKey, Encoded> = {
161
+ seedNamespace: (ns) => seedNamespace(ns),
162
+
163
+ all: resolveNamespace.pipe(
164
+ Effect.flatMap((ns) =>
165
+ exec(`SELECT id, _etag, data FROM "${tableName}" WHERE _namespace = $1`, [ns])
132
166
  .pipe(
133
- Effect.orDie,
134
- Effect.map((_) => _ as unknown as NonEmptyReadonlyArray<PM>)
167
+ Effect.map((rows) => (rows as any[]).map((r) => parseRow<Encoded>(r, idKey, defaultValues))),
168
+ Effect.withSpan("PgSQL.all [effect-app/infra/Store]", {
169
+ attributes: {
170
+ "repository.table_name": tableName,
171
+ "repository.model_name": name,
172
+ "repository.namespace": ns
173
+ }
174
+ }, { captureStackTrace: false })
135
175
  )
176
+ )
177
+ ),
136
178
 
137
- const ctx = yield* Effect.context<R>()
138
- const seedCache = new Map<string, Effect.Effect<void>>()
139
- const makeSeedEffect = Effect.fnUntraced(function*(ns: string) {
140
- yield* ensureTable
141
- if (!seed) return
142
- const existing = yield* exec(
143
- `SELECT id FROM "_migrations" WHERE id = $1 AND version = $2`,
144
- [`${tableName}::${ns}`, tableName]
145
- )
146
- if ((existing as any[]).length > 0) return
147
- yield* InfraLogger.logInfo(`Seeding data for ${name} (namespace: ${ns})`)
148
- const items = yield* seed.pipe(Effect.provide(ctx), Effect.orDie)
149
- const ne = toNonEmptyArray([...items])
150
- if (Option.isSome(ne)) yield* bulkSetInternal(ne.value, ns)
151
- yield* exec(
152
- `INSERT INTO "_migrations" (id, version) VALUES ($1, $2)`,
153
- [`${tableName}::${ns}`, tableName]
154
- )
155
- })
156
- const seedNamespace = (ns: string) => {
157
- let cached = seedCache.get(ns)
158
- if (!cached) {
159
- cached = Effect.cached(Effect.uninterruptible(makeSeedEffect(ns))).pipe(Effect.runSync)
160
- seedCache.set(ns, cached)
161
- }
162
- return cached
163
- }
164
- const s: Store<IdKey, Encoded> = {
165
- seedNamespace: (ns) => seedNamespace(ns),
166
-
167
- all: resolveNamespace.pipe(Effect.flatMap((ns) =>
168
- exec(`SELECT id, _etag, data FROM "${tableName}" WHERE _namespace = $1`, [ns])
179
+ find: (id) =>
180
+ resolveNamespace.pipe(Effect
181
+ .flatMap((ns) =>
182
+ exec(`SELECT id, _etag, data FROM "${tableName}" WHERE id = $1 AND _namespace = $2`, [id, ns])
169
183
  .pipe(
170
- Effect.map((rows) => (rows as any[]).map((r) => parseRow<Encoded>(r, idKey, defaultValues))),
171
- Effect.withSpan("PgSQL.all [effect-app/infra/Store]", {
172
- attributes: {
173
- "repository.table_name": tableName,
174
- "repository.model_name": name,
175
- "repository.namespace": ns
176
- }
184
+ Effect.map((rows) => {
185
+ const row = (rows as any[])[0]
186
+ return row
187
+ ? Option.some(parseRow<Encoded>(row, idKey, defaultValues))
188
+ : Option.none()
189
+ }),
190
+ Effect.withSpan("PgSQL.find [effect-app/infra/Store]", {
191
+ attributes: { "repository.table_name": tableName, "repository.model_name": name, id }
177
192
  }, { captureStackTrace: false })
178
193
  )
179
194
  )),
180
195
 
181
- find: (id) =>
182
- resolveNamespace.pipe(Effect
183
- .flatMap((ns) =>
184
- exec(`SELECT id, _etag, data FROM "${tableName}" WHERE id = $1 AND _namespace = $2`, [id, ns])
185
- .pipe(
186
- Effect.map((rows) => {
187
- const row = (rows as any[])[0]
188
- return row
189
- ? Option.some(parseRow<Encoded>(row, idKey, defaultValues))
190
- : Option.none()
191
- }),
192
- Effect.withSpan("PgSQL.find [effect-app/infra/Store]", {
193
- attributes: { "repository.table_name": tableName, "repository.model_name": name, id }
194
- }, { captureStackTrace: false })
195
- )
196
- )),
197
-
198
- filter: <U extends keyof Encoded = never>(f: FilterArgs<Encoded, U>) => {
199
- const filter = f
200
- .filter
201
- type M = U extends undefined ? Encoded : Pick<Encoded, U>
202
- return resolveNamespace.pipe(Effect.flatMap((ns) =>
203
- Effect
204
- .sync(() => {
205
- const q = buildWhereSQLQuery(
206
- pgDialect,
207
- idKey,
208
- filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
209
- tableName,
210
- defaultValues,
211
- f.select as
212
- | NonEmptyReadonlyArray<string | { key: string; subKeys: readonly string[] }>
213
- | undefined,
214
- f.order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
215
- f.skip,
216
- f.limit
217
- )
218
- const nsPlaceholder = pgDialect.placeholder(q.params.length + 1)
219
- const hasWhere = q.sql.includes("WHERE")
220
- const nsSql = hasWhere
221
- ? q.sql.replace("WHERE", `WHERE _namespace = ${nsPlaceholder} AND`)
222
- : q.sql.replace(
223
- `FROM "${tableName}"`,
224
- `FROM "${tableName}" WHERE _namespace = ${nsPlaceholder}`
225
- )
226
- return { sql: nsSql, params: [...q.params, ns] }
227
- })
228
- .pipe(
229
- Effect.tap((q) => logQuery(q)),
230
- Effect.flatMap((q) =>
231
- exec(q.sql, q.params).pipe(
232
- Effect.map((rows) => {
233
- if (f.select) {
234
- return (rows as any[]).map((r) => {
235
- const selected = parseSelectRow(r, idKey, {})
236
- return {
237
- ...Struct.pick(
238
- defaultValues as any,
239
- f.select!.filter((_) => typeof _ === "string") as never[]
240
- ),
241
- ...selected
242
- } as M
243
- })
244
- }
245
- return (rows as any[]).map((r) => parseRow<Encoded>(r, idKey, defaultValues) as any as M)
196
+ filter: <U extends keyof Encoded = never>(f: FilterArgs<Encoded, U>) => {
197
+ const filter = f
198
+ .filter
199
+ type M = U extends undefined ? Encoded : Pick<Encoded, U>
200
+ return resolveNamespace.pipe(Effect.flatMap((ns) =>
201
+ Effect
202
+ .sync(() => {
203
+ const q = buildWhereSQLQuery(
204
+ pgDialect,
205
+ idKey,
206
+ filter ? [{ t: "where-scope", result: filter, relation: "some" }] : [],
207
+ tableName,
208
+ defaultValues,
209
+ f.select as
210
+ | NonEmptyReadonlyArray<string | { key: string; subKeys: readonly string[] }>
211
+ | undefined,
212
+ f.order as NonEmptyReadonlyArray<{ key: string; direction: "ASC" | "DESC" }> | undefined,
213
+ f.skip,
214
+ f.limit
215
+ )
216
+ const nsPlaceholder = pgDialect.placeholder(q.params.length + 1)
217
+ const hasWhere = q.sql.includes("WHERE")
218
+ const nsSql = hasWhere
219
+ ? q.sql.replace("WHERE", `WHERE _namespace = ${nsPlaceholder} AND`)
220
+ : q.sql.replace(
221
+ `FROM "${tableName}"`,
222
+ `FROM "${tableName}" WHERE _namespace = ${nsPlaceholder}`
223
+ )
224
+ return { sql: nsSql, params: [...q.params, ns] }
225
+ })
226
+ .pipe(
227
+ Effect.tap((q) => logQuery(q)),
228
+ Effect.flatMap((q) =>
229
+ exec(q.sql, q.params).pipe(
230
+ Effect.map((rows) => {
231
+ if (f.select) {
232
+ return (rows as any[]).map((r) => {
233
+ const selected = parseSelectRow(r, idKey, {})
234
+ return {
235
+ ...Struct.pick(
236
+ defaultValues as any,
237
+ f.select!.filter((_) => typeof _ === "string") as never[]
238
+ ),
239
+ ...selected
240
+ } as M
246
241
  })
247
- )
248
- ),
249
- Effect.withSpan("PgSQL.filter [effect-app/infra/Store]", {
250
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
251
- }, { captureStackTrace: false })
242
+ }
243
+ return (rows as any[]).map((r) => parseRow<Encoded>(r, idKey, defaultValues) as any as M)
244
+ })
252
245
  )
253
- ))
254
- },
255
-
256
- set: (e) =>
257
- resolveNamespace.pipe(Effect.flatMap((ns) =>
258
- setInternal(e, ns).pipe(
259
- Effect.withSpan("PgSQL.set [effect-app/infra/Store]", {
260
- attributes: { "repository.table_name": tableName, "repository.model_name": name, id: e[idKey] }
261
- }, { captureStackTrace: false })
262
- )
263
- )),
246
+ ),
247
+ Effect.withSpan("PgSQL.filter [effect-app/infra/Store]", {
248
+ attributes: { "repository.table_name": tableName, "repository.model_name": name }
249
+ }, { captureStackTrace: false })
250
+ )
251
+ ))
252
+ },
264
253
 
265
- batchSet: (items) =>
266
- resolveNamespace.pipe(Effect.flatMap((ns) =>
267
- bulkSetInternal(items, ns).pipe(
268
- Effect.withSpan("PgSQL.batchSet [effect-app/infra/Store]", {
269
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
270
- }, { captureStackTrace: false })
271
- )
272
- )),
254
+ set: (e) =>
255
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
256
+ setInternal(e, ns).pipe(
257
+ Effect.withSpan("PgSQL.set [effect-app/infra/Store]", {
258
+ attributes: { "repository.table_name": tableName, "repository.model_name": name, id: e[idKey] }
259
+ }, { captureStackTrace: false })
260
+ )
261
+ )),
273
262
 
274
- bulkSet: (items) =>
275
- resolveNamespace.pipe(Effect.flatMap((ns) =>
276
- bulkSetInternal(items, ns).pipe(
277
- Effect.withSpan("PgSQL.bulkSet [effect-app/infra/Store]", {
278
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
279
- }, { captureStackTrace: false })
280
- )
281
- )),
263
+ batchSet: (items) =>
264
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
265
+ bulkSetInternal(items, ns).pipe(
266
+ Effect.withSpan("PgSQL.batchSet [effect-app/infra/Store]", {
267
+ attributes: { "repository.table_name": tableName, "repository.model_name": name }
268
+ }, { captureStackTrace: false })
269
+ )
270
+ )),
282
271
 
283
- batchRemove: (ids) => {
284
- const placeholders = ids.map((_, i) => `$${i + 1}`).join(", ")
285
- const nsPlaceholder = `$${ids.length + 1}`
286
- return resolveNamespace.pipe(Effect.flatMap((ns) =>
287
- exec(
288
- `DELETE FROM "${tableName}" WHERE id IN (${placeholders}) AND _namespace = ${nsPlaceholder}`,
289
- [...ids, ns]
290
- )
291
- .pipe(
292
- Effect.asVoid,
293
- Effect.withSpan("PgSQL.batchRemove [effect-app/infra/Store]", {
294
- attributes: { "repository.table_name": tableName, "repository.model_name": name }
295
- }, { captureStackTrace: false })
296
- )
297
- ))
298
- },
272
+ bulkSet: (items) =>
273
+ resolveNamespace.pipe(Effect.flatMap((ns) =>
274
+ bulkSetInternal(items, ns).pipe(
275
+ Effect.withSpan("PgSQL.bulkSet [effect-app/infra/Store]", {
276
+ attributes: { "repository.table_name": tableName, "repository.model_name": name }
277
+ }, { captureStackTrace: false })
278
+ )
279
+ )),
299
280
 
300
- queryRaw: (query) =>
301
- s.all.pipe(
302
- Effect.map(query.memory),
303
- Effect.withSpan("PgSQL.queryRaw [effect-app/infra/Store]", {
281
+ batchRemove: (ids) => {
282
+ const placeholders = ids.map((_, i) => `$${i + 1}`).join(", ")
283
+ const nsPlaceholder = `$${ids.length + 1}`
284
+ return resolveNamespace.pipe(Effect.flatMap((ns) =>
285
+ exec(
286
+ `DELETE FROM "${tableName}" WHERE id IN (${placeholders}) AND _namespace = ${nsPlaceholder}`,
287
+ [...ids, ns]
288
+ )
289
+ .pipe(
290
+ Effect.asVoid,
291
+ Effect.withSpan("PgSQL.batchRemove [effect-app/infra/Store]", {
304
292
  attributes: { "repository.table_name": tableName, "repository.model_name": name }
305
293
  }, { captureStackTrace: false })
306
294
  )
307
- }
295
+ ))
296
+ },
308
297
 
309
- // Eagerly seed primary namespace on initialization
310
- yield* seedNamespace("primary")
298
+ queryRaw: (query) =>
299
+ s.all.pipe(
300
+ Effect.map(query.memory),
301
+ Effect.withSpan("PgSQL.queryRaw [effect-app/infra/Store]", {
302
+ attributes: { "repository.table_name": tableName, "repository.model_name": name }
303
+ }, { captureStackTrace: false })
304
+ )
305
+ }
311
306
 
312
- return s
313
- })
314
- }
315
- })
316
- }
307
+ // Eagerly seed primary namespace on initialization
308
+ yield* seedNamespace("primary")
309
+
310
+ return s
311
+ })
312
+ }
313
+ })
317
314
 
318
315
  export function PgStoreLayer(cfg: StorageConfig) {
319
316
  return StoreMaker