@effect-app/infra 2.10.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 (70) hide show
  1. package/CHANGELOG.md +12 -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 +245 -0
  5. package/_cjs/Model/Repository/internal/internal.cjs.map +1 -0
  6. package/_cjs/Model/Repository/legacy.cjs +0 -139
  7. package/_cjs/Model/Repository/legacy.cjs.map +1 -1
  8. package/_cjs/Model/Repository/makeRepo.cjs +2 -241
  9. package/_cjs/Model/Repository/makeRepo.cjs.map +1 -1
  10. package/_cjs/Store/Cosmos/query.cjs +9 -2
  11. package/_cjs/Store/Cosmos/query.cjs.map +1 -1
  12. package/_cjs/Store/Cosmos.cjs +49 -23
  13. package/_cjs/Store/Cosmos.cjs.map +1 -1
  14. package/_cjs/Store/Disk.cjs +5 -5
  15. package/_cjs/Store/Disk.cjs.map +1 -1
  16. package/_cjs/Store/Memory.cjs +9 -9
  17. package/_cjs/Store/Memory.cjs.map +1 -1
  18. package/_cjs/Store/codeFilter.cjs.map +1 -1
  19. package/_cjs/Store/service.cjs.map +1 -1
  20. package/_cjs/Store/utils.cjs +3 -3
  21. package/_cjs/Store/utils.cjs.map +1 -1
  22. package/dist/Model/Repository/ext.d.ts +6 -9
  23. package/dist/Model/Repository/ext.d.ts.map +1 -1
  24. package/dist/Model/Repository/ext.js +2 -2
  25. package/dist/Model/Repository/internal/internal.d.ts +61 -0
  26. package/dist/Model/Repository/internal/internal.d.ts.map +1 -0
  27. package/dist/Model/Repository/internal/internal.js +245 -0
  28. package/dist/Model/Repository/legacy.d.ts +4 -192
  29. package/dist/Model/Repository/legacy.d.ts.map +1 -1
  30. package/dist/Model/Repository/legacy.js +2 -123
  31. package/dist/Model/Repository/makeRepo.d.ts +7 -77
  32. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  33. package/dist/Model/Repository/makeRepo.js +3 -247
  34. package/dist/Model/Repository/service.d.ts +1 -3
  35. package/dist/Model/Repository/service.d.ts.map +1 -1
  36. package/dist/Operations.d.ts +3 -3
  37. package/dist/QueueMaker/sbqueue.d.ts +2 -2
  38. package/dist/Store/Cosmos/query.d.ts +1 -1
  39. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  40. package/dist/Store/Cosmos/query.js +7 -3
  41. package/dist/Store/Cosmos.d.ts.map +1 -1
  42. package/dist/Store/Cosmos.js +43 -23
  43. package/dist/Store/Disk.d.ts +2 -3
  44. package/dist/Store/Disk.d.ts.map +1 -1
  45. package/dist/Store/Disk.js +6 -6
  46. package/dist/Store/Memory.d.ts +4 -9
  47. package/dist/Store/Memory.d.ts.map +1 -1
  48. package/dist/Store/Memory.js +12 -12
  49. package/dist/Store/codeFilter.d.ts +2 -3
  50. package/dist/Store/codeFilter.d.ts.map +1 -1
  51. package/dist/Store/codeFilter.js +1 -1
  52. package/dist/Store/service.d.ts +9 -23
  53. package/dist/Store/service.d.ts.map +1 -1
  54. package/dist/Store/service.js +1 -1
  55. package/dist/Store/utils.d.ts +1 -3
  56. package/dist/Store/utils.d.ts.map +1 -1
  57. package/dist/Store/utils.js +4 -4
  58. package/package.json +1 -1
  59. package/src/Model/Repository/ext.ts +6 -5
  60. package/src/Model/Repository/internal/internal.ts +482 -0
  61. package/src/Model/Repository/legacy.ts +4 -538
  62. package/src/Model/Repository/makeRepo.ts +11 -489
  63. package/src/Model/Repository/service.ts +1 -1
  64. package/src/Store/Cosmos/query.ts +6 -1
  65. package/src/Store/Cosmos.ts +85 -48
  66. package/src/Store/Disk.ts +20 -8
  67. package/src/Store/Memory.ts +25 -16
  68. package/src/Store/codeFilter.ts +2 -1
  69. package/src/Store/service.ts +8 -7
  70. package/src/Store/utils.ts +4 -3
