@effect-app/infra 0.211.1 → 0.211.3

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.
@@ -8,7 +8,6 @@ import {
8
8
  AnyPureDSL,
9
9
  byIdAndSaveWithPure,
10
10
  get,
11
- queryEffect,
12
11
  type Repository,
13
12
  saveAllWithEffectInt,
14
13
  saveManyWithPure_,
@@ -16,7 +15,7 @@ import {
16
15
  saveWithPure_
17
16
  } from "./Repository.js"
18
17
  import { StoreMaker } from "./Store.js"
19
- import type { Filter, FilterArgs, FilterFunc, PersistenceModelType, StoreConfig } from "./Store.js"
18
+ import type { FilterArgs, PersistenceModelType, StoreConfig } from "./Store.js"
20
19
  import type {} from "effect/Equal"
21
20
  import type {} from "effect/Hash"
22
21
  import { toNonEmptyArray } from "@effect-app/core/Array"
@@ -35,7 +34,7 @@ import { make as makeQuery } from "./query.js"
35
34
  import type { QAll, Query, QueryEnd, QueryProjection, QueryWhere } from "./query.js"
36
35
  import * as Q from "./query.js"
37
36
  import { ContextMapContainer } from "./Store/ContextMapContainer.js"
38
- import * as QB from "./Store/filterApi/query.js"
37
+ import type * as QB from "./Store/filterApi/query.js"
39
38
 
40
39
  export interface Mapped1<PM extends { id: string }, X, R> {
41
40
  all: Effect<X[], ParseResult.ParseError, R>
@@ -82,24 +81,12 @@ export abstract class RepositoryBaseC<
82
81
  items: Iterable<T>,
83
82
  events?: Iterable<Evt>
84
83
  ) => Effect<void, InvalidStateError | OptimisticConcurrencyException>
85
- abstract readonly utils: {
86
- parseMany: (a: readonly PM[]) => Effect<readonly T[]>
87
- parseMany2: <A, R>(
88
- a: readonly PM[],
89
- schema: S.Schema<A, Omit<PM, "_etag">, R>
90
- ) => Effect<readonly A[], S.ParseResult.ParseError, R>
91
- all: Effect<PM[]>
92
- filter: FilterFunc<PM>
93
- // count: (filter?: Filter<PM>) => Effect<never, never, NonNegativeInt>
94
- }
95
84
  abstract readonly changeFeed: PubSub.PubSub<[T[], "save" | "remove"]>
96
85
  abstract readonly removeAndPublish: (
97
86
  items: Iterable<T>,
98
87
  events?: Iterable<Evt>
99
88
  ) => Effect<void>
100
89
 
101
- /** @deprecated use query */
102
- abstract readonly mapped: Mapped<PM, Omit<PM, "_etag">>
103
90
  abstract readonly query: {
104
91
  <A, R, From extends FieldValues, TType extends "one" | "many" | "count" = "many">(
105
92
  q: (
@@ -119,6 +106,9 @@ export abstract class RepositoryBaseC<
119
106
  // q: QueryProjection<Omit<PM, "_etag"> extends From ? From : never, A, R>
120
107
  // ): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
121
108
  }
109
+
110
+ /** @deprecated use query */
111
+ abstract readonly mapped: Mapped<PM, Omit<PM, "_etag">>
122
112
  }
123
113
 
124
114
  export abstract class RepositoryBaseC1<
@@ -149,7 +139,6 @@ export class RepositoryBaseC2<
149
139
  this.removeAndPublish = this.impl.removeAndPublish
150
140
  this.find = this.impl.find
151
141
  this.all = this.impl.all
152
- this.utils = this.impl.utils
153
142
  this.changeFeed = this.impl.changeFeed
154
143
  this.mapped = this.impl.mapped
155
144
  this.query = this.impl.query
@@ -159,7 +148,6 @@ export class RepositoryBaseC2<
159
148
  override removeAndPublish
160
149
  override find
161
150
  override all
162
- override utils
163
151
  override changeFeed
164
152
  override mapped
165
153
  override query
@@ -220,7 +208,7 @@ export class RepositoryBaseC3<
220
208
  q: Query<Omit<PM, "_etag">>
221
209
  ) => Query<Omit<PM, "_etag">> | QueryWhere<Omit<PM, "_etag">> | QueryEnd<Omit<PM, "_etag">, "many">,
222
210
  pure: Effect<A, E2, FixEnv<R2, Evt, readonly T[], readonly T2[]>>,
223
- batched: "batched" | number
211
+ batch: "batched" | number
224
212
  ): Effect.Effect<
