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