@effect-app/infra 2.11.0 → 2.12.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 (65) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/_cjs/Model/Repository/ext.cjs +1 -1
  3. package/_cjs/Model/Repository/ext.cjs.map +1 -1
  4. package/_cjs/Model/Repository/internal/internal.cjs +18 -20
  5. package/_cjs/Model/Repository/internal/internal.cjs.map +1 -1
  6. package/_cjs/Model/Repository/makeRepo.cjs.map +1 -1
  7. package/_cjs/Store/Cosmos/query.cjs +9 -2
  8. package/_cjs/Store/Cosmos/query.cjs.map +1 -1
  9. package/_cjs/Store/Cosmos.cjs +49 -23
  10. package/_cjs/Store/Cosmos.cjs.map +1 -1
  11. package/_cjs/Store/Disk.cjs +5 -5
  12. package/_cjs/Store/Disk.cjs.map +1 -1
  13. package/_cjs/Store/Memory.cjs +9 -9
  14. package/_cjs/Store/Memory.cjs.map +1 -1
  15. package/_cjs/Store/codeFilter.cjs.map +1 -1
  16. package/_cjs/Store/service.cjs.map +1 -1
  17. package/_cjs/Store/utils.cjs +3 -3
  18. package/_cjs/Store/utils.cjs.map +1 -1
  19. package/dist/Model/Repository/ext.d.ts +6 -9
  20. package/dist/Model/Repository/ext.d.ts.map +1 -1
  21. package/dist/Model/Repository/ext.js +2 -2
  22. package/dist/Model/Repository/internal/internal.d.ts +4 -9
  23. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  24. package/dist/Model/Repository/internal/internal.js +19 -21
  25. package/dist/Model/Repository/legacy.d.ts +2 -6
  26. package/dist/Model/Repository/legacy.d.ts.map +1 -1
  27. package/dist/Model/Repository/makeRepo.d.ts +4 -9
  28. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  29. package/dist/Model/Repository/makeRepo.js +1 -1
  30. package/dist/Model/Repository/service.d.ts +1 -3
  31. package/dist/Model/Repository/service.d.ts.map +1 -1
  32. package/dist/QueueMaker/sbqueue.d.ts +2 -2
  33. package/dist/Store/Cosmos/query.d.ts +1 -1
  34. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  35. package/dist/Store/Cosmos/query.js +7 -3
  36. package/dist/Store/Cosmos.d.ts.map +1 -1
  37. package/dist/Store/Cosmos.js +43 -23
  38. package/dist/Store/Disk.d.ts +2 -3
  39. package/dist/Store/Disk.d.ts.map +1 -1
  40. package/dist/Store/Disk.js +6 -6
  41. package/dist/Store/Memory.d.ts +4 -9
  42. package/dist/Store/Memory.d.ts.map +1 -1
  43. package/dist/Store/Memory.js +12 -12
  44. package/dist/Store/codeFilter.d.ts +2 -3
  45. package/dist/Store/codeFilter.d.ts.map +1 -1
  46. package/dist/Store/codeFilter.js +1 -1
  47. package/dist/Store/service.d.ts +9 -23
  48. package/dist/Store/service.d.ts.map +1 -1
  49. package/dist/Store/service.js +1 -1
  50. package/dist/Store/utils.d.ts +1 -3
  51. package/dist/Store/utils.d.ts.map +1 -1
  52. package/dist/Store/utils.js +4 -4
  53. package/package.json +1 -1
  54. package/src/Model/Repository/ext.ts +6 -5
  55. package/src/Model/Repository/internal/internal.ts +37 -36
  56. package/src/Model/Repository/legacy.ts +2 -2
  57. package/src/Model/Repository/makeRepo.ts +8 -9
  58. package/src/Model/Repository/service.ts +1 -1
  59. package/src/Store/Cosmos/query.ts +6 -1
  60. package/src/Store/Cosmos.ts +85 -48
  61. package/src/Store/Disk.ts +20 -8
  62. package/src/Store/Memory.ts +25 -16
  63. package/src/Store/codeFilter.ts +2 -1
  64. package/src/Store/service.ts +8 -7
  65. package/src/Store/utils.ts +4 -3