225
213
  A[],
226
214
  InvalidStateError | OptimisticConcurrencyException | E2,
@@ -228,15 +216,16 @@ export class RepositoryBaseC3<
228
216
  env: PureEnv<Evt, readonly T[], readonly T2[]>
229
217
  }>
230
218
  >
231
- } = (q, pure, batched?) =>
219
+ } = (q, pure, batch?: "batched" | number) =>
232
220
  this.query(q).pipe(
233
- Effect.andThen((_) =>
234
- Array.isArray(_)
235
- ? batched === undefined
221
+ Effect.andThen((_) => {
222
+ console.log("$$$ query returned", _, pure, batch)
223
+ return Array.isArray(_)
224
+ ? batch === undefined
236
225
  ? saveManyWithPure_(this, _, pure as any)
237
- : saveManyWithPureBatched_(this, _, pure as any, batched as any)
226
+ : saveManyWithPureBatched_(this, _, pure as any, batch === "batched" ? 100 : batch)
238
227
  : saveWithPure_(this, _ as any, pure as any)
239
- )
228
+ })
240
229
  ) as any
241
230
 
242
231
  /**
@@ -313,31 +302,6 @@ export class RepositoryBaseC3<
313
302
  .pipe(Effect.map(([item, events, a]) => [[item], events, a]))
314
303
  )
315
304
  }
316
-
317
- /** @deprecated use query */
318
- queryLegacy<S = T>(
319
- // TODO: think about collectPM, collectE, and collect(Parsed)
320
- _map: { filter?: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number }
321
- ) {
322
- return Effect.flatMap(Effect.sync(() => _map), (f) =>
323
- (f.filter ? this.utils.filter(f) : this.utils.all)
324
- .pipe(
325
- Effect.flatMap((_) => this.utils.parseMany(_)),
326
- Effect.map((_) => f.collect ? ReadonlyArray.filterMap(_, f.collect) : _ as unknown[] as S[])
327
- ))
328
- }
329
-
330
- /** @deprecated use query */
331
- queryAndSavePureBatched<
332
- S extends T = T
333
- >(
334
- // TODO: think about collectPM, collectE, and collect(Parsed)
335
- map: { filter: Filter<PM>; collect?: (t: T) => Option<S>; limit?: number; skip?: number },
336
- batchSize = 100
337
- ) {
338
- return <R2, A, E2, S2 extends T>(pure: Effect<A, E2, FixEnv<R2, Evt, readonly S[], readonly S2[]>>) =>
339
- Effect.flatMap(queryEffect(this, Effect.succeed(map)), (_) => this.saveManyWithPure(_, pure, batchSize))
340
- }
341
305
  }
342
306
 
343
307
  type Exact<A, B> = [A] extends [B] ? [B] extends [A] ? true : false : false
@@ -415,12 +379,8 @@ export function makeRepo<
415
379
  : () => Effect.unit
416
380
  const changeFeed = yield* $(PubSub.unbounded<[T[], "save" | "remove"]>())
417
381
 
418
- const allE = store.all.pipe(Effect.flatMap((items) =>
419
- Effect.gen(function*($) {
420
- const { set } = yield* $(cms)
421
- return items.map((_) => mapReverse(_, set))
422
- })
423
- ))
382
+ const allE = cms
383
+ .pipe(Effect.flatMap((cm) => Effect.map(store.all, (_) => _.map((_) => mapReverse(_, cm.set)))))
424
384
 