@@ -7,495 +7,17 @@
7
7
  // import type { ParserEnv } from "effect-app/Schema/custom/Parser"
8
8
  import type {} from "effect/Equal"
9
9
  import type {} from "effect/Hash"
10
- import type { NonEmptyReadonlyArray } from "effect-app"
11
- import { Array, Chunk, Context, Effect, Equivalence, flow, Option, pipe, Pipeable, PubSub, S, Unify } from "effect-app"
12
- import { toNonEmptyArray } from "effect-app/Array"
13
- import { NotFoundError } from "effect-app/client"
14
- import { flatMapOption } from "effect-app/Effect"
15
- import type { Schema } from "effect-app/Schema"
16
- import { NonNegativeInt } from "effect-app/Schema"
17
- import { setupRequestContextFromCurrent } from "../../api/setupRequest.js"
18
- import type { FilterArgs, PersistenceModelType, StoreConfig } from "../../Store.js"
19
- import { StoreMaker } from "../../Store.js"
20
- import { getContextMap } from "../../Store/ContextMapContainer.js"
10
+ import type { Context, NonEmptyReadonlyArray, S } from "effect-app"
11
+ import { Effect } from "effect-app"
12
+ import type { StoreConfig, StoreMaker } from "../../Store.js"
21
13
  import type { FieldValues } from "../filter/types.js"
22
- import * as Q from "../query.js"
23
14
  import type { ExtendedRepository } from "./ext.js"
24
15
  import { extendRepo } from "./ext.js"
