@effect-app/infra 0.170.5 → 0.171.0

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 (90) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/_cjs/api/routing/base.cjs.map +1 -1
  3. package/_cjs/api/routing/makeRequestHandler.cjs.map +1 -1
  4. package/_cjs/services/QueueMaker/errors.cjs.map +1 -1
  5. package/_cjs/services/Repository/dsl.cjs +70 -0
  6. package/_cjs/services/Repository/dsl.cjs.map +1 -0
  7. package/_cjs/services/Repository/ext.cjs +202 -0
  8. package/_cjs/services/Repository/ext.cjs.map +1 -0
  9. package/_cjs/services/Repository/service.cjs +6 -0
  10. package/_cjs/services/Repository/service.cjs.map +1 -0
  11. package/_cjs/services/Repository.cjs +32 -252
  12. package/_cjs/services/Repository.cjs.map +1 -1
  13. package/_cjs/services/RepositoryBase.cjs +173 -48
  14. package/_cjs/services/RepositoryBase.cjs.map +1 -1
  15. package/_cjs/services/RequestContextContainer.cjs +6 -7
  16. package/_cjs/services/RequestContextContainer.cjs.map +1 -1
  17. package/_cjs/services/Store/ContextMapContainer.cjs +6 -7
  18. package/_cjs/services/Store/ContextMapContainer.cjs.map +1 -1
  19. package/_cjs/services/Store/Memory.cjs.map +1 -1
  20. package/_cjs/services/Store/utils.cjs.map +1 -1
  21. package/_src/api/routing/base.ts +5 -3
  22. package/_src/api/routing/makeRequestHandler.ts +20 -12
  23. package/_src/rateLimit.ts +2 -2
  24. package/_src/services/Emailer/Sendgrid.ts +2 -2
  25. package/_src/services/QueueMaker/errors.ts +6 -3
  26. package/_src/services/QueueMaker/memQueue.ts +2 -2
  27. package/_src/services/QueueMaker/sbqueue.ts +2 -2
  28. package/_src/services/Repository/dsl.ts +137 -0
  29. package/_src/services/Repository/ext.ts +669 -0
  30. package/_src/services/Repository/service.ts +12 -0
  31. package/_src/services/Repository.ts +3 -791
  32. package/_src/services/RepositoryBase.ts +640 -13
  33. package/_src/services/RequestContextContainer.ts +14 -16
  34. package/_src/services/Store/ContextMapContainer.ts +6 -9
  35. package/_src/services/Store/Cosmos.ts +2 -2
  36. package/_src/services/Store/Disk.ts +2 -2
  37. package/_src/services/Store/Memory.ts +2 -1
  38. package/_src/services/Store/Redis.ts +2 -2
  39. package/_src/services/Store/utils.ts +4 -5
  40. package/_src/services/simpledb/cosmosdb.ts +1 -1
  41. package/_src/services/simpledb/diskdb.ts +1 -1
  42. package/_src/services/simpledb/memdb.ts +1 -1
  43. package/_src/services/simpledb/mongodb.ts +1 -1
  44. package/_src/services/simpledb/redisdb.ts +2 -2
  45. package/dist/api/routing/base.d.ts +1 -2
  46. package/dist/api/routing/base.d.ts.map +1 -1
  47. package/dist/api/routing/base.js +1 -1
  48. package/dist/api/routing/makeRequestHandler.d.ts.map +1 -1
  49. package/dist/api/routing/makeRequestHandler.js +15 -11
  50. package/dist/rateLimit.js +1 -1
  51. package/dist/services/Emailer/Sendgrid.js +1 -1
  52. package/dist/services/QueueMaker/errors.d.ts.map +1 -1
  53. package/dist/services/QueueMaker/errors.js +5 -2
  54. package/dist/services/QueueMaker/memQueue.js +1 -1
  55. package/dist/services/QueueMaker/sbqueue.js +1 -1
  56. package/dist/services/QueueMaker/service.d.ts +2 -2
  57. package/dist/services/Repository/dsl.d.ts +51 -0
  58. package/dist/services/Repository/dsl.d.ts.map +1 -0
  59. package/dist/services/Repository/dsl.js +55 -0
  60. package/dist/services/Repository/ext.d.ts +310 -0
  61. package/dist/services/Repository/ext.d.ts.map +1 -0
  62. package/dist/services/Repository/ext.js +166 -0
  63. package/dist/services/Repository/service.d.ts +10 -0
  64. package/dist/services/Repository/service.d.ts.map +1 -0
  65. package/dist/services/Repository/service.js +2 -0
  66. package/dist/services/Repository.d.ts +3 -363
  67. package/dist/services/Repository.d.ts.map +1 -1
  68. package/dist/services/Repository.js +4 -217
  69. package/dist/services/RepositoryBase.d.ts +241 -6
  70. package/dist/services/RepositoryBase.d.ts.map +1 -1
  71. package/dist/services/RepositoryBase.js +176 -52
  72. package/dist/services/RequestContextContainer.d.ts +3 -5
  73. package/dist/services/RequestContextContainer.d.ts.map +1 -1
  74. package/dist/services/RequestContextContainer.js +17 -16
  75. package/dist/services/Store/ContextMapContainer.d.ts +2 -5
  76. package/dist/services/Store/ContextMapContainer.d.ts.map +1 -1
  77. package/dist/services/Store/ContextMapContainer.js +7 -8
  78. package/dist/services/Store/Cosmos.js +1 -1
  79. package/dist/services/Store/Disk.js +1 -1
  80. package/dist/services/Store/Memory.d.ts.map +1 -1
  81. package/dist/services/Store/Memory.js +1 -1
  82. package/dist/services/Store/Redis.js +1 -1
  83. package/dist/services/Store/utils.d.ts.map +1 -1
  84. package/dist/services/Store/utils.js +1 -1
  85. package/dist/services/simpledb/cosmosdb.js +1 -1
  86. package/dist/services/simpledb/diskdb.js +1 -1
  87. package/dist/services/simpledb/memdb.js +1 -1
  88. package/dist/services/simpledb/mongodb.js +1 -1
  89. package/dist/services/simpledb/redisdb.js +1 -1
  90. package/package.json +37 -7