425
385
  const all = Effect
426
386
  .flatMap(
@@ -531,33 +491,30 @@ export function makeRepo<
531
491
  })
532
492
  }
533
493
 
534
- const utils = {
535
- parseMany: (items) =>
536
- Effect
537
- .flatMap(cms, (cm) =>
538
- decodeMany(items.map((_) => mapReverse(_, cm.set)))
539
- .pipe(Effect.orDie, Effect.withSpan("parseMany"))),
540
- parseMany2: (items, schema) =>
541
- Effect
542
- .flatMap(cms, (cm) =>
543
- S
544
- .decode(S.array(schema))(
545
- items.map((_) => mapReverse(_, cm.set) as unknown as Omit<PM, "_etag">)
546
- )
547
- .pipe(Effect.orDie, Effect.withSpan("parseMany2"))),
548
- filter: <U extends keyof PM = keyof PM>(args: FilterArgs<PM, U>) =>
549
- store
550
- .filter(args)
551
- .pipe(Effect.tap((items) =>
552
- args.select
553
- ? Effect.unit
554
- : Effect.map(cms, ({ set }) => items.forEach((_) => set((_ as PM).id, (_ as PM)._etag)))
555
- )),
556
- all: Effect.tap(
557
- store.all,
558
- (items) => Effect.map(cms, ({ set }) => items.forEach((_) => set(_.id, _._etag)))
559
- )
560
- } satisfies Repository<T, PM, Evt, ItemType>["utils"]
494
+ const parseMany = (items: readonly PM[]) =>
495
+ Effect
496
+ .flatMap(cms, (cm) =>
497
+ decodeMany(items.map((_) => mapReverse(_, cm.set)))
498
+ .pipe(Effect.orDie, Effect.withSpan("parseMany")))
499
+ const parseMany2 = <A, R>(
500
+ items: readonly PM[],
501
+ schema: S.Schema<A, Omit<PM, "_etag">, R>
502
+ ) =>
503
+ Effect
504
+ .flatMap(cms, (cm) =>
505
+ S
506
+ .decode(S.array(schema))(
507
+ items.map((_) => mapReverse(_, cm.set) as unknown as Omit<PM, "_etag">)
508
+ )
509
+ .pipe(Effect.orDie, Effect.withSpan("parseMany2")))
510
+ const filter = <U extends keyof PM = keyof PM>(args: FilterArgs<PM, U>) =>
511
+ store
512
+ .filter(args)
513
+ .pipe(Effect.tap((items) =>
514
+ args.select
515
+ ? Effect.unit
516
+ : Effect.map(cms, ({ set }) => items.forEach((_) => set((_ as PM).id, (_ as PM)._etag)))
517
+ ))
561
518
 
562
519
  // TODO: For raw we should use S.from, and drop the R...