25
- import type { Repository } from "./service.js"
26
-
27
- const dedupe = Array.dedupeWith(Equivalence.string)
28
-
29
- /**
30
- * A base implementation to create a repository.
31
- */
32
- export function makeRepoInternal<
33
- Evt = never
34
- >() {
35
- return <
36
- ItemType extends string,
37
- R,
38
- Encoded extends { id: string },
39
- T,
40
- IdKey extends keyof T
41
- >(
42
- name: ItemType,
43
- schema: S.Schema<T, Encoded, R>,
44
- mapFrom: (pm: Encoded) => Encoded,
45
- mapTo: (e: Encoded, etag: string | undefined) => PersistenceModelType<Encoded>,
46
- idKey: IdKey
47
- ) => {
48
- type PM = PersistenceModelType<Encoded>
49
- function mapToPersistenceModel(
50
- e: Encoded,
51
- getEtag: (id: string) => string | undefined
52
- ): PM {
53
- return mapTo(e, getEtag(e.id))
54
- }
55
-
56
- function mapReverse(
57
- { _etag, ...e }: PM,
58
- setEtag: (id: string, eTag: string | undefined) => void
59
- ): Encoded {
60
- setEtag(e.id, _etag)
61
- return mapFrom(e as unknown as Encoded)
62
- }
63
-
64
- const mkStore = makeStore<Encoded>()(name, schema, mapTo)
65
-
66
- function make<RInitial = never, E = never, RPublish = never, RCtx = never>(
67
- args: [Evt] extends [never] ? {
68
- schemaContext?: Context.Context<RCtx>
69
- makeInitial?: Effect<readonly T[], E, RInitial>
70
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
71
- partitionValue?: (a: Encoded) => string
72
- }
73
- }
74
- : {
75
- schemaContext?: Context.Context<RCtx>
76
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, RPublish>
77
- makeInitial?: Effect<readonly T[], E, RInitial>
78
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
79
- partitionValue?: (a: Encoded) => string
80
- }
81
- }
82
- ) {
83
- return Effect
84
- .gen(function*() {
85
- const rctx: Context<RCtx> = args.schemaContext ?? Context.empty() as any
86
- const provideRctx = Effect.provide(rctx)
87
- const encodeMany = flow(
88
- S.encode(S.Array(schema)),
89
- provideRctx,
90
- Effect.withSpan("encodeMany", { captureStackTrace: false })
91
- )
92
- const decode = flow(S.decode(schema), provideRctx)
93
- const decodeMany = flow(
94
- S.decode(S.Array(schema)),
95
- provideRctx,
96
- Effect.withSpan("decodeMany", { captureStackTrace: false })
97
- )
98
-
99
- const store = yield* mkStore(args.makeInitial, args.config)
100
- const cms = Effect.andThen(getContextMap.pipe(Effect.orDie), (_) => ({
101
- get: (id: string) => _.get(`${name}.${id}`),
102
- set: (id: string, etag: string | undefined) => _.set(`${name}.${id}`, etag)
103
- }))
104
-
105
- const pub = "publishEvents" in args
106
- ? args.publishEvents
107
- : () => Effect.void
108
- const changeFeed = yield* PubSub.unbounded<[T[], "save" | "remove"]>()
109
-
110
- const allE = cms
111
- .pipe(Effect.flatMap((cm) => Effect.map(store.all, (_) => _.map((_) => mapReverse(_, cm.set)))))
112
-
113
- const all = Effect
114
- .flatMap(
115
- allE,
116
- (_) => decodeMany(_).pipe(Effect.orDie)
117
- )
118
- .pipe(Effect.map((_) => _ as T[]))
119
-
120
- const fieldsSchema = schema as unknown as { fields: any }
121
- // assumes the id field never needs a service...
122
- const i = ("fields" in fieldsSchema ? S.Struct(fieldsSchema["fields"]) as unknown as typeof schema : schema)
123
- .pipe((_) => {
124
- let ast = _.ast
125
- if (ast._tag === "Declaration") ast = ast.typeParameters[0]!
126
-
127
- const s = S.make(ast) as unknown as Schema<T, Encoded, R>
128
-
129
- return ast._tag === "Union"
130
- // we need to get the TypeLiteral, incase of class it's behind a transform...
131
- ? S.Union(
132
- ...ast.types.map((_) =>
133
- (S.make(_._tag === "Transformation" ? _.from : _) as unknown as Schema<T, Encoded>)
134
- .pipe(S.pick(idKey as any))
135
- )
136
- )
137
- : s.pipe(S.pick(idKey as any))
138
- })
139
- const encodeId = flow(S.encode(i), provideRctx)
140
- function findEId(id: Encoded["id"]) {
141
- return Effect.flatMap(
142
- store.find(id),
143
- (item) =>
144
- Effect.gen(function*() {
145
- const { set } = yield* cms
146
- return item.pipe(Option.map((_) => mapReverse(_, set)))
147
- })
148
- )
149
- }
150
- function findE(id: T[IdKey]) {
151
- return pipe(
152
- encodeId({ [idKey]: id } as any),
153
- Effect.orDie,
154
- // we will have idKey because the transform is undone again by the encode schema mumbo jumbo above
155
- // TODO: make reliable. (Security: isin: PrimaryKey(ISIN), idKey: "isin", does end up with "id")
156
- Effect.map((_) => (_ as any)[idKey] ?? (_ as any).id),
157
- Effect.flatMap(findEId)
158
- )
159
- }
160
-
161
- function find(id: T[IdKey]) {
162
- return Effect.flatMapOption(findE(id), (_) => Effect.orDie(decode(_)))
163
- }
164
-
165
- const saveAllE = (a: Iterable<Encoded>) =>
166
- Effect
167
- .flatMapOption(
168
- Effect
169
- .sync(() => toNonEmptyArray([...a])),
170
- (a) =>
171
- Effect.gen(function*() {
172
- const { get, set } = yield* cms
173
- const items = a.map((_) => mapToPersistenceModel(_, get))
174
- const ret = yield* store.batchSet(items)
175
- ret.forEach((_) => set(_.id, _._etag))
176
- })
177
- )
178
- .pipe(Effect.asVoid)
179
-
180
- const saveAll = (a: Iterable<T>) =>
181
- encodeMany(Array.fromIterable(a))
182
- .pipe(
183
- Effect.orDie,
184
- Effect.andThen(saveAllE)
185
- )
186
-
187
- const saveAndPublish = (items: Iterable<T>, events: Iterable<Evt> = []) => {
188
- return Effect
189
- .suspend(() => {
190
- const it = Chunk.fromIterable(items)
191
- return saveAll(it)
192
- .pipe(
193
- Effect.andThen(Effect.sync(() => toNonEmptyArray([...events]))),
194
- // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
195
- (_) => Effect.flatMapOption(_, pub),
196
- Effect.andThen(changeFeed.publish([Chunk.toArray(it), "save"])),
197
- Effect.asVoid
198
- )
199
- })
200
- .pipe(Effect.withSpan("saveAndPublish", { captureStackTrace: false }))
201
- }
202
-
203
- function removeAndPublish(a: Iterable<T>, events: Iterable<Evt> = []) {
204
- return Effect.gen(function*() {
205
- const { get, set } = yield* cms
206
- const it = [...a]
207
- const items = yield* encodeMany(it).pipe(Effect.orDie)
208
- // TODO: we should have a batchRemove on store so the adapter can actually batch...
209
- for (const e of items) {
210
- yield* store.remove(mapToPersistenceModel(e, get))
211
- set(e.id, undefined)
212
- }
213
- yield* Effect
214
- .sync(() => toNonEmptyArray([...events]))
215
- // TODO: for full consistency the events should be stored within the same database transaction, and then picked up.
216
- .pipe((_) => Effect.flatMapOption(_, pub))
217
-
218
- yield* changeFeed.publish([it, "remove"])
219
- })
220
- }
221
-
222
- const parseMany = (items: readonly PM[]) =>
223
- Effect
224
- .flatMap(cms, (cm) =>
225
- decodeMany(items.map((_) => mapReverse(_, cm.set)))
226
- .pipe(Effect.orDie, Effect.withSpan("parseMany", { captureStackTrace: false })))
227
- const parseMany2 = <A, R>(
228
- items: readonly PM[],
229
- schema: S.Schema<A, Encoded, R>
230
- ) =>
231
- Effect
232
- .flatMap(cms, (cm) =>
233
- S
234
- .decode(S.Array(schema))(
235
- items.map((_) => mapReverse(_, cm.set))
236
- )
237
- .pipe(Effect.orDie, Effect.withSpan("parseMany2", { captureStackTrace: false })))
238
- const filter = <U extends keyof Encoded = keyof Encoded>(args: FilterArgs<Encoded, U>) =>
239
- store
240
- .filter(
241
- // always enforce id and _etag because they are system fields, required for etag tracking etc
242
- {
243
- ...args,
244
- select: args.select
245
- ? dedupe([...args.select, "id", "_etag" as any])
246
- : undefined
247
- } as typeof args
248
- )
249
- .pipe(
250
- Effect.tap((items) =>
251
- Effect.map(cms, ({ set }) => items.forEach((_) => set((_ as Encoded).id, (_ as PM)._etag)))
252
- )
253
- )
254
-
255
- // TODO: For raw we should use S.from, and drop the R...
256
- const query: {
257
- <A, R, From extends FieldValues>(
258
- q: Q.QueryProjection<Encoded extends From ? From : never, A, R>
259
- ): Effect.Effect<readonly A[], S.ParseResult.ParseError, R>
260
- <A, R, EncodedRefined extends Encoded = Encoded>(
261
- q: Q.QAll<NoInfer<Encoded>, NoInfer<EncodedRefined>, A, R>
262
- ): Effect.Effect<readonly A[], never, R>
263
- } = (<A, R, EncodedRefined extends Encoded = Encoded>(q: Q.QAll<Encoded, EncodedRefined, A, R>) => {
264
- const a = Q.toFilter(q)
265
- const eff = a.mode === "project"
266
- ? filter(a)
267
- // TODO: mapFrom but need to support per field and dependencies
268
- .pipe(
269
- Effect.andThen(flow(S.decode(S.Array(a.schema ?? schema)), provideRctx))
270
- )
271
- : a.mode === "collect"
272
- ? filter(a)
273
- // TODO: mapFrom but need to support per field and dependencies
274
- .pipe(
275
- Effect.flatMap(flow(
276
- S.decode(S.Array(a.schema)),
277
- Effect.map(Array.getSomes),
278
- provideRctx
279
- ))
280
- )
281
- : Effect.flatMap(
282
- filter(a),
283
- (_) =>
284
- Unify.unify(
285
- a.schema
286
- // TODO: partial may not match?
287
- ? parseMany2(_ as any, a.schema as any)
288
- : parseMany(_ as any)
289
- )
290
- )
291
- return pipe(
292
- a.ttype === "one"
293
- ? Effect.andThen(
294
- eff,
295
- flow(
296
- Array.head,
297
- Effect.mapError(() => new NotFoundError({ id: "query", /* TODO */ type: name }))
298
- )
299
- )
300
- : a.ttype === "count"
301
- ? Effect
302
- .andThen(eff, (_) => NonNegativeInt(_.length))
303
- .pipe(Effect.catchTag("ParseError", (e) => Effect.die(e)))
304
- : eff,
305
- Effect.withSpan("Repository.query [effect-app/infra]", {
306
- captureStackTrace: false,
307
- attributes: {
308
- "repository.model_name": name,
309
- query: { ...a, schema: a.schema ? "__SCHEMA__" : a.schema, filter: a.filter }
310
- }
311
- })
312
- )
313
- }) as any
314
-
315
- const r: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish> = {
316
- changeFeed,
317
- itemType: name,
318
- idKey,
319
- find,
320
- all,
321
- saveAndPublish,
322
- removeAndPublish,
323
- query(q: any) {
324
- // eslint-disable-next-line prefer-rest-params
325
- return query(typeof q === "function" ? Pipeable.pipeArguments(Q.make(), arguments) : q) as any
326
- },
327
- /**
328
- * @internal
329
- */
330
- mapped: <A, R>(schema: S.Schema<A, any, R>) => {
331
- const dec = S.decode(schema)
332
- const encMany = S.encode(S.Array(schema))
333
- const decMany = S.decode(S.Array(schema))
334
- return {
335
- all: allE.pipe(
336
- Effect.flatMap(decMany),
337
- Effect.map((_) => _ as any[])
338
- ),
339
- find: (id: T[IdKey]) => flatMapOption(findE(id), dec),
340
- // query: (q: any) => {
341
- // const a = Q.toFilter(q)
342
-
343
- // return filter(a)
344
- // .pipe(
345
- // Effect.flatMap(decMany),
346
- // Effect.map((_) => _ as any[]),
347
- // Effect.withSpan("Repository.mapped.query [effect-app/infra]", {
348
- // captureStackTrace: false,
349
- // attributes: {
350
- // "repository.model_name": name,
351
- // query: { ...a, schema: a.schema ? "__SCHEMA__" : a.schema, filter: a.filter.build() }
352
- // }
353
- // })
354
- // )
355
- // },
356
- save: (...xes: any[]) =>
357
- Effect.flatMap(encMany(xes), (_) => saveAllE(_)).pipe(
358
- Effect.withSpan("mapped.save", { captureStackTrace: false })
359
- )
360
- }
361
- }
362
- }
363
- return r
364
- })
365
- .pipe(Effect
366
- // .withSpan("Repository.make [effect-app/infra]", { attributes: { "repository.model_name": name } })
367
- .withLogSpan("Repository.make: " + name))
368
- }
369
-
370
- return {
371
- make,
372
- Q: Q.make<Encoded>()
373
- }
374
- }
375
- }
376
-
377
- const pluralize = (s: string) =>
378
- s.endsWith("s")
379
- ? s + "es"
380
- : s.endsWith("y")
381
- ? s.substring(0, s.length - 1) + "ies"
382
- : s + "s"
383
-
384
- export function makeStore<
385
- Encoded extends { id: string }
386
- >() {
387
- return <
388
- ItemType extends string,
389
- R,
390
- E extends { id: string },
391
- T
392
- >(
393
- name: ItemType,
394
- schema: S.Schema<T, E, R>,
395
- mapTo: (e: E, etag: string | undefined) => Encoded
396
- ) => {
397
- function encodeToEncoded() {
398
- const getEtag = () => undefined
399
- return (t: T) =>
400
- S.encode(schema)(t).pipe(
401
- Effect.orDie,
402
- Effect.map((_) => mapToPersistenceModel(_, getEtag))
403
- )
404
- }
405
-
406
- function mapToPersistenceModel(
407
- e: E,
408
- getEtag: (id: string) => string | undefined
409
- ): Encoded {
410
- return mapTo(e, getEtag(e.id))
411
- }
412
-
413
- function makeStore<RInitial = never, EInitial = never>(
414
- makeInitial?: Effect<readonly T[], EInitial, RInitial>,
415
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
416
- partitionValue?: (a: Encoded) => string
417
- }
418
- ) {
419
- return Effect.gen(function*() {
420
- const { make } = yield* StoreMaker
421
-
422
- const store = yield* make<Encoded, string, RInitial | R, EInitial>(
423
- pluralize(name),
424
- makeInitial
425
- ? makeInitial
426
- .pipe(
427
- Effect.flatMap(Effect.forEach(encodeToEncoded())),
428
- setupRequestContextFromCurrent("Repository.makeInitial [effect-app/infra]", {
429
- attributes: { "repository.model_name": name }
430
- })
431
- )
432
- : undefined,
433
- {
434
- ...config,
435
- partitionValue: config?.partitionValue
436
- ?? ((_) => "primary") /*(isIntegrationEvent(r) ? r.companyId : r.id*/
437
- }
438
- )
439
-
440
- return store
441
- })
442
- }
443
-
444
- return makeStore
445
- }
446
- }
447
-
448
- export interface Repos<
449
- T,
450
- Encoded extends { id: string },
451
- RSchema,
452
- Evt,
453
- ItemType extends string,
454
- IdKey extends keyof T,
455
- RPublish
456
- > {
457
- make<RInitial = never, E = never, R2 = never>(
458
- args: [Evt] extends [never] ? {
459
- makeInitial?: Effect<readonly T[], E, RInitial>
460
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
461
- partitionValue?: (a: Encoded) => string
462
- }
463
- }
464
- : {
465
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, R2>
466
- makeInitial?: Effect<readonly T[], E, RInitial>
467
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
468
- partitionValue?: (a: Encoded) => string
469
- }
470
- }
471
- ): Effect<Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>, E, StoreMaker | RInitial | R2>
472
- makeWith<Out, RInitial = never, E = never, R2 = never>(
473
- args: [Evt] extends [never] ? {
474
- makeInitial?: Effect<readonly T[], E, RInitial>
475
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
476
- partitionValue?: (a: Encoded) => string
477
- }
478
- }
479
- : {
480
- publishEvents: (evt: NonEmptyReadonlyArray<Evt>) => Effect<void, never, R2>
481
- makeInitial?: Effect<readonly T[], E, RInitial>
482
- config?: Omit<StoreConfig<Encoded>, "partitionValue"> & {
483
- partitionValue?: (a: Encoded) => string
484
- }
485
- },
486
- f: (r: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>) => Out
487
- ): Effect<Out, E, StoreMaker | RInitial | R2>
488
- readonly Q: ReturnType<typeof Q.make<Encoded>>
489
- readonly type: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>
490
- }
491
-
492
- export type GetRepoType<T> = T extends { type: infer R } ? R : never
16
+ import { makeRepoInternal } from "./internal/internal.js"
493
17
 
