@effect-app/infra 0.96.0 → 0.97.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.
@@ -3,10 +3,9 @@
3
3
  // Modify = Must `set` updated items, and can return anything.
4
4
  import type { FixEnv, PureLogT } from "@effect-app/prelude/Pure"
5
5
  import { Pure } from "@effect-app/prelude/Pure"
6
- import type { ParserEnv } from "@effect-app/schema/custom/Parser"
7
- import type { InvalidStateError, OptimisticConcurrencyException } from "../errors.js"
8
6
  import { NotFoundError } from "../errors.js"
9
7
  import type { Filter } from "../services/Store.js"
8
+ import type { RepositoryBaseC } from "./RepositoryBase.js"
10
9
  import { ContextMapContainer } from "./Store/ContextMapContainer.js"
11
10
 
12
11
  /**
@@ -17,29 +16,7 @@ export interface Repository<
17
16
  PM extends { id: string },
18
17
  Evt,
19
18
  ItemType extends string
20
- > {
21
- itemType: ItemType
22
- find: (id: T["id"]) => Effect<never, never, Option<T>>
23
- all: Effect<never, never, T[]>
24
- saveAndPublish: (
25
- items: Iterable<T>,
26
- events?: Iterable<Evt>
27
- ) => Effect<never, InvalidStateError | OptimisticConcurrencyException, void>
28
- removeAndPublish: (
29
- items: Iterable<T>,
30
- events?: Iterable<Evt>
31
- ) => Effect<never, never, void>
32
- utils: {
33
- mapReverse: (
34
- pm: PM,
35
- setEtag: (id: string, eTag: string | undefined) => void
36
- ) => unknown // TODO
37
- parse: (a: unknown, env?: ParserEnv | undefined) => T
38
- all: Effect<never, never, PM[]>
39
- filter: (filter: Filter<PM>, cursor?: { limit?: number; skip?: number }) => Effect<never, never, PM[]>
40
- }
41
- changeFeed: PubSub<[T[], "save" | "remove"]>
42
- }
19
+ > extends RepositoryBaseC<T, PM, Evt, ItemType> {}
43
20
 
44
21
  export interface PureDSL<S, S2, W> {
45
22
  get: ReturnType<typeof Pure.get<S>>
@@ -62,7 +39,7 @@ export function get<
62
39
  Evt,
63
40
  ItemType extends string
64
41
  >(
65
- self: Repository<T, PM, Evt, ItemType>,
42
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
66
43
  id: T["id"]
67
44
  ) {
68
45
  return self.find(id).flatMap((_) => _.encaseInEffect(() => new NotFoundError({ type: self.itemType, id })))
@@ -76,7 +53,7 @@ export function filter<
76
53
  PM extends { id: string },
77
54
  Evt,
78
55
  ItemType extends string
79
- >(self: Repository<T, PM, Evt, ItemType>, filter: Predicate<T>) {
56
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, filter: Predicate<T>) {
80
57
  return self.all.map((_) => _.filter(filter))
81
58
  }
82
59
 
@@ -89,7 +66,7 @@ export function filterAll<
89
66
  Evt,
90
67
  ItemType extends string,
91
68
  S extends T
92
- >(self: Repository<T, PM, Evt, ItemType>, map: (items: T[]) => S[]) {
69
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, map: (items: T[]) => S[]) {
93
70
  return self.all.map(map)
94
71
  }
95
72
 
@@ -102,7 +79,7 @@ export function collect<
102
79
  Evt,
103
80
  ItemType extends string,
104
81
  S extends T
105
- >(self: Repository<T, PM, Evt, ItemType>, collect: (item: T) => Option<S>) {
82
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, collect: (item: T) => Option<S>) {
106
83
  return self.all.map((_) => _.filterMap(collect))
107
84
  }
108
85
 
@@ -114,7 +91,7 @@ export function log<
114
91
  PM extends { id: string },
115
92
  Evt,
116
93
  ItemType extends string
117
- >(_: Repository<T, PM, Evt, ItemType>) {
94
+ >(_: RepositoryBaseC<T, PM, Evt, ItemType>) {
118
95
  return (evt: Evt) => AnyPureDSL.log(evt)
119
96
  }
120
97
 
@@ -131,7 +108,7 @@ export function projectEffect<
131
108
  E,
132
109
  S = PM
133
110
  >(
134
- self: Repository<T, PM, Evt, ItemType>,
111
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
135
112
  map: Effect<R, E, { filter?: Filter<PM>; collect?: (t: PM) => Option<S>; limit?: number; skip?: number }>
136
113
  ) {
137
114
  // TODO: a projection that gets sent to the db instead.
@@ -152,7 +129,7 @@ export function project<
152
129
  ItemType extends string,
153
130
  S = PM
154
131
  >(
155
- self: Repository<T, PM, Evt, ItemType>,
132
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
156
133
  map: { filter?: Filter<PM>; collect?: (t: PM) => Option<S>; limit?: number; skip?: number }
157
134
  ) {
158
135
  return self.projectEffect(Effect(map))
@@ -176,7 +153,7 @@ export function queryEffect<
176
153
  E,
177
154
  S = T
178
155
  >(
179
- self: Repository<T, PM, Evt, ItemType>,
156
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
180
157
  // TODO: think about collectPM, collectE, and collect(Parsed)
181
158
  map: Effect<R, E, { filter?: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }>
182
159
  ) {
@@ -205,7 +182,7 @@ export function queryOneEffect<
205
182
  E,
206
183
  S = T
207
184
  >(
208
- self: Repository<T, PM, Evt, ItemType>,
185
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
209
186
  // TODO: think about collectPM, collectE, and collect(Parsed)
210
187
  map: Effect<R, E, { filter?: Filter<PM>; collect?: (t: T) => Option<S> }>
211
188
  ) {
@@ -237,7 +214,7 @@ export function query<
237
214
  ItemType extends string,
238
215
  S = T
239
216
  >(
240
- self: Repository<T, PM, Evt, ItemType>,
217
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
241
218
  // TODO: think about collectPM, collectE, and collect(Parsed)
242
219
  map: { filter?: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }
243
220
  ) {
@@ -254,7 +231,7 @@ export function queryOne<
254
231
  ItemType extends string,
255
232
  S = T
256
233
  >(
257
- self: Repository<T, PM, Evt, ItemType>,
234
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
258
235
  // TODO: think about collectPM, collectE, and collect(Parsed)
259
236
  map: { filter?: Filter<PM>; collect?: (t: T) => Option<S> }
260
237
  ) {
@@ -273,7 +250,7 @@ export function queryAndSavePureEffect<
273
250
  E,
274
251
  S extends T = T
275
252
  >(
276
- self: Repository<T, PM, Evt, ItemType>,
253
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
277
254
  // TODO: think about collectPM, collectE, and collect(Parsed)
278
255
  map: Effect<R, E, { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }>
279
256
  ) {
@@ -292,7 +269,7 @@ export function queryAndSavePure<
292
269
  ItemType extends string,
293
270
  S extends T = T
294
271
  >(
295
- self: Repository<T, PM, Evt, ItemType>,
272
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
296
273
  // TODO: think about collectPM, collectE, and collect(Parsed)
297
274
  map: { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }
298
275
  ) {
@@ -307,7 +284,7 @@ export function saveManyWithPure<
307
284
  PM extends { id: string },
308
285
  Evt,
309
286
  ItemType extends string
310
- >(self: Repository<T, PM, Evt, ItemType>) {
287
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>) {
311
288
  return <R, A, E, S1 extends T, S2 extends T>(pure: Effect<FixEnv<R, Evt, S1[], S2[]>, E, A>) =>
312
289
  (items: Iterable<S1>) => saveManyWithPure_(self, items, pure)
313
290
  }
@@ -320,7 +297,7 @@ export function byIdAndSaveWithPure<
320
297
  PM extends { id: string },
321
298
  Evt,
322
299
  ItemType extends string
323
- >(self: Repository<T, PM, Evt, ItemType>, id: T["id"]) {
300
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, id: T["id"]) {
324
301
  return <R, A, E, S2 extends T>(pure: Effect<FixEnv<R, Evt, T, S2>, E, A>) =>
325
302
  get(self, id).flatMap((item) => saveWithPure_(self, item, pure))
326
303
  }
@@ -334,7 +311,7 @@ export function handleByIdAndSaveWithPure<
334
311
  PM extends { id: string },
335
312
  Evt,
336
313
  ItemType extends string
337
- >(self: Repository<T, PM, Evt, ItemType>) {
314
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>) {
338
315
  return <Req extends { id: T["id"] }, Context, R, A, E, S2 extends T>(
339
316
  pure: (req: Req, ctx: Context) => Effect<FixEnv<R, Evt, T, S2>, E, A>
340
317
  ) =>
@@ -356,7 +333,7 @@ export function saveManyWithPure_<
356
333
  S2 extends T,
357
334
  ItemType extends string
358
335
  >(
359
- self: Repository<T, PM, Evt, ItemType>,
336
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
360
337
  items: Iterable<S1>,
361
338
  pure: Effect<FixEnv<R, Evt, S1[], S2[]>, E, A>
362
339
  ) {
@@ -381,7 +358,7 @@ export function saveWithPure_<
381
358
  S2 extends T,
382
359
  ItemType extends string
383
360
  >(
384
- self: Repository<T, PM, Evt, ItemType>,
361
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
385
362
  item: S1,
386
363
  pure: Effect<FixEnv<R, Evt, S1, S2>, E, A>
387
364
  ) {
@@ -403,7 +380,7 @@ export function saveAllWithEffectInt<
403
380
  E,
404
381
  A
405
382
  >(
406
- self: Repository<T, PM, Evt, ItemType>,
383
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
407
384
  gen: Effect<R, E, readonly [Iterable<P>, Iterable<Evt>, A]>
408
385
  ) {
409
386
  return gen
@@ -424,7 +401,7 @@ export function queryAndSavePureEffectBatched<
424
401
  E,
425
402
  S extends T = T
426
403
  >(
427
- self: Repository<T, PM, Evt, ItemType>,
404
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
428
405
  // TODO: think about collectPM, collectE, and collect(Parsed)
429
406
  map: Effect<R, E, { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }>,
430
407
  batchSize = 100
@@ -444,7 +421,7 @@ export function queryAndSavePureBatched<
444
421
  ItemType extends string,
445
422
  S extends T = T
446
423
  >(
447
- self: Repository<T, PM, Evt, ItemType>,
424
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
448
425
  // TODO: think about collectPM, collectE, and collect(Parsed)
449
426
  map: { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number },
450
427
  batchSize = 100
@@ -460,7 +437,7 @@ export function saveManyWithPureBatched<
460
437
  PM extends { id: string },
461
438
  Evt,
462
439
  ItemType extends string
463
- >(self: Repository<T, PM, Evt, ItemType>, batchSize = 100) {
440
+ >(self: RepositoryBaseC<T, PM, Evt, ItemType>, batchSize = 100) {
464
441
  return <R, A, E, S1 extends T, S2 extends T>(pure: Effect<FixEnv<R, Evt, S1[], S2[]>, E, A>) =>
465
442
  (items: Iterable<S1>) => saveManyWithPureBatched_(self, items, pure, batchSize)
466
443
  }
@@ -480,7 +457,7 @@ export function saveManyWithPureBatched_<
480
457
  S2 extends T,
481
458
  ItemType extends string
482
459
  >(
483
- self: Repository<T, PM, Evt, ItemType>,
460
+ self: RepositoryBaseC<T, PM, Evt, ItemType>,
484
461
  items: Iterable<S1>,
485
462
  pure: Effect<FixEnv<R, Evt, S1[], S2[]>, E, A>,
486
463
  batchSize = 100
@@ -628,7 +605,7 @@ export function save<
628
605
  Evt,
629
606
  ItemType extends string
630
607
  >(
631
- self: Repository<T, PM, Evt, ItemType>
608
+ self: RepositoryBaseC<T, PM, Evt, ItemType>
632
609
  ) {
633
610
  return (...items: NonEmptyArray<T>) => self.saveAndPublish(items)
634
611
  }
@@ -642,7 +619,7 @@ export function saveWithEvents<
642
619
  Evt,
643
620
  ItemType extends string
644
621
  >(
645
- self: Repository<T, PM, Evt, ItemType>
622
+ self: RepositoryBaseC<T, PM, Evt, ItemType>
646
623
  ) {
647
624
  return (events: Iterable<Evt>) => (...items: NonEmptyArray<T>) => self.saveAndPublish(items, events)
648
625
  }
@@ -15,55 +15,74 @@ import type { InvalidStateError, OptimisticConcurrencyException } from "../error
15
15
  import { ContextMapContainer } from "./Store/ContextMapContainer.js"
16
16
 
17
17
  /**
18
- * A base for creating an abstract class usable as Tag, Companion and interface to create your own implementation.
18
+ * @tsplus type Repository
19
19
  */