563
520
  const query: {
@@ -580,22 +537,20 @@ export function makeRepo<
580
537
  >(q: QAll<PM, A, R>) => {
581
538
  const a = Q.toFilter(q)
582
539
  const eff = a.mode === "raw"
583
- ? r
584
- .utils
585
- .filter(a)
540
+ ? filter(a)
586
541
  // TODO: mapFrom but need to support per field and dependencies
587
542
  .pipe(Effect.andThen(flow(S.decode(S.array(S.from(a.schema ?? schema))), Effect.provide(rctx))))
588
543
  : Effect.flatMap(
589
- utils.filter(a),
544
+ filter(a),
590
545
  (_) =>
591
546
  Unify
592
547
  .unify(
593
548
  a.schema
594
- ? utils.parseMany2(
549
+ ? parseMany2(
595
550
  _,
596
551
  a.schema as any
597
552
  )
598
- : utils.parseMany(_)
553
+ : parseMany(_)
599
554
  )
600
555
  )
601
556
  return pipe(
@@ -623,40 +578,36 @@ export function makeRepo<
623
578
  }) as any
624
579
 
625
580
  const r: Repository<T, PM, Evt, ItemType> = {
581
+ changeFeed,
582
+ itemType: name,
583
+ find,
584
+ all,
585
+ saveAndPublish,
586
+ removeAndPublish,
587
+ query: (q: any) => query(typeof q === "function" ? q(makeQuery()) : q) as any,
588
+
626
589
  /**
627
590
  * @internal
628
591
  */
629
- utils,
630
592
  mapped: <A, R>(schema: S.Schema<A, any, R>) => {
631
593
  const dec = S.decode(schema)
632
594
  const encMany = S.encode(S.array(schema))
633
595
  const decMany = S.decode(S.array(schema))
634
596
  return {
635
- all: cms
636
- .pipe(
637
- Effect.flatMap((cm) => Effect.map(utils.all, (_) => _.map((_) => mapReverse(_, cm.set)))),
638
- Effect.flatMap(decMany),
639
- Effect.map((_) => _ as any[])
640
- ),
597
+ all: allE.pipe(
598
+ Effect.flatMap(decMany),
599
+ Effect.map((_) => _ as any[])
600
+ ),
641
601
  find: (id: PM["id"]) => flatMapOption(findE(id), dec),
642
602
  query: (b: any) =>
643
- r
644
- .utils
645
- .filter({ filter: b })
603
+ filter({ filter: b })
646
604
  .pipe(
647
605
  Effect.flatMap(decMany),
648
606
  Effect.map((_) => _ as any[])
649
607
  ),
650
608
  save: (...xes: any[]) => Effect.flatMap(encMany(xes), (_) => saveAllE(_))
651
609
  }
652
- },
653
- changeFeed,
654
- itemType: name,
655
- find,
656
- all,
657
- saveAndPublish,
658
- removeAndPublish,
659
- query: (q: any) => query(typeof q === "function" ? q(makeQuery()) : q) as any
610
+ }
660
611
  }
661
612
  return r
662
613
  })
@@ -667,28 +618,11 @@ export function makeRepo<
667
618
 
668
619
  return {
669
620
  make,
670
- Query: QB.QueryBuilder.make<PM>(),
671
621
  Q: Q.make<Omit<PM, "_etag">>()
672
622
  }
673
623
  }
674
624
  }
675
625
 
676
- /**
677
- * only use this as a shortcut if you don't have the item already
678
- * @tsplus fluent Repository removeById
679
- */
680
- export function removeById<
681
- T extends { id: unknown },
682
- PM extends PersistenceModelType<string>,
683
- Evt,
684
- ItemType extends string
685
- >(
686
- self: Repository<T, PM, Evt, ItemType>,
687
- id: T["id"]
688
- ) {
689
- return get(self, id).pipe(Effect.flatMap((_) => self.removeAndPublish([_])))
690
- }
691
-
692
626
  const pluralize = (s: string) =>
693
627
  s.endsWith("s")
694
628
  ? s + "es"
@@ -799,8 +733,6 @@ export interface Repos<
799
733
  },
800
734
  f: (r: Repository<T, PM, Evt, ItemType>) => Out
801
735
  ): Effect<Out, E, StoreMaker | ContextMapContainer | R | RInitial | R2>
802
- /** @deprecated use `Q` instead */
803
- readonly Query: ReturnType<typeof QB.QueryBuilder.make<PM>>
804
736
  readonly Q: ReturnType<typeof Q.make<PM>>
805
737
  readonly type: Repository<T, PM, Evt, ItemType>
806
738
  }
@@ -927,14 +859,6 @@ export interface RepoFunctions<T extends { id: unknown }, PM extends { id: strin
927
859
  >
928
860
  }
929
861
 
930
- /** @deprecated use query */
931
- queryLegacy: <S = T>(map: {
932
- filter?: Filter<PM>
933
- collect?: (t: T) => Option<S>
934
- limit?: number
935
- skip?: number
936
- }) => Effect<S[], never, Service>
937
-
938
862
  /** @experimental */
939
863
  mapped: MM<Service, PM, Omit<PM, "_etag">>