@@ -5,12 +5,13 @@ import type { NonEmptyReadonlyArray } from "effect-app"
5
5
  import { NonEmptyString255 } from "effect-app/Schema"
6
6
  import { get } from "effect-app/utils"
7
7
  import { InfraLogger } from "../logger.js"
8
+ import type { FieldValues } from "../Model/filter/types.js"
8
9
  import { codeFilter } from "./codeFilter.js"
9
10
  import type { FilterArgs, PersistenceModelType, Store, StoreConfig } from "./service.js"
10
11
  import { StoreMaker } from "./service.js"
11
12
  import { makeUpdateETag } from "./utils.js"
12
13
 
13
- export function memFilter<T extends { id: string }, U extends keyof T = never>(f: FilterArgs<T, U>) {
14
+ export function memFilter<T extends FieldValues, U extends keyof T = never>(f: FilterArgs<T, U>) {
14
15
  type M = U extends undefined ? T : Pick<T, U>
15
16
  return ((c: T[]): M[] => {
16
17
  const select = (r: T[]): M[] => (f.select ? r.map(Struct.pick(...f.select)) : r) as any
@@ -76,8 +77,9 @@ function logQuery(f: FilterArgs<any, any>, defaultValues?: any) {
76
77
  }))
77
78
  }
78
79
 
79
- export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }, R = never, E = never>(
80
+ export function makeMemoryStoreInt<IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
80
81
  modelName: string,
82
+ idKey: IdKey,
81
83
  namespace: string,
82
84
  seed?: Effect<Iterable<Encoded>, E, R>,
83
85
  _defaultValues?: Partial<Encoded>
@@ -88,8 +90,8 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
88
90
  const items_ = yield* seed ?? Effect.sync(() => [])
89
91
  const defaultValues = _defaultValues ?? {}
90
92
 
91
- const items = new Map([...items_].map((_) => [_.id, { _etag: undefined, ...defaultValues, ..._ }] as const))
92
- const store = Ref.unsafeMake<ReadonlyMap<Id, PM>>(items)
93
+ const items = new Map([...items_].map((_) => [_[idKey], { _etag: undefined, ...defaultValues, ..._ }] as const))
94
+ const store = Ref.unsafeMake<ReadonlyMap<string, PM>>(items)
93
95
  const sem = Effect.unsafeMakeSemaphore(1)
94
96
  const withPermit = sem.withPermits(1)
95
97
  const values = Effect.map(Ref.get(store), (s) => s.values())
@@ -98,7 +100,7 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
98
100
 
99
101
  const batchSet = (items: NonEmptyReadonlyArray<PM>) =>
100
102
  Effect
101
- .forEach(items, (i) => Effect.flatMap(s.find(i.id), (current) => updateETag(i, current)))
103
+ .forEach(items, (i) => Effect.flatMap(s.find(i[idKey]), (current) => updateETag(i, idKey, current)))
102
104
  .pipe(
103
105
  Effect
104
106
  .tap((items) =>
@@ -107,8 +109,8 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
107
109
  .pipe(
108
110
  Effect
109
111
  .map((m) => {
110
- const mut = m as Map<Id, PM>
111
- items.forEach((e) => mut.set(e.id, e))
112
+ const mut = m as Map<string, PM>
113
+ items.forEach((e) => mut.set(e[idKey], e))
112
114
  return mut
113
115
  }),
114
116
  Effect
@@ -119,7 +121,7 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
119
121
  .map((_) => _),
120
122
  withPermit
121
123
  )
122
- const s: Store<Encoded, Id> = {
124
+ const s: Store<IdKey, Encoded> = {
123
125
  all: all.pipe(Effect.withSpan("Memory.all [effect-app/infra/Store]", {
124
126
  captureStackTrace: false,
125
127
  attributes: {
@@ -153,13 +155,13 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
153
155
  ),
154
156
  set: (e) =>
155
157
  s
156
- .find(e.id)
158
+ .find(e[idKey])
157
159
  .pipe(
158
- Effect.flatMap((current) => updateETag(e, current)),
160
+ Effect.flatMap((current) => updateETag(e, idKey, current)),
159
161
  Effect
160
162
  .tap((e) =>
161
163
  Ref.get(store).pipe(
162
- Effect.map((_) => new Map([..._, [e.id, e]])),
164
+ Effect.map((_) => new Map([..._, [e[idKey], e]])),
163
165
  Effect.flatMap((_) => Ref.set(store, _))
164
166
  )
165
167
  ),
@@ -197,7 +199,7 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
197
199
  Ref
198
200
  .get(store)
199
201
  .pipe(
200
- Effect.map((_) => new Map([..._].filter(([_]) => _ !== e.id))),
202
+ Effect.map((_) => new Map([..._].filter(([_]) => _ !== e[idKey]))),
201
203
  Effect.flatMap((_) => Ref.set(store, _)),
202
204
  withPermit,
203
205
  Effect.withSpan("Memory.remove [effect-app/infra/Store]", {
@@ -211,14 +213,21 @@ export function makeMemoryStoreInt<Id extends string, Encoded extends { id: Id }
211
213
  }
212
214
 
213
215
  export const makeMemoryStore = () => ({
214
- make: <Id extends string, Encoded extends { id: Id }, R = never, E = never>(
216
+ make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R, E>(
215
217
  modelName: string,
218
+ idKey: IdKey,
216
219
  seed?: Effect<Iterable<Encoded>, E, R>,
217
220
  config?: StoreConfig<Encoded>
218
221
  ) =>
219
222
  Effect.gen(function*() {
220
223
  const storesSem = Effect.unsafeMakeSemaphore(1)
221
- const primary = yield* makeMemoryStoreInt<Id, Encoded, R, E>(modelName, "primary", seed, config?.defaultValues)
224
+ const primary = yield* makeMemoryStoreInt<IdKey, Encoded, R, E>(
225
+ modelName,
226
+ idKey,
227
+ "primary",
228
+ seed,
229
+ config?.defaultValues
230
+ )
222
231
  const ctx = yield* Effect.context<R>()
223
232
  const stores = new Map([["primary", primary]])
224
233
  const getStore = !config?.allowNamespace
@@ -234,7 +243,7 @@ export const makeMemoryStore = () => ({
234
243
  return storesSem.withPermits(1)(Effect.suspend(() => {
235
244
  const store = stores.get(namespace)
236
245
  if (store) return Effect.sync(() => store)
237
- return makeMemoryStoreInt(modelName, namespace, seed, config?.defaultValues)
246
+ return makeMemoryStoreInt(modelName, idKey, namespace, seed, config?.defaultValues)
238
247
  .pipe(
239
248
  Effect.orDie,
240
249
  Effect.provide(ctx),
@@ -242,7 +251,7 @@ export const makeMemoryStore = () => ({
242
251
  )
243
252
  }))
244
253
  }))
245
- const s: Store<Encoded, Id> = {
254
+ const s: Store<IdKey, Encoded> = {
246
255
  all: Effect.flatMap(getStore, (_) => _.all),
247
256
  find: (...args) => Effect.flatMap(getStore, (_) => _.find(...args)),
248
257
  filter: (...args) => Effect.flatMap(getStore, (_) => _.filter(...args)),
@@ -3,6 +3,7 @@
3
3
  import { Array, Option } from "effect-app"
4
4
  import { assertUnreachable, get } from "effect-app/utils"
5
5
  import type { FilterR, FilterResult } from "../Model/filter/filterApi.js"
6
+ import type { FieldValues } from "../Model/filter/types.js"
6
7
  import type { Filter } from "./service.js"
7
8
  import { compare, greaterThan, greaterThanExclusive, lowerThan, lowerThanExclusive } from "./utils.js"
8
9
 
@@ -120,6 +121,6 @@ export const codeFilter3_ = <E>(state: readonly FilterResult[], sut: E): boolean
120
121
  return eval(s)
121
122
  }
122
123
 
123
- export function codeFilter<E extends { id: string }, NE extends E>(filter: Filter) {
124
+ export function codeFilter<E extends FieldValues, NE extends E>(filter: Filter) {
124
125
  return (x: E) => codeFilter3_(filter, x) ? Option.some(x as unknown as NE) : Option.none()
125
126
  }
@@ -57,7 +57,7 @@ export interface O<TFieldValues extends FieldValues> {
57
57
  direction: "ASC" | "DESC"
58
58
  }
59
59
 
60
- export interface FilterArgs<Encoded extends { id: string }, U extends keyof Encoded = never> {
60
+ export interface FilterArgs<Encoded extends FieldValues, U extends keyof Encoded = never> {
61
61
  t: Encoded
62
62
  filter?: Filter | undefined
63
63
  select?: NonEmptyReadonlyArray<U> | undefined
@@ -66,18 +66,18 @@ export interface FilterArgs<Encoded extends { id: string }, U extends keyof Enco
66
66
  skip?: number | undefined
67
67
  }
68
68
 
69
- export type FilterFunc<Encoded extends { id: string }> = <U extends keyof Encoded = never>(
69
+ export type FilterFunc<Encoded extends FieldValues> = <U extends keyof Encoded = never>(
70
70
  args: FilterArgs<Encoded, U>
71
71
  ) => Effect<(U extends undefined ? Encoded : Pick<Encoded, U>)[]>
72
72
 
73
73
  export interface Store<
74
- Encoded extends { id: Id },
75
- Id extends string,
74
+ IdKey extends keyof Encoded,
75
+ Encoded extends FieldValues,
76
76
  PM extends PersistenceModelType<Encoded> = PersistenceModelType<Encoded>
77
77
  > {
78
78
  all: Effect<PM[]>
79
79
  filter: FilterFunc<Encoded>
80
- find: (id: Id) => Effect<Option<PM>>
80
+ find: (id: Encoded[IdKey]) => Effect<Option<PM>>
81
81
  set: (e: PM) => Effect<PM, OptimisticConcurrencyException>
82
82
  batchSet: (
83
83
  items: NonEmptyReadonlyArray<PM>
@@ -96,11 +96,12 @@ export interface Store<
96
96
  * @tsplus companion StoreMaker.Ops
97
97
  */
98
98
  export class StoreMaker extends Context.TagId("effect-app/StoreMaker")<StoreMaker, {
99
- make: <Encoded extends { id: Id }, Id extends string, R = never, E = never>(
99
+ make: <IdKey extends keyof Encoded, Encoded extends FieldValues, R = never, E = never>(
100
100
  name: string,
101
+ idKey: IdKey,
101
102
  seed?: Effect<Iterable<Encoded>, E, R>,
102
103
  config?: StoreConfig<Encoded>
103
- ) => Effect<Store<Encoded, Id>, E, R>
104
+ ) => Effect<Store<IdKey, Encoded>, E, R>
104
105
  }>() {
105
106
  }
106
107
 
@@ -13,18 +13,19 @@ export const makeETag = <E extends PersistenceModelType<{}>>(
13
13
  }) as any
14
14
 
15
15
  export const makeUpdateETag =
16
- (type: string) => <E extends PersistenceModelType<{ id: string }>>(e: E, current: Option<E>) =>
16
+ (type: string) =>
17
+ <IdKey extends keyof E, E extends PersistenceModelType<{}>>(e: E, idKey: IdKey, current: Option<E>) =>
17
18
  Effect.gen(function*() {
18
19
  if (e._etag) {
19
20
  yield* Effect.mapError(
20
21
  current,
21
- () => new OptimisticConcurrencyException({ type, id: e.id, current: "", found: e._etag })
22
+ () => new OptimisticConcurrencyException({ type, id: e[idKey] as string, current: "", found: e._etag })
22
23
  )
23
24
  }
24
25
  if (Option.isSome(current) && current.value._etag !== e._etag) {
25
26
  return yield* new OptimisticConcurrencyException({
26
27
  type,
27
- id: current.value.id,
28
+ id: current.value[idKey] as string,
28
29
  current: current.value._etag,
29
30
  found: e._etag
30
31
  })