494
18
  export interface RepositoryOptions<
495
- IdKey extends keyof T,
496
- Encoded extends {
497
- id: string
498
- },
19
+ IdKey extends keyof T & keyof Encoded,
20
+ Encoded,
499
21
  T,
500
22
  Evt = never,
501
23
  RPublish = never,
@@ -543,9 +65,9 @@ export const makeRepo: {
543
65
  <
544
66
  ItemType extends string,
545
67
  RSchema,
546
- Encoded extends { id: string },
68
+ Encoded extends FieldValues,
547
69
  T,
548
- IdKey extends keyof T,
70
+ IdKey extends keyof T & keyof Encoded,
549
71
  E = never,
550
72
  Evt = never,
551
73
  RInitial = never,
@@ -563,7 +85,7 @@ export const makeRepo: {
563
85
  <
564
86
  ItemType extends string,
565
87
  RSchema,
566
- Encoded extends { id: string },
88
+ Encoded extends FieldValues,
567
89
  T extends { id: unknown },
568
90
  E = never,
569
91
  Evt = never,
@@ -582,9 +104,9 @@ export const makeRepo: {
582
104
  } = <
583
105
  ItemType extends string,
584
106
  R,
585
- Encoded extends { id: string },
107
+ Encoded extends FieldValues,
586
108
  T,
587
- IdKey extends keyof T,
109
+ IdKey extends keyof T & keyof Encoded,
588
110
  E = never,
589
111
  RInitial = never,
590
112
  RPublish = never,
@@ -11,7 +11,7 @@ import type { Mapped } from "./legacy.js"
11
11
  */
12
12
  export interface Repository<
13
13
  T,
14
- Encoded extends { id: string },
14
+ Encoded extends FieldValues,
15
15
  Evt,
16
16
  ItemType extends string,
17
17
  IdKey extends keyof T,
@@ -32,6 +32,7 @@ const arrayContains = (v: any[]) => v.map((_) => JSON.stringify(_)).join(", ")
32
32
  const vAsArr = (v: string) => v as unknown as any[]
33
33
 
34
34
  export function buildWhereCosmosQuery3(
35
+ idKey: PropertyKey,
35
36
  filter: readonly FilterResult[],
36
37
  name: string,
37
38
  importedMarkerId: string,
@@ -42,10 +43,14 @@ export function buildWhereCosmosQuery3(
42
43
  limit?: number
43
44
  ) {
44
45
  const statement = (x: FilterR, i: number) => {
46
+ if (x.path === idKey) {
47
+ x = { ...x, path: "id" }
48
+ }
45
49
  let k = x.path.includes(".-1.")
46
50
  ? `${x.path.split(".-1.")[0]}.${x.path.split(".-1.")[1]!}`
47
51
  : `f.${x.path}`
48
52
 
53
+ // would have to map id, but shouldnt allow id in defaultValues anyway..
49
54
  k = x.path in defaultValues ? `(${k} ?? ${JSON.stringify(defaultValues[x.path])})` : k
50
55
 
51
56
  const v = "@v" + i
@@ -180,7 +185,7 @@ export function buildWhereCosmosQuery3(
180
185
  query: `
181
186
  SELECT ${
182
187
  select
183
- ? `${select.map((_) => `f.${_}`).join(", ")}`
188
+ ? `${select.map((_) => (_ as any) === idKey ? "id" : _).map((_) => `f.${_}`).join(", ")}`
184
189
  : "f"
185
190
  }
186
191
  FROM ${name} f