940
864
 
@@ -951,7 +875,6 @@ const makeRepoFunctions = (tag: any) => {
951
875
  get,
952
876
  query,
953
877
  queryAndSavePure,
954
- queryLegacy,
955
878
  removeAndPublish,
956
879
  removeById,
957
880
  save,
@@ -971,7 +894,6 @@ const makeRepoFunctions = (tag: any) => {
971
894
  save,
972
895
  get,
973
896
  query,
974
- queryLegacy,
975
897
  mapped,
976
898
  queryAndSavePure,
977
899
  saveManyWithPure,
@@ -1014,7 +936,6 @@ export const RepositoryBaseImpl = <Service>() => {
1014
936
  static readonly make = mkRepo.make
1015
937
  static readonly makeWith = ((a: any, b: any) => Effect.map(mkRepo.make(a), b)) as any
1016
938
 
1017
- static readonly Query = QB.QueryBuilder.make<PM>()
1018
939
  static readonly Q = Q.make<From>()
1019
940
  static readonly type: Repository<T, PM, Evt, ItemType> = undefined as any
1020
941
  }
@@ -1062,7 +983,6 @@ export const RepositoryDefaultImpl = <Service>() => {
1062
983
  static readonly make = mkRepo.make
1063
984
  static readonly makeWith = ((a: any, b: any) => Effect.map(mkRepo.make(a), b)) as any
1064
985
 
1065
- static readonly Query = QB.QueryBuilder.make<PM>()
1066
986
  static readonly Q = Q.make<From>()
1067
987
 
1068
988
  static readonly type: Repository<T, PM, Evt, ItemType> = undefined as any
@@ -53,52 +53,6 @@ export const codeFilterStatement = <E>(p: FilterR, x: E) => {
53
53
  }
54
54
  }
55
55
 
56
- // const or = <E extends { id: string }, NE extends E>(filters: readonly FilterResult[], x: E): Option<NE> =>
57
- // filters
58
- // .some((p) => {
59
- // if (p.t === "and-scope") {
60
- // return and(p.result, x)
61
- // }
62
- // if (p.t === "or-scope") {
63
- // return or(p.result, x)
64
- // }
65
- // if (p.t === "where-scope") {
66
- // return codeFilter2(filters)(x)
67
- // }
68
- // return codeFilterStatement(p, x)
69
- // })
70
- // ? Option.some(x as unknown as NE)
71
- // : Option.none()
72
-
73
- // export const and = <E extends { id: string }, NE extends E>(filters: readonly FilterResult[], x: E): Option<NE> =>
74
- // filters
75
- // .every((p) => {
76
- // if (p.t === "and-scope") {
77
- // return and(p.result, x)
78
- // }
79
- // if (p.t === "or-scope") {
80
- // return or(p.result, x)
81
- // }
82
- // if (p.t === "where-scope") {
83
- // return codeFilter2(filters)(x)
84
- // }
85
- // return codeFilterStatement(p, x)
86
- // })
87
- // ? Option.some(x as unknown as NE)
88
- // : Option.none()
89
-
90
- // // TODO: how to handle and/or outside scopes.
91
- // // TODO: the scopes are not about and every, or some.. they're about logical grouping. It's a logical group + and/or etc.
92
- // // TODO: how to convert this to code? would we compile an actual function body instead?!
93
- // export function codeFilter2<E extends { id: string }, NE extends E>(filters: readonly FilterResult[]) {
94
- // // TODO: handle or, and, or-scope, and-scope, where-scope
95
- // return (x: E) =>
96
- // // AND
97
- // and<E, NE>(filters, x)
98
- // // OR
99
- // // or<E, NE>(filters, x)
100
- // }
101
-
102
56
  export const codeFilter3 = <E>(state: readonly FilterResult[]) => (sut: E) => codeFilter3_(state, sut)
103
57
  export const codeFilter3_ = <E>(state: readonly FilterResult[], sut: E, statements: any[] = []): boolean => {
104
58
  let s = ""