@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.
- package/CHANGELOG.md +17 -0
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +8 -10
- package/dist/Model/Repository/ext.d.ts +15 -3
- package/dist/Model/Repository/ext.d.ts.map +1 -1
- package/dist/Model/Repository/ext.js +25 -2
- package/dist/Model/Repository/internal/internal.d.ts +1 -1
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +9 -8
- package/dist/Model/Repository/makeRepo.d.ts +3 -3
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/service.d.ts +21 -21
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts +2 -2
- package/dist/Operations.d.ts +2 -2
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Operations.js +54 -57
- package/dist/OperationsRepo.d.ts +2 -2
- package/dist/QueueMaker/SQLQueue.d.ts +2 -3
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +104 -115
- package/dist/QueueMaker/memQueue.d.ts +2 -2
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +51 -62
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +34 -50
- package/dist/Store/ContextMapContainer.d.ts +1 -1
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +304 -306
- package/dist/Store/Disk.d.ts +1 -1
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +2 -2
- package/dist/Store/Memory.d.ts +1 -1
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +2 -2
- package/dist/Store/SQL/Pg.d.ts.map +1 -1
- package/dist/Store/SQL/Pg.js +147 -149
- package/dist/Store/SQL.d.ts.map +1 -1
- package/dist/Store/SQL.js +6 -6
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +3 -4
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +7 -9
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +1 -1
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +2 -2
- package/dist/errorReporter.d.ts +3 -3
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +16 -23
- package/package.json +14 -14
- package/src/CUPS.ts +7 -9
- package/src/Model/Repository/ext.ts +71 -6
- package/src/Model/Repository/internal/internal.ts +13 -25
- package/src/Model/Repository/makeRepo.ts +4 -4
- package/src/Model/Repository/service.ts +22 -21
- package/src/Operations.ts +76 -111
- package/src/QueueMaker/SQLQueue.ts +119 -150
- package/src/QueueMaker/memQueue.ts +81 -102
- package/src/QueueMaker/sbqueue.ts +51 -81
- package/src/Store/Cosmos.ts +481 -484
- package/src/Store/Disk.ts +52 -53
- package/src/Store/Memory.ts +49 -50
- package/src/Store/SQL/Pg.ts +247 -250
- package/src/Store/SQL.ts +420 -426
- package/src/Store/utils.ts +23 -22
- package/src/adapters/ServiceBus.ts +106 -110
- package/src/api/internal/auth.ts +8 -6
- package/src/api/routing/middleware/middleware.ts +10 -11
- package/src/errorReporter.ts +58 -72
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- package/test/repository-ext.test.ts +58 -0
package/src/Store/SQL/Pg.ts
CHANGED
|
@@ -37,283 +37,280 @@ const parseSelectRow = (
|
|
|
37
37
|
return result
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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.
|
|
134
|
-
Effect.
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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) =>
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
f.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
310
|
-
|
|
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
|
-
|
|
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
|