20
- export const RepositoryBase = <Service>() => {
21
- return <T extends { id: string }, PM extends { id: string; _etag: string | undefined }, Evt, ItemType extends string>(
22
- itemType: ItemType
23
- ) => {
24
- abstract class RepositoryBaseC implements Repository<T, PM, Evt, ItemType> {
25
- readonly itemType: ItemType = itemType
26
- abstract readonly find: (id: T["id"]) => Effect<never, never, Opt<T>>
27
- abstract readonly all: Effect<never, never, T[]>
28
- abstract readonly saveAndPublish: (
29
- items: Iterable<T>,
30
- events?: Iterable<Evt>
31
- ) => Effect<never, InvalidStateError | OptimisticConcurrencyException, void>
32
- abstract readonly utils: {
33
- mapReverse: (
34
- pm: PM,
35
- setEtag: (id: string, eTag: string | undefined) => void
36
- ) => unknown // TODO
37
- parse: (a: unknown, env?: ParserEnv | undefined) => T
38
- all: Effect<never, never, PM[]>
39
- filter: (filter: Filter<PM>, cursor?: { limit?: number; skip?: number }) => Effect<never, never, PM[]>
40
- }
41
- abstract readonly changeFeed: PubSub<[T[], "save" | "remove"]>
42
- abstract readonly removeAndPublish: (
43
- items: Iterable<T>,
44
- events?: Iterable<Evt>
45
- ) => Effect<never, never, void>
46
- static readonly where = makeWhere<PM>()
47
- static flatMap<R1, E1, B>(f: (a: Service) => Effect<R1, E1, B>): Effect<Service | R1, E1, B> {
48
- return Effect.flatMap(this as unknown as Tag<Service, Service>, f)
49
- }
50
- static map<B>(f: (a: Service) => B): Effect<Service, never, B> {
51
- return Effect.map(this as unknown as Tag<Service, Service>, f)
52
- }
53
- static makeLayer(svc: Service) {
54
- return Layer.succeed(this as unknown as Tag<Service, Service>, svc)
55
- }
56
- }
57
- return assignTag<Service>()(RepositoryBaseC)
20
+ export abstract class RepositoryBaseC<
21
+ T extends { id: string },
22
+ PM extends { id: string },
23
+ Evt,
24
+ ItemType extends string
25
+ > {
26
+ abstract readonly itemType: ItemType
27
+ abstract readonly find: (id: T["id"]) => Effect<never, never, Opt<T>>
28
+ abstract readonly all: Effect<never, never, T[]>
29
+ abstract readonly saveAndPublish: (
30
+ items: Iterable<T>,
31
+ events?: Iterable<Evt>
32
+ ) => Effect<never, InvalidStateError | OptimisticConcurrencyException, void>
33
+ abstract readonly utils: {
34
+ mapReverse: (
35
+ pm: PM,
36
+ setEtag: (id: string, eTag: string | undefined) => void
37
+ ) => unknown // TODO
38
+ parse: (a: unknown, env?: ParserEnv | undefined) => T
39
+ all: Effect<never, never, PM[]>
40
+ filter: (filter: Filter<PM>, cursor?: { limit?: number; skip?: number }) => Effect<never, never, PM[]>
41
+ }
42
+ abstract readonly changeFeed: PubSub<[T[], "save" | "remove"]>
43
+ abstract readonly removeAndPublish: (
44
+ items: Iterable<T>,
45
+ events?: Iterable<Evt>
46
+ ) => Effect<never, never, void>
47
+ }
48
+
49
+ export abstract class RepositoryBaseC1<
50
+ T extends { id: string },
51
+ PM extends { id: string },
52
+ Evt,
53
+ ItemType extends string
54
+ > extends RepositoryBaseC<T, PM, Evt, ItemType> {
55
+ constructor(
56
+ public readonly itemType: ItemType
57
+ ) {
58
+ super()
58
59
  }
59
60
  }
60
61
 
62
+ export class RepositoryBaseC2<T extends { id: string }, PM extends { id: string }, Evt, ItemType extends string>
63
+ extends RepositoryBaseC1<T, PM, Evt, ItemType>
64
+ {
65
+ constructor(
66
+ itemType: ItemType,
67
+ protected readonly impl: Repository<T, PM, Evt, ItemType>
68
+ ) {
69
+ super(itemType)
70
+ }
71
+ // makes super calls a compiler error, as it should
72
+ override saveAndPublish = this.impl.saveAndPublish
73
+ override removeAndPublish = this.impl.removeAndPublish
74
+ override find = this.impl.find
75
+ override all = this.impl.all
76
+ override utils = this.impl.utils
77
+ override changeFeed = this.impl.changeFeed
78
+ }
79
+
61
80
  /**
62
81
  * A base implementation to create a repository.
63
82
  */
64
83
  export function makeRepo<
65
84
  PM extends { id: string; _etag: string | undefined },
66
- Evt = unknown
85
+ Evt = never
67
86
  >() {
68
87
  return <
69
88
  ItemType extends string,
@@ -97,14 +116,14 @@ export function makeRepo<
97
116
  const mkStore = makeStore<PM>()(name, schema, mapTo)
98
117
 
99
118
  function make<R = never, E = never, R2 = never>(
100
- args: [Evt] extends [object] ? {
101
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
119
+ args: [Evt] extends [never] ? {
102
120
  makeInitial?: Effect<R, E, readonly T[]>
103
121
  config?: Omit<StoreConfig<PM>, "partitionValue"> & {
104
122
  partitionValue?: (a: PM) => string
105
123
  }
106
124
  }
107
125
  : {
126
+ publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
108
127
  makeInitial?: Effect<R, E, readonly T[]>
109
128
  config?: Omit<StoreConfig<PM>, "partitionValue"> & {
110
129
  partitionValue?: (a: PM) => string
@@ -326,49 +345,85 @@ export function makeStore<
326
345
  }
327
346
  }
328
347
 
348
+ type Repos<
349
+ Service,
350
+ Out,
351
+ T extends { id: string },
352
+ PM extends { id: string; _etag: string | undefined },
353
+ Evt
354
+ > = {
355
+ make<R = never, E = never, R2 = never>(
356
+ args: [Evt] extends [never] ? {
357
+ makeInitial?: Effect<R, E, readonly T[]>
358
+ config?: Omit<StoreConfig<PM>, "partitionValue"> & {
359
+ partitionValue?: (a: PM) => string
360
+ }
361
+ }
362
+ : {
363
+ publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
364
+ makeInitial?: Effect<R, E, readonly T[]>
365
+ config?: Omit<StoreConfig<PM>, "partitionValue"> & {
366
+ partitionValue?: (a: PM) => string
367
+ }
368
+ }
369
+ ): Effect<
370
+ StoreMaker | ContextMapContainer | R | R2,
371
+ E,
372
+ Out
373
+ >
374
+ where: ReturnType<typeof makeWhere<PM>>
375
+ flatMap: <R1, E1, B>(f: (a: Service) => Effect<R1, E1, B>) => Effect<Service | R1, E1, B>
376
+ makeLayer: (svc: Service) => Layer<never, never, Service>
377
+ map: <B>(f: (a: Service) => B) => Effect<Service, never, B>
378
+ }
379
+
329
380
  export const RepositoryBaseImpl = <Service>() => {
330
381
  return <
331
382
  PM extends { id: string; _etag: string | undefined },
332
- Evt = unknown
383
+ Evt = never
333
384
  >() =>
334
385
  <ItemType extends string, T extends { id: string }, ConstructorInput, Api, E extends { id: string }>(
335
386
  itemType: ItemType,
336
387
  schema: Schema.Schema<unknown, T, ConstructorInput, E, Api>,
337
388
  mapFrom: (pm: Omit<PM, "_etag">) => E,
338
389
  mapTo: (e: E, etag: string | undefined) => PM
339
- ): (abstract new() => Repository<T, PM, Evt, ItemType>) & Tag<Service, Service> & {
340
- make<R = never, E = never, R2 = never>(
341
- args: [Evt] extends [object] ? {
342
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
343
- makeInitial?: Effect<R, E, readonly T[]>
344
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
345
- partitionValue?: (a: PM) => string
346
- }
347
- }
348
- : {
349
- makeInitial?: Effect<R, E, readonly T[]>
350
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
351
- partitionValue?: (a: PM) => string
352
- }
353
- }
354
- ): Effect<StoreMaker | ContextMapContainer | R | R2, E, Repository<T, PM, Evt, ItemType>>
355
- where: ReturnType<typeof makeWhere<PM>>
356
- flatMap: <R1, E1, B>(f: (a: Service) => Effect<R1, E1, B>) => Effect<Service | R1, E1, B>
357
- makeLayer: (svc: Service) => Layer<never, never, Service>
358
- map: <B>(f: (a: Service) => B) => Effect<Service, never, B>
359
- } => {
390
+ ):
391
+ & (abstract new() => Omit<RepositoryBaseC1<T, PM, Evt, ItemType>, "impl">)
392
+ & Tag<Service, Service>
393
+ & Repos<
394
+ Service,
395
+ Repository<T, PM, Evt, ItemType>,
396
+ T,
397
+ PM,
398
+ Evt
399
+ > =>
400
+ {
360
401
  const mkRepo = makeRepo<PM, Evt>()(itemType, schema, mapFrom, mapTo)
361
- abstract class Cls extends RepositoryBase<Service>()<T, PM, Evt, ItemType>(itemType) {
402
+ abstract class Cls extends RepositoryBaseC1<T, PM, Evt, ItemType> {
403
+ constructor() {
404
+ super(itemType)
405
+ }
362
406
  static readonly make = mkRepo.make
407
+
408
+ static readonly where = makeWhere<PM>()
409
+ static flatMap<R1, E1, B>(f: (a: Service) => Effect<R1, E1, B>): Effect<Service | R1, E1, B> {
410
+ return Effect.flatMap(this as unknown as Tag<Service, Service>, f)
411
+ }
412
+ static map<B>(f: (a: Service) => B): Effect<Service, never, B> {
413
+ return Effect.map(this as unknown as Tag<Service, Service>, f)
414
+ }
415
+ static makeLayer(svc: Service) {
416
+ return Layer.succeed(this as unknown as Tag<Service, Service>, svc)
417
+ }
363
418
  }
364
- return Cls
419
+ return assignTag<Service>()(Cls)
365
420
  }
366
421
  }
367
422
 
368
423
  export const RepositoryDefaultImpl = <Service>() => {
369
424
  return <
370
425
  PM extends { id: string; _etag: string | undefined },
371
- Evt = unknown
426
+ Evt = never
372
427
  >() =>
373
428
  <ItemType extends string, T extends { id: string }, ConstructorInput, Api, E extends { id: string }>(
374
429
  itemType: ItemType,
@@ -376,88 +431,56 @@ export const RepositoryDefaultImpl = <Service>() => {
376
431
  mapFrom: (pm: Omit<PM, "_etag">) => E,
377
432
  mapTo: (e: E, etag: string | undefined) => PM
378
433
  ):
434
+ & (abstract new(
435
+ impl: Repository<T, PM, Evt, ItemType>
436
+ ) => RepositoryBaseC2<T, PM, Evt, ItemType>)
379
437
  & Tag<Service, Service>
380
- & {
381
- new(
382
- impl: Repository<T, PM, Evt, ItemType>
383
- ): Repository<T, PM, Evt, ItemType>
384
-
385
- where: ReturnType<typeof makeWhere<PM>>
386
- flatMap: <R1, E1, B>(f: (a: Service) => Effect<R1, E1, B>) => Effect<Service | R1, E1, B>
387
- makeLayer: (svc: Service) => Layer<never, never, Service>
388
- map: <B>(f: (a: Service) => B) => Effect<Service, never, B>
389
- repo: Repository<T, PM, Evt, ItemType> // just a helper to type the constructor
390
- }
391
- & ([Evt] extends [object] ? {
392
- make<R = never, E = never, R2 = never>(
393
- args: {
394
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
395
- makeInitial?: Effect<R, E, readonly T[]>
396
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
397
- partitionValue?: (a: PM) => string
398
- }
399
- }
400
- ): Effect<StoreMaker | R | R2, E, Repository<T, PM, Evt, ItemType>>
401
-
402
- toLayer<R = never, E = never, R2 = never>(
403
- args: {
404
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
405
- makeInitial?: Effect<R, E, readonly T[]>
406
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
407
- partitionValue?: (a: PM) => string
408
- }
409
- }
410
- ): Layer<StoreMaker | R | R2, E, Service>
411
- }
412
- : {
413
- make<R = never, E = never>(
414
- args: {
415
- makeInitial?: Effect<R, E, readonly T[]>
416
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
417
- partitionValue?: (a: PM) => string
418
- }
419
- }
420
- ): Effect<StoreMaker | R, E, Repository<T, PM, Evt, ItemType>>
421
- toLayer<R = never, E = never>(
422
- args: {
423
- makeInitial?: Effect<R, E, readonly T[]>
424
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
425
- partitionValue?: (a: PM) => string
426
- }
427
- }
428
- ): Layer<StoreMaker | R, E, Service>
429
- }) =>
438
+ & Repos<
439
+ Service,
440
+ RepositoryBaseC2<T, PM, Evt, ItemType>,
441
+ T,
442
+ PM,
443
+ Evt
444
+ > =>
430
445
  {
431
- return class extends RepositoryBaseImpl<Service>()<PM, Evt>()(itemType, schema, mapFrom, mapTo) {
432
- static toLayer<R = never, E = never, R2 = never>(
433
- args: [Evt] extends [object] ? {
434
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<R2, never, void>
435
- makeInitial?: Effect<R, E, readonly T[]>
436
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
437
- partitionValue?: (a: PM) => string
438
- }
439
- }
440
- : {
441
- makeInitial?: Effect<R, E, readonly T[]>
442
- config?: Omit<StoreConfig<PM>, "partitionValue"> & {
443
- partitionValue?: (a: PM) => string
444
- }
445
- }
446
- ) {
447
- return this
448
- .make(args)
449
- .map((impl) => new this(impl) as any as Service)
450
- .toLayer(
451
- this
452
- )
453
- }
454
- static repo: any
446
+ const mkRepo = makeRepo<PM, Evt>()(itemType, schema, mapFrom, mapTo)
447
+ abstract class Cls extends RepositoryBaseC2<T, PM, Evt, ItemType> {
455
448
  constructor(
456
449
  impl: Repository<T, PM, Evt, ItemType>
457
450
  ) {
458
- super()
459
- Object.assign(this, impl)
451
+ super(itemType, impl)
452
+ }
453
+ static readonly make = mkRepo.make
454
+
455
+ static readonly where = makeWhere<PM>()
456
+ static flatMap<R1, E1, B>(f: (a: Service) => Effect<R1, E1, B>): Effect<Service | R1, E1, B> {
457
+ return Effect.flatMap(this as unknown as Tag<Service, Service>, f)
460
458
  }
461
- } as any // TODO: seems to be a compiler bug, it somehow says its missing toLayer and repo...
459
+ static map<B>(f: (a: Service) => B): Effect<Service, never, B> {
460
+ return Effect.map(this as unknown as Tag<Service, Service>, f)
461
+ }
462
+ static makeLayer(svc: Service) {
463
+ return Layer.succeed(this as unknown as Tag<Service, Service>, svc)
464
+ }
465
+ }
466
+ return assignTag<Service>()(Cls) as any // impl is missing, but its marked protected
462
467
  }
463
468
  }
469
+
470
+ // @useClassFeaturesForSchema
471
+ // export class Shop extends Model<Shop>()({ id: string }) {}
472
+
473
+ // /**
474
+ // * @tsplus type ShopRepo
475
+ // * @tsplus companion ShopRepo.Ops
476
+ // */
477
+ // export class ShopRepo extends RepositoryDefaultImpl<ShopRepo>()<Shop & { _etag: string | undefined }>()(
478
+ // "Shop",
479
+ // Shop,
480
+ // (pm) => pm,
481
+ // (e, _etag) => ({ ...e, _etag })
482
+ // ) {
483
+ // override saveAndPublish = (items: Iterable<Shop>, events?: Iterable<unknown> | undefined) => {
484
+ // return this.impl.saveAndPublish(items, events)
485
+ // }
486
+ // }