@@ -0,0 +1,669 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ // Update = Must return updated items
3
+ // Modify = Must `set` updated items, and can return anything.
4
+ import type { FixEnv } from "@effect-app/prelude/Pure"
5
+ import type { InvalidStateError, OptimisticConcurrencyException } from "../../errors.js"
6
+ import { NotFoundError } from "../../errors.js"
7
+ import type { Filter, PersistenceModelType } from "../../services/Store.js"
8
+ import type { RepositoryBaseC } from "../RepositoryBase.js"
9
+ import type { QueryBuilder } from "../Store/filterApi/query.js"
10
+ import { AnyPureDSL } from "./dsl.js"
11
+
12
+ /**
13
+ * @tsplus fluent Repository get
14
+ */
15
+ export function get<
16
+ T extends { id: unknown },
17
+ PM extends PersistenceModelType<string>,
18
+ Evt,
19
+ ItemType extends string
20
+ >(
21
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
22
+ id: T["id"]
23
+ ) {
24
+ return self
25
+ .find(id)
26
+ .flatMap((_) => _.encaseInEffect(() => new NotFoundError<ItemType>({ type: self.itemType, id })))
27
+ }
28
+
29
+ /**
30
+ * @tsplus getter Repository log
31
+ */
32
+ export function log<
33
+ T extends { id: unknown },
34
+ PM extends PersistenceModelType<string>,
35
+ Evt,
36
+ ItemType extends string
37
+ >(_: RepositoryBaseC<T, PM, Evt, ItemType>) {
38
+ return (evt: Evt) => AnyPureDSL.log(evt)
39
+ }
40
+
41
+ /**
42
+ * TODO: project inside the db.
43
+ * @tsplus fluent Repository projectEffect
44
+ */
45
+ export function projectEffect<
46
+ T extends { id: unknown },
47
+ PM extends PersistenceModelType<string>,
48
+ Evt,
49
+ ItemType extends string,
50
+ R,
51
+ E,
52
+ S = PM
53
+ >(
54
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
55
+ map: Effect<
56
+ {
57
+ filter?: Filter<PM> | undefined
58
+ collect?: ((t: PM) => Option<S>) | undefined
59
+ limit?: number | undefined
60
+ skip?: number | undefined
61
+ },
62
+ E,
63
+ R
64
+ >
65
+ ): Effect<S[], E, R>
66
+ export function projectEffect<
67
+ T extends { id: unknown },
68
+ PM extends PersistenceModelType<string>,
69
+ Evt,
70
+ ItemType extends string,
71
+ R,
72
+ E,
73
+ U extends keyof PM,
74
+ S = PM
75
+ >(
76
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
77
+ map: Effect<
78
+ {
79
+ filter?: QueryBuilder<PM> | undefined
80
+ collect?: ((t: PM) => Option<S>) | undefined
81
+ limit?: number | undefined
82
+ skip?: number | undefined
83
+ },
84
+ E,
85
+ R
86
+ >
87
+ ): Effect<Pick<PM, U>[], E, R>
88
+ export function projectEffect<
89
+ T extends { id: unknown },
90
+ PM extends PersistenceModelType<string>,
91
+ Evt,
92
+ ItemType extends string,
93
+ R,
94
+ E,
95
+ U extends keyof PM,
96
+ S = Pick<PM, U>
97
+ >(
98
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
99
+ map: Effect<
100
+ {
101
+ filter?: Filter<PM> | undefined
102
+ select?: NonEmptyReadonlyArray<U> | undefined
103
+ collect?: ((t: PM) => Option<S>) | undefined
104
+ limit?: number | undefined
105
+ skip?: number | undefined
106
+ },
107
+ E,
108
+ R
109
+ >
110
+ ): Effect<S[], E, R> {
111
+ // TODO: a projection that gets sent to the db instead.
112
+ return map.flatMap((f) =>
113
+ self
114
+ .utils
115
+ .filter(f)
116
+ .map((_) => f.collect ? _.filterMap(f.collect) : _ as unknown as S[])
117
+ )
118
+ }
119
+
120
+ /**
121
+ * TODO: project inside the db.
122
+ * @tsplus fluent Repository project
123
+ */
124
+ export function project<
125
+ T extends { id: unknown },
126
+ PM extends PersistenceModelType<string>,
127
+ Evt,
128
+ ItemType extends string,
129
+ S = PM
130
+ >(
131
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
132
+ map: {
133
+ filter?: Filter<PM>
134
+ collect?: (t: PM) => Option<S>
135
+ limit?: number
136
+ skip?: number
137
+ }
138
+ ): Effect<S[]>
139
+ export function project<
140
+ T extends { id: unknown },
141
+ PM extends PersistenceModelType<string>,
142
+ Evt,
143
+ ItemType extends string,
144
+ U extends keyof PM
145
+ >(
146
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
147
+ map: {
148
+ filter?: QueryBuilder<PM>
149
+ select: NonEmptyReadonlyArray<U>
150
+ limit?: number
151
+ skip?: number
152
+ }
153
+ ): Effect<Pick<PM, U>[]>
154
+ export function project<
155
+ T extends { id: unknown },
156
+ PM extends PersistenceModelType<string>,
157
+ Evt,
158
+ ItemType extends string,
159
+ U extends keyof PM,
160
+ S = Pick<PM, U>
161
+ >(
162
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
163
+ map: {
164
+ filter?: Filter<PM>
165
+ select?: NonEmptyReadonlyArray<U>
166
+ collect?: (t: Pick<PM, U>) => Option<S>
167
+ limit?: number
168
+ skip?: number
169
+ }
170
+ ): Effect<S[]> {
171
+ return self.projectEffect(Effect.sync(() => map))
172
+ }
173
+
174
+ /**
175
+ * TODO: count inside the db.
176
+ * @tsplus fluent Repository project
177
+ */
178
+ export function count<
179
+ T extends { id: unknown },
180
+ PM extends PersistenceModelType<string>,
181
+ Evt,
182
+ ItemType extends string
183
+ >(
184
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
185
+ filter?: Filter<PM>
186
+ ) {
187
+ return self
188
+ .projectEffect(Effect.sync(() => ({ filter })))
189
+ .map((_) => NonNegativeInt(_.length))
190
+ }
191
+
192
+ /**
193
+ * @tsplus fluent Repository queryEffect
194
+ */
195
+ export function queryEffect<
196
+ T extends { id: unknown },
197
+ PM extends PersistenceModelType<string>,
198
+ Evt,
199
+ ItemType extends string,
200
+ R,
201
+ E,
202
+ S = T
203
+ >(
204
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
205
+ // TODO: think about collectPM, collectE, and collect(Parsed)
206
+ map: Effect<{ filter?: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }, E, R>
207
+ ) {
208
+ return map.flatMap((f) =>
209
+ (f.filter ? self.utils.filter(f) : self.utils.all)
210
+ .flatMap((_) => self.utils.parseMany(_))
211
+ .map((_) => f.collect ? _.filterMap(f.collect) : _ as any as S[])
212
+ )
213
+ }
214
+
215
+ /**
216
+ * @tsplus fluent Repository queryOneEffect
217
+ */
218
+ export function queryOneEffect<
219
+ T extends { id: unknown },
220
+ PM extends PersistenceModelType<string>,
221
+ Evt,
222
+ ItemType extends string,
223
+ R,
224
+ E
225
+ >(
226
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
227
+ // TODO: think about collectPM, collectE, and collect(Parsed)
228
+ map: Effect<{ filter?: Filter<PM> }, E, R>
229
+ ): Effect<T, E | NotFoundError<ItemType>, R>
230
+ export function queryOneEffect<
231
+ T extends { id: unknown },
232
+ PM extends PersistenceModelType<string>,
233
+ Evt,
234
+ ItemType extends string,
235
+ R,
236
+ E,
237
+ S = T
238
+ >(
239
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
240
+ // TODO: think about collectPM, collectE, and collect(Parsed)
241
+ map: Effect<{ filter?: Filter<PM>; collect: (t: T) => Option<S> }, E, R>
242
+ ): Effect<S, E | NotFoundError<ItemType>, R>
243
+ export function queryOneEffect<
244
+ T extends { id: unknown },
245
+ PM extends PersistenceModelType<string>,
246
+ Evt,
247
+ ItemType extends string,
248
+ R,
249
+ E,
250
+ S = T
251
+ >(
252
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
253
+ // TODO: think about collectPM, collectE, and collect(Parsed)
254
+ map: Effect<{ filter?: Filter<PM>; collect?: (t: T) => Option<S> }, E, R>
255
+ ): Effect<S, E | NotFoundError<ItemType>, R> {
256
+ return map.flatMap((f) =>
257
+ (f.filter ? self.utils.filter({ filter: f.filter, limit: 1 }) : self.utils.all)
258
+ .flatMap((_) => self.utils.parseMany(_))
259
+ .flatMap((_) =>
260
+ (f.collect ? _.filterMap(f.collect) : _ as any as S[])
261
+ .toNonEmpty
262
+ .encaseInEffect(() => new NotFoundError<ItemType>({ type: self.itemType, id: f.filter }))
263
+ .map((_) => _[0])
264
+ )
265
+ )
266
+ }
267
+
268
+ /**
269
+ * @tsplus fluent Repository query
270
+ */
271
+ export function query<
272
+ T extends { id: unknown },
273
+ PM extends PersistenceModelType<string>,
274
+ Evt,
275
+ ItemType extends string,
276
+ S = T
277
+ >(
278
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
279
+ // TODO: think about collectPM, collectE, and collect(Parsed)
280
+ map: { filter?: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }
281
+ ) {
282
+ return self.queryEffect(Effect.sync(() => map))
283
+ }
284
+
285
+ /**
286
+ * @tsplus fluent Repository queryOne
287
+ */
288
+ export function queryOne<
289
+ T extends { id: unknown },
290
+ PM extends PersistenceModelType<string>,
291
+ Evt,
292
+ ItemType extends string,
293
+ S = T
294
+ >(
295
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
296
+ map: { filter?: Filter<PM>; collect: (t: T) => Option<S> }
297
+ ): Effect<S, NotFoundError<ItemType>>
298
+ export function queryOne<
299
+ T extends { id: unknown },
300
+ PM extends PersistenceModelType<string>,
301
+ Evt,
302
+ ItemType extends string
303
+ >(
304
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
305
+ map: { filter?: Filter<PM> }
306
+ ): Effect<T, NotFoundError<ItemType>>
307
+ export function queryOne<
308
+ T extends { id: unknown },
309
+ PM extends PersistenceModelType<string>,
310
+ Evt,
311
+ ItemType extends string,
312
+ S = T
313
+ >(
314
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
315
+ map: { filter?: Filter<PM>; collect?: (t: T) => Option<S> }
316
+ ) {
317
+ return self.queryOneEffect(Effect.sync(() => map))
318
+ }
319
+
320
+ /**
321
+ * @tsplus fluent Repository queryAndSaveOnePureEffect
322
+ */
323
+ export function queryAndSaveOnePureEffect<
324
+ T extends { id: unknown },
325
+ PM extends PersistenceModelType<string>,
326
+ Evt,
327
+ ItemType extends string,
328
+ R,
329
+ E,
330
+ S extends T = T
331
+ >(
332
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
333
+ map: Effect<{ filter: Filter<PM>; collect: (t: T) => Option<S>; limit?: number; skip?: number }, E, R>
334
+ ): <R2, A, E2, S2 extends T>(
335
+ pure: Effect<A, E2, FixEnv<R2, Evt, S, S2>>
336
+ ) => Effect<
337
+ A,
338
+ InvalidStateError | OptimisticConcurrencyException | E | E2 | NotFoundError<ItemType>,
339
+ | R
340
+ | Exclude<R2, {
341
+ env: PureEnv<Evt, S, S2>
342
+ }>
343
+ >
344
+ export function queryAndSaveOnePureEffect<
345
+ T extends { id: unknown },
346
+ PM extends PersistenceModelType<string>,
347
+ Evt,
348
+ ItemType extends string,
349
+ R,
350
+ E
351
+ >(
352
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
353
+ map: Effect<{ filter: Filter<PM> }, E, R>
354
+ ): <R2, A, E2, T2 extends T>(
355
+ pure: Effect<A, E2, FixEnv<R2, Evt, T, T2>>
356
+ ) => Effect<
357
+ A,
358
+ InvalidStateError | OptimisticConcurrencyException | E | E2 | NotFoundError<ItemType>,
359
+ | R
360
+ | Exclude<R2, {
361
+ env: PureEnv<Evt, T, T2>
362
+ }>
363
+ >
364
+ export function queryAndSaveOnePureEffect(
365
+ self: any,
366
+ map: any
367
+ ) {
368
+ return (pure: any) =>
369
+ queryOneEffect(self, map)
370
+ .flatMap((_) => saveWithPure_(self, _, pure))
371
+ }
372
+
373
+ /**
374
+ * @tsplus fluent Repository queryAndSaveOnePure
375
+ */
376
+ export function queryAndSaveOnePure<
377
+ T extends { id: unknown },
378
+ PM extends PersistenceModelType<string>,
379
+ Evt,
380
+ ItemType extends string,
381
+ S extends T = T
382
+ >(
383
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
384
+ map: { filter: Filter<PM>; collect: (t: T) => Option<S>; limit?: number; skip?: number }
385
+ ): <R2, A, E2, S2>(pure: Effect<A, E2, FixEnv<R2, Evt, S, S2>>) => Effect<
386
+ A,
387
+ InvalidStateError | OptimisticConcurrencyException | E2 | NotFoundError<ItemType>,
388
+ Exclude<R2, {
389
+ env: PureEnv<Evt, S, S2>
390
+ }>
391
+ >
392
+ export function queryAndSaveOnePure<
393
+ T extends { id: unknown },
394
+ PM extends PersistenceModelType<string>,
395
+ Evt,
396
+ ItemType extends string
397
+ >(
398
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
399
+ map: { filter: Filter<PM> }
400
+ ): <R2, A, E2, T2>(pure: Effect<A, E2, FixEnv<R2, Evt, T, T2>>) => Effect<
401
+ A,
402
+ InvalidStateError | OptimisticConcurrencyException | E2 | NotFoundError<ItemType>,
403
+ Exclude<R2, {
404
+ env: PureEnv<Evt, T, T2>
405
+ }>
406
+ >
407
+ export function queryAndSaveOnePure(
408
+ self: any,
409
+ map: { filter: Filter<any>; collect?: any }
410
+ ) {
411
+ return queryAndSaveOnePureEffect(self, Effect.sync(() => map))
412
+ }
413
+
414
+ /**
415
+ * @tsplus fluent Repository queryAndSavePureEffect
416
+ */
417
+ export function queryAndSavePureEffect<
418
+ T extends { id: unknown },
419
+ PM extends PersistenceModelType<string>,
420
+ Evt,
421
+ ItemType extends string,
422
+ R,
423
+ E,
424
+ S extends T = T
425
+ >(
426
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
427
+ map: Effect<{ filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }, E, R>
428
+ ) {
429
+ return <R2, A, E2, S2 extends T>(pure: Effect<A, E2, FixEnv<R2, Evt, S[], S2[]>>) =>
430
+ queryEffect(self, map)
431
+ .flatMap((_) => self.saveManyWithPure_(_, pure))
432
+ }
433
+
434
+ /**
435
+ * @tsplus fluent Repository queryAndSavePure
436
+ */
437
+ export function queryAndSavePure<
438
+ T extends { id: unknown },
439
+ PM extends PersistenceModelType<string>,
440
+ Evt,
441
+ ItemType extends string,
442
+ S extends T = T
443
+ >(
444
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
445
+ map: { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }
446
+ ) {
447
+ return self.queryAndSavePureEffect(Effect.sync(() => map))
448
+ }
449
+
450
+ /**
451
+ * @tsplus getter Repository saveManyWithPure
452
+ */
453
+ export function saveManyWithPure<
454
+ T extends { id: unknown },
455
+ PM extends PersistenceModelType<string>,
456
+ Evt,
457
+ ItemType extends string
458
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>) {
459
+ return <R, A, E, S1 extends T, S2 extends T>(pure: Effect<A, E, FixEnv<R, Evt, S1[], S2[]>>) =>
460
+ (items: Iterable<S1>) => saveManyWithPure_(self, items, pure)
461
+ }
462
+
463
+ /**
464
+ * @tsplus fluent Repository byIdAndSaveWithPure
465
+ */
466
+ export function byIdAndSaveWithPure<
467
+ T extends { id: unknown },
468
+ PM extends PersistenceModelType<string>,
469
+ Evt,
470
+ ItemType extends string
471
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, id: T["id"]) {
472
+ return <R, A, E, S2 extends T>(pure: Effect<A, E, FixEnv<R, Evt, T, S2>>) =>
473
+ get(self, id).flatMap((item) => saveWithPure_(self, item, pure))
474
+ }
475
+
476
+ /**
477
+ * NOTE: it's not as composable, only useful when the request is simple, and only this part needs request args.
478
+ * @tsplus getter Repository handleByIdAndSaveWithPure
479
+ */
480
+ export function handleByIdAndSaveWithPure<
481
+ T extends { id: unknown },
482
+ PM extends PersistenceModelType<string>,
483
+ Evt,
484
+ ItemType extends string
485
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>) {
486
+ return <Req extends { id: T["id"] }, Context, R, A, E, S2 extends T>(
487
+ pure: (req: Req, ctx: Context) => Effect<A, E, FixEnv<R, Evt, T, S2>>
488
+ ) =>
489
+ (req: Req, ctx: Context) => byIdAndSaveWithPure(self, req.id)(pure(req, ctx))
490
+ }
491
+
492
+ /**
493
+ * @tsplus fluent Repository saveManyWithPure_
494
+ */
495
+ export function saveManyWithPure_<
496
+ R,
497
+ T extends { id: unknown },
498
+ PM extends PersistenceModelType<string>,
499
+ A,
500
+ E,
501
+ Evt,
502
+ S1 extends T,
503
+ S2 extends T,
504
+ ItemType extends string
505
+ >(
506
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
507
+ items: Iterable<S1>,
508
+ pure: Effect<A, E, FixEnv<R, Evt, S1[], S2[]>>
509
+ ) {
510
+ return saveAllWithEffectInt(
511
+ self,
512
+ pure.runTerm([...items])
513
+ )
514
+ }
515
+
516
+ /**
517
+ * @tsplus fluent Repository saveWithPure_
518
+ */
519
+ export function saveWithPure_<
520
+ R,
521
+ T extends { id: unknown },
522
+ PM extends PersistenceModelType<string>,
523
+ A,
524
+ E,
525
+ Evt,
526
+ S1 extends T,
527
+ S2 extends T,
528
+ ItemType extends string
529
+ >(
530
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
531
+ item: S1,
532
+ pure: Effect<A, E, FixEnv<R, Evt, S1, S2>>
533
+ ) {
534
+ return saveAllWithEffectInt(
535
+ self,
536
+ pure
537
+ .runTerm(item)
538
+ .map(([item, events, a]) => [[item], events, a])
539
+ )
540
+ }
541
+
542
+ export function saveAllWithEffectInt<
543
+ T extends { id: unknown },
544
+ PM extends PersistenceModelType<string>,
545
+ P extends T,
546
+ Evt,
547
+ ItemType extends string,
548
+ R,
549
+ E,
550
+ A
551
+ >(
552
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
553
+ gen: Effect<readonly [Iterable<P>, Iterable<Evt>, A], E, R>
554
+ ) {
555
+ return gen
556
+ .flatMap(
557
+ ([items, events, a]) => self.saveAndPublish(items, events).map(() => a)
558
+ )
559
+ }
560
+
561
+ /**
562
+ * @tsplus fluent Repository queryAndSavePureEffectBatched
563
+ */
564
+ export function queryAndSavePureEffectBatched<
565
+ T extends { id: unknown },
566
+ PM extends PersistenceModelType<string>,
567
+ Evt,
568
+ ItemType extends string,
569
+ R,
570
+ E,
571
+ S extends T = T
572
+ >(
573
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
574
+ // TODO: think about collectPM, collectE, and collect(Parsed)
575
+ map: Effect<{ filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }, E, R>,
576
+ batchSize = 100
577
+ ) {
578
+ return <R2, A, E2, S2 extends T>(pure: Effect<A, E2, FixEnv<R2, Evt, S[], S2[]>>) =>
579
+ queryEffect(self, map)
580
+ .flatMap((_) => self.saveManyWithPureBatched_(_, pure, batchSize))
581
+ }
582
+
583
+ /**
584
+ * @tsplus fluent Repository queryAndSavePureBatched
585
+ */
586
+ export function queryAndSavePureBatched<
587
+ T extends { id: unknown },
588
+ PM extends PersistenceModelType<string>,
589
+ Evt,
590
+ ItemType extends string,
591
+ S extends T = T
592
+ >(
593
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
594
+ // TODO: think about collectPM, collectE, and collect(Parsed)
595
+ map: { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number },
596
+ batchSize = 100
597
+ ) {
598
+ return self.queryAndSavePureEffectBatched(Effect.sync(() => map), batchSize)
599
+ }
600
+
601
+ /**
602
+ * @tsplus fluent Repository saveManyWithPureBatched
603
+ */
604
+ export function saveManyWithPureBatched<
605
+ T extends { id: unknown },
606
+ PM extends PersistenceModelType<string>,
607
+ Evt,
608
+ ItemType extends string
609
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, batchSize = 100) {
610
+ return <R, A, E, S1 extends T, S2 extends T>(pure: Effect<A, E, FixEnv<R, Evt, S1[], S2[]>>) =>
611
+ (items: Iterable<S1>) => saveManyWithPureBatched_(self, items, pure, batchSize)
612
+ }
613
+
614
+ /**
615
+ * @tsplus fluent Repository saveManyWithPureBatched_
616
+ */
617
+ export function saveManyWithPureBatched_<
618
+ R,
619
+ T extends { id: unknown },
620
+ PM extends PersistenceModelType<string>,
621
+ A,
622
+ E,
623
+ Evt,
624
+ S1 extends T,
625
+ S2 extends T,
626
+ ItemType extends string
627
+ >(
628
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
629
+ items: Iterable<S1>,
630
+ pure: Effect<A, E, FixEnv<R, Evt, S1[], S2[]>>,
631
+ batchSize = 100
632
+ ) {
633
+ return items
634
+ .chunk(batchSize)
635
+ .forEachEffect((batch) =>
636
+ saveAllWithEffectInt(
637
+ self,
638
+ pure.runTerm(batch)
639
+ )
640
+ )
641
+ }
642
+
643
+ /**
644
+ * @tsplus getter Repository save
645
+ */
646
+ export function save<
647
+ T extends { id: unknown },
648
+ PM extends PersistenceModelType<string>,
649
+ Evt,
650
+ ItemType extends string
651
+ >(
652
+ self: RepositoryBaseC<T, PM, Evt, ItemType>
653
+ ) {
654
+ return (...items: NonEmptyArray<T>) => self.saveAndPublish(items)
655
+ }
656
+
657
+ /**
658
+ * @tsplus getter Repository saveWithEvents
659
+ */
660
+ export function saveWithEvents<
661
+ T extends { id: unknown },
662
+ PM extends PersistenceModelType<string>,
663
+ Evt,
664
+ ItemType extends string
665
+ >(
666
+ self: RepositoryBaseC<T, PM, Evt, ItemType>
667
+ ) {
668
+ return (events: Iterable<Evt>) => (...items: NonEmptyArray<T>) => self.saveAndPublish(items, events)
669
+ }
@@ -0,0 +1,12 @@
1
+ import type { RepositoryBaseC } from "../RepositoryBase.js"
2
+ import type { PersistenceModelType } from "../Store.js"
3
+
4
+ /**
5
+ * @tsplus type Repository
6
+ */
7
+ export interface Repository<
8
+ T extends { id: unknown },
9
+ PM extends PersistenceModelType<string>,
10
+ Evt,
11
+ ItemType extends string
12
+ > extends RepositoryBaseC<T, PM, Evt, ItemType> {}