@effect-app/infra 4.0.0-beta.120 → 4.0.0-beta.122

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 (74) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/CUPS.d.ts.map +1 -1
  3. package/dist/CUPS.js +8 -10
  4. package/dist/Model/Repository/ext.d.ts +17 -5
  5. package/dist/Model/Repository/ext.d.ts.map +1 -1
  6. package/dist/Model/Repository/ext.js +25 -2
  7. package/dist/Model/Repository/internal/internal.d.ts +1 -1
  8. package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
  9. package/dist/Model/Repository/internal/internal.js +9 -8
  10. package/dist/Model/Repository/makeRepo.d.ts +3 -3
  11. package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
  12. package/dist/Model/Repository/service.d.ts +21 -21
  13. package/dist/Model/Repository/service.d.ts.map +1 -1
  14. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  15. package/dist/Model/query/new-kid-interpreter.js +3 -3
  16. package/dist/Operations.d.ts +3 -3
  17. package/dist/Operations.d.ts.map +1 -1
  18. package/dist/Operations.js +54 -57
  19. package/dist/OperationsRepo.d.ts +2 -2
  20. package/dist/QueueMaker/SQLQueue.d.ts +2 -3
  21. package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
  22. package/dist/QueueMaker/SQLQueue.js +104 -115
  23. package/dist/QueueMaker/memQueue.d.ts +2 -2
  24. package/dist/QueueMaker/memQueue.d.ts.map +1 -1
  25. package/dist/QueueMaker/memQueue.js +51 -62
  26. package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
  27. package/dist/QueueMaker/sbqueue.js +34 -50
  28. package/dist/Store/Cosmos.d.ts.map +1 -1
  29. package/dist/Store/Cosmos.js +304 -306
  30. package/dist/Store/Disk.d.ts +1 -1
  31. package/dist/Store/Disk.d.ts.map +1 -1
  32. package/dist/Store/Disk.js +2 -2
  33. package/dist/Store/Memory.d.ts +1 -1
  34. package/dist/Store/Memory.d.ts.map +1 -1
  35. package/dist/Store/Memory.js +2 -2
  36. package/dist/Store/SQL/Pg.d.ts.map +1 -1
  37. package/dist/Store/SQL/Pg.js +147 -149
  38. package/dist/Store/SQL.d.ts.map +1 -1
  39. package/dist/Store/SQL.js +6 -6
  40. package/dist/Store/utils.d.ts.map +1 -1
  41. package/dist/Store/utils.js +3 -4
  42. package/dist/adapters/ServiceBus.d.ts.map +1 -1
  43. package/dist/adapters/ServiceBus.js +7 -9
  44. package/dist/api/internal/auth.d.ts.map +1 -1
  45. package/dist/api/internal/auth.js +1 -1
  46. package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
  47. package/dist/api/routing/middleware/middleware.js +2 -2
  48. package/dist/errorReporter.d.ts +3 -3
  49. package/dist/errorReporter.d.ts.map +1 -1
  50. package/dist/errorReporter.js +16 -23
  51. package/package.json +14 -14
  52. package/src/CUPS.ts +7 -9
  53. package/src/Model/Repository/ext.ts +71 -6
  54. package/src/Model/Repository/internal/internal.ts +13 -25
  55. package/src/Model/Repository/makeRepo.ts +4 -4
  56. package/src/Model/Repository/service.ts +22 -21
  57. package/src/Model/query/new-kid-interpreter.ts +2 -2
  58. package/src/Operations.ts +76 -111
  59. package/src/QueueMaker/SQLQueue.ts +119 -150
  60. package/src/QueueMaker/memQueue.ts +81 -102
  61. package/src/QueueMaker/sbqueue.ts +51 -81
  62. package/src/Store/Cosmos.ts +481 -484
  63. package/src/Store/Disk.ts +52 -53
  64. package/src/Store/Memory.ts +49 -50
  65. package/src/Store/SQL/Pg.ts +247 -250
  66. package/src/Store/SQL.ts +420 -426
  67. package/src/Store/utils.ts +23 -22
  68. package/src/adapters/ServiceBus.ts +106 -110
  69. package/src/api/internal/auth.ts +8 -6
  70. package/src/api/routing/middleware/middleware.ts +10 -11
  71. package/src/errorReporter.ts +58 -72
  72. package/test/dist/repository-ext.test.d.ts.map +1 -0
  73. package/test/query.test.ts +27 -0
  74. package/test/repository-ext.test.ts +58 -0
@@ -9,6 +9,24 @@ import type { Query, QueryEnd, QueryWhere } from "../query.js"
9
9
  import * as Q from "../query.js"
10
10
  import type { Repository } from "./service.js"
11
11
 
12
+ interface BatchOptions {
13
+ readonly batch?: true | number
14
+ }
15
+
16
+ type NonEmptyReadonlyArray<A> = readonly [A, ...A[]]
17
+
18
+ const asReadonlyArray = <T>(itemOrItems: T | NonEmptyReadonlyArray<T>): ReadonlyArray<T> =>
19
+ globalThis.Array.isArray(itemOrItems)
20
+ ? itemOrItems as ReadonlyArray<T>
21
+ : [itemOrItems as T]
22
+
23
+ const getBatchSize = (batch?: true | number) =>
24
+ batch === true
25
+ ? 100
26
+ : typeof batch === "number" && Number.isFinite(batch) && batch > 0
27
+ ? Math.floor(batch)
28
+ : undefined
29
+
12
30
  export const extendRepo = <
13
31
  T,
14
32
  Encoded extends FieldValues,
@@ -16,9 +34,10 @@ export const extendRepo = <
16
34
  ItemType extends string,
17
35
  IdKey extends keyof T & keyof Encoded,
18
36
  RSchema,
19
- RPublish
37
+ RPublish,
38
+ RProvided = never
20
39
  >(
21
- repo: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>
40
+ repo: Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided>
22
41
  ) => {
23
42
  const get = (id: T[IdKey]) =>
24
43
  repo.find(id).pipe(
@@ -244,8 +263,53 @@ export const extendRepo = <
244
263
  request: (id: T[IdKey]) => Effect.request(_request({ id }), requestResolver),
245
264
  get,
246
265
  log: (evt: Evt) => AnyPureDSL.log(evt),
247
- save: (...items: NonEmptyArray<T>) => repo.saveAndPublish(items),
266
+ save: ((itemOrItems: T | NonEmptyReadonlyArray<T>, options?: BatchOptions) => {
267
+ const items = asReadonlyArray(itemOrItems)
268
+ const batchSize = getBatchSize(options?.batch)
269
+ if (batchSize === undefined) {
270
+ return repo.saveAndPublish(items)
271
+ }
272
+ return Effect.forEach(
273
+ Array.chunksOf(items, batchSize),
274
+ (batch) => repo.saveAndPublish(batch),
275
+ { discard: true }
276
+ )
277
+ }) as {
278
+ (item: T, options?: BatchOptions): Effect.Effect<
279
+ void,
280
+ InvalidStateError | OptimisticConcurrencyException,
281
+ RSchema | RPublish
282
+ >
283
+ (items: NonEmptyReadonlyArray<T>, options?: BatchOptions): Effect.Effect<
284
+ void,
285
+ InvalidStateError | OptimisticConcurrencyException,
286
+ RSchema | RPublish
287
+ >
288
+ /**
289
+ * Enables chunked writes for large batches.
290
+ * Note: batching breaks transactional properties because chunks are saved independently.
291
+ */
292
+ },
248
293
  saveWithEvents: (events: Iterable<Evt>) => (...items: NonEmptyArray<T>) => repo.saveAndPublish(items, events),
294
+ remove: ((itemOrItems: T | NonEmptyReadonlyArray<T>, options?: BatchOptions) => {
295
+ const items = asReadonlyArray(itemOrItems)
296
+ const batchSize = getBatchSize(options?.batch)
297
+ if (batchSize === undefined) {
298
+ return repo.removeAndPublish(items)
299
+ }
300
+ return Effect.forEach(
301
+ Array.chunksOf(items, batchSize),
302
+ (batch) => repo.removeAndPublish(batch),
303
+ { discard: true }
304
+ )
305
+ }) as {
306
+ (item: T, options?: BatchOptions): Effect.Effect<void, never, RSchema | RPublish>
307
+ (items: NonEmptyReadonlyArray<T>, options?: BatchOptions): Effect.Effect<void, never, RSchema | RPublish>
308
+ /**
309
+ * Enables chunked deletes for large batches.
310
+ * Note: batching breaks transactional properties because chunks are removed independently.
311
+ */
312
+ },
249
313
  queryAndSavePure,
250
314
  saveManyWithPure,
251
315
  byIdAndSaveWithPure,
@@ -268,7 +332,7 @@ export const extendRepo = <
268
332
  return {
269
333
  ...repo,
270
334
  ...exts
271
- } as Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish> & typeof exts
335
+ } as Repository<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided> & typeof exts
272
336
  }
273
337
 
274
338
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
@@ -279,5 +343,6 @@ export interface ExtendedRepository<
279
343
  ItemType extends string,
280
344
  IdKey extends keyof T & keyof Encoded,
281
345
  RSchema,
282
- RPublish
283
- > extends ReturnType<typeof extendRepo<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish>> {}
346
+ RPublish,
347
+ RProvided = never
348
+ > extends ReturnType<typeof extendRepo<T, Encoded, Evt, ItemType, IdKey, RSchema, RPublish, RProvided>> {}
@@ -248,28 +248,16 @@ export function makeRepoInternal<
248
248
  }
249
249
  )
250
250
 
251
- const parseMany = (items: readonly PM[]) =>
252
- Effect
253
- .flatMap(cms, (cm) =>
254
- decodeMany(items.map((_) => mapReverse(_, cm.set)))
255
- .pipe(
256
- Effect.orDie,
257
- Effect.withSpan("parseMany", { attributes: { itemType: name } }, { captureStackTrace: false })
258
- ))
259
- const parseMany2 = <A, R>(
260
- items: readonly PM[],
261
- schema: S.Codec<A, Encoded, R>
262
- ) =>
263
- Effect
264
- .flatMap(cms, (cm) =>
265
- S
266
- .decodeEffect(S.Array(schema))(
267
- items.map((_) => mapReverse(_, cm.set))
268
- )
269
- .pipe(
270
- Effect.orDie,
271
- Effect.withSpan("parseMany2", { attributes: { itemType: name } }, { captureStackTrace: false })
272
- ))
251
+ const parseMany = Effect.fn("parseMany", { attributes: { itemType: name } })(function*(items: readonly PM[]) {
252
+ const cm = yield* cms
253
+ return yield* decodeMany(items.map((_) => mapReverse(_, cm.set))).pipe(Effect.orDie)
254
+ })
255
+ const parseMany2 = Effect.fn("parseMany2", { attributes: { itemType: name } })(
256
+ function*<A, R>(items: readonly PM[], schema: S.Codec<A, Encoded, R>) {
257
+ const cm = yield* cms
258
+ return yield* S.decodeEffect(S.Array(schema))(items.map((_) => mapReverse(_, cm.set))).pipe(Effect.orDie)
259
+ }
260
+ )
273
261
  const filter = <U extends keyof Encoded = keyof Encoded>(args: FilterArgs<Encoded, U>) =>
274
262
  store
275
263
  .filter(
@@ -291,10 +279,10 @@ export function makeRepoInternal<
291
279
  const query: {
292
280
  <A, R, From extends FieldValues>(
293
281
  q: Q.QueryProjection<Encoded extends From ? From : never, A, R>
294
- ): Effect.Effect<readonly A[], S.SchemaError, R>
282
+ ): Effect.Effect<readonly A[], S.SchemaError, Exclude<R, RCtx>>
295
283
  <A, R, EncodedRefined extends Encoded = Encoded>(
296
284
  q: Q.QAll<NoInfer<Encoded>, NoInfer<EncodedRefined>, A, R>
297
- ): Effect.Effect<readonly A[], never, R>
285
+ ): Effect.Effect<readonly A[], never, Exclude<R, RCtx>>
298
286
  } = (<A, R, EncodedRefined extends Encoded = Encoded>(q: Q.QAll<Encoded, EncodedRefined, A, R>) => {
299
287
  const a = Q.toFilter(q)
300
288
  const eff = a.mode === "project"
@@ -463,7 +451,7 @@ export function makeRepoInternal<
463
451
  }
464
452
  }
465
453
  }
466
- return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish>
454
+ return r as Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<R, RCtx>, RPublish, RCtx>
467
455
  })
468
456
  .pipe(Effect
469
457
  // .withSpan("Repository.make [effect-app/infra]", { attributes: { "repository.model_name": name } })
@@ -56,8 +56,8 @@ export interface RepositoryOptions<
56
56
  schemaContext?: Context.Context<RCtx>
57
57
 
58
58
  overrides?: (
59
- repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>
60
- ) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>
59
+ repo: Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
60
+ ) => Repository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>
61
61
  }
62
62
 
63
63
  /**
@@ -84,7 +84,7 @@ export const makeRepo: {
84
84
  schema: S.Codec<T, Encoded, RSchema>,
85
85
  options: RepositoryOptions<IdKey, Encoded, T, ItemType, Evt, RPublish, E, RInitial, RCtx, RSchema>
86
86
  ): Effect.Effect<
87
- ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish>,
87
+ ExtendedRepository<T, Encoded, Evt, ItemType, IdKey, Exclude<RSchema, RCtx>, RPublish, RCtx>,
88
88
  E,
89
89
  RInitial | StoreMaker | RepositoryRegistry
90
90
  >
@@ -103,7 +103,7 @@ export const makeRepo: {
103
103
  schema: S.Codec<T, Encoded, RSchema>,
104
104
  options: Omit<RepositoryOptions<"id", Encoded, T, ItemType, Evt, RPublish, E, RInitial, RCtx, RSchema>, "idKey">
105
105
  ): Effect.Effect<
106
- ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish>,
106
+ ExtendedRepository<T, Encoded, Evt, ItemType, "id", Exclude<RSchema, RCtx>, RPublish, RCtx>,
107
107
  E,
108
108
  RInitial | StoreMaker | RepositoryRegistry
109
109
  >
@@ -14,7 +14,8 @@ export interface Repository<
14
14
  ItemType extends string,
15
15
  IdKey extends keyof T,
16
16
  RSchema,
17
- RPublish
17
+ RPublish,
18
+ RProvided = never
18
19
  > {
19
20
  readonly itemType: ItemType
20
21
  readonly idKey: IdKey
@@ -59,7 +60,7 @@ export interface Repository<
59
60
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
60
61
  | (TType extends "many" ? never : NotFoundError<ItemType>)
61
62
  | (TType extends "count" ? never : S.SchemaError),
62
- R | RSchema
63
+ Exclude<R, RProvided> | RSchema
63
64
  >
64
65
  <
65
66
  A,
@@ -79,7 +80,7 @@ export interface Repository<
79
80
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
80
81
  | (TType extends "many" ? never : NotFoundError<ItemType>)
81
82
  | (TType extends "count" ? never : S.SchemaError),
82
- R | RSchema
83
+ Exclude<R, RProvided> | RSchema
83
84
  >
84
85
  <
85
86
  A,
@@ -101,7 +102,7 @@ export interface Repository<
101
102
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
102
103
  | (TType extends "many" ? never : NotFoundError<ItemType>)
103
104
  | (TType extends "count" ? never : S.SchemaError),
104
- R | RSchema
105
+ Exclude<R, RProvided> | RSchema
105
106
  >
106
107
  <
107
108
  A,
@@ -125,7 +126,7 @@ export interface Repository<
125
126
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
126
127
  | (TType extends "many" ? never : NotFoundError<ItemType>)
127
128
  | (TType extends "count" ? never : S.SchemaError),
128
- R | RSchema
129
+ Exclude<R, RProvided> | RSchema
129
130
  >
130
131
  <
131
132
  A,
@@ -151,7 +152,7 @@ export interface Repository<
151
152
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
152
153
  | (TType extends "many" ? never : NotFoundError<ItemType>)
153
154
  | (TType extends "count" ? never : S.SchemaError),
154
- R | RSchema
155
+ Exclude<R, RProvided> | RSchema
155
156
  >
156
157
  <
157
158
  A,
@@ -177,7 +178,7 @@ export interface Repository<
177
178
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
178
179
  | (TType extends "many" ? never : NotFoundError<ItemType>)
179
180
  | (TType extends "count" ? never : S.SchemaError),
180
- R | RSchema
181
+ Exclude<R, RProvided> | RSchema
181
182
  >
182
183
  <
183
184
  A,
@@ -205,7 +206,7 @@ export interface Repository<
205
206
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
206
207
  | (TType extends "many" ? never : NotFoundError<ItemType>)
207
208
  | (TType extends "count" ? never : S.SchemaError),
208
- R | RSchema
209
+ Exclude<R, RProvided> | RSchema
209
210
  >
210
211
  <
211
212
  A,
@@ -235,7 +236,7 @@ export interface Repository<
235
236
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
236
237
  | (TType extends "many" ? never : NotFoundError<ItemType>)
237
238
  | (TType extends "count" ? never : S.SchemaError),
238
- R | RSchema
239
+ Exclude<R, RProvided> | RSchema
239
240
  >
240
241
  <
241
242
  A,
@@ -267,7 +268,7 @@ export interface Repository<
267
268
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
268
269
  | (TType extends "many" ? never : NotFoundError<ItemType>)
269
270
  | (TType extends "count" ? never : S.SchemaError),
270
- R | RSchema
271
+ Exclude<R, RProvided> | RSchema
271
272
  >
272
273
  <
273
274
  A,
@@ -301,7 +302,7 @@ export interface Repository<
301
302
  TType extends "many" ? readonly A[] : TType extends "count" ? NonNegativeInt : A,
302
303
  | (TType extends "many" ? never : NotFoundError<ItemType>)
303
304
  | (TType extends "count" ? never : S.SchemaError),
304
- R | RSchema
305
+ Exclude<R, RProvided> | RSchema
305
306
  >
306
307
 
307
308
  // ending with generic query
@@ -315,7 +316,7 @@ export interface Repository<
315
316
  ): Effect.Effect<
316
317
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
317
318
  TType extends "many" ? never : NotFoundError<ItemType>,
318
- R | RSchema
319
+ Exclude<R, RProvided> | RSchema
319
320
  >
320
321
  <
321
322
  R = never,
@@ -331,7 +332,7 @@ export interface Repository<
331
332
  ): Effect.Effect<
332
333
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
333
334
  TType extends "many" ? never : NotFoundError<ItemType>,
334
- R | RSchema
335
+ Exclude<R, RProvided> | RSchema
335
336
  >
336
337
  <
337
338
  R = never,
@@ -351,7 +352,7 @@ export interface Repository<
351
352
  ): Effect.Effect<
352
353
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
353
354
  TType extends "many" ? never : NotFoundError<ItemType>,
354
- R | RSchema
355
+ Exclude<R, RProvided> | RSchema
355
356
  >
356
357
  <
357
358
  R = never,
@@ -371,7 +372,7 @@ export interface Repository<
371
372
  ): Effect.Effect<
372
373
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
373
374
  TType extends "many" ? never : NotFoundError<ItemType>,
374
- R | RSchema
375
+ Exclude<R, RProvided> | RSchema
375
376
  >
376
377
  <
377
378
  R = never,
@@ -393,7 +394,7 @@ export interface Repository<
393
394
  ): Effect.Effect<
394
395
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
395
396
  TType extends "many" ? never : NotFoundError<ItemType>,
396
- R | RSchema
397
+ Exclude<R, RProvided> | RSchema
397
398
  >
398
399
  <
399
400
  R = never,
@@ -417,7 +418,7 @@ export interface Repository<
417
418
  ): Effect.Effect<
418
419
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
419
420
  TType extends "many" ? never : NotFoundError<ItemType>,
420
- R | RSchema
421
+ Exclude<R, RProvided> | RSchema
421
422
  >
422
423
  <
423
424
  R = never,
@@ -443,7 +444,7 @@ export interface Repository<
443
444
  ): Effect.Effect<
444
445
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined> : RefineTHelper<T, EncodedRefined>,
445
446
  TType extends "many" ? never : NotFoundError<ItemType>,
446
- R | RSchema
447
+ Exclude<R, RProvided> | RSchema
447
448
  >
448
449
  <
449
450
  R = never,
@@ -472,7 +473,7 @@ export interface Repository<
472
473
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined>
473
474
  : RefineTHelper<T, EncodedRefined>,
474
475
  TType extends "many" ? never : NotFoundError<ItemType>,
475
- R | RSchema
476
+ Exclude<R, RProvided> | RSchema
476
477
  >
477
478
  <
478
479
  R = never,
@@ -503,7 +504,7 @@ export interface Repository<
503
504
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined>
504
505
  : RefineTHelper<T, EncodedRefined>,
505
506
  TType extends "many" ? never : NotFoundError<ItemType>,
506
- R | RSchema
507
+ Exclude<R, RProvided> | RSchema
507
508
  >
508
509
  <
509
510
  R = never,
@@ -536,7 +537,7 @@ export interface Repository<
536
537
  TType extends "many" ? DistributeQueryIfExclusiveOnArray<E, T, EncodedRefined>
537
538
  : RefineTHelper<T, EncodedRefined>,
538
539
  TType extends "many" ? never : NotFoundError<ItemType>,
539
- R | RSchema
540
+ Exclude<R, RProvided> | RSchema
540
541
  >
541
542
  }
542
543
 
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
3
- import { Array, identity, Match, Option, pipe, S } from "effect-app"
3
+ import { Array, identity, Match, Option, pipe, S, SchemaAST } from "effect-app"
4
4
  import { toNonEmptyArray } from "effect-app/Array"
5
5
  import { dropUndefinedT } from "effect-app/utils"
6
6
  import type { FilterResult } from "../filter/filterApi.js"
@@ -165,7 +165,7 @@ export const toFilter = <
165
165
  let select: (keyof TFieldValues | { key: string; subKeys: string[] })[] = []
166
166
  // TODO: support more complex (nested) schemas?
167
167
  if (schema) {
168
- const t = walkTransformation(schema.ast)
168
+ const t = walkTransformation(SchemaAST.toEncoded(schema.ast))
169
169
  if (S.AST.isObjects(t)) {
170
170
  select = t.propertySignatures.map((_) => _.name as string)
171
171
  for (const prop of t.propertySignatures) {
package/src/Operations.ts CHANGED
@@ -20,6 +20,33 @@ const make = Effect.gen(function*() {
20
20
  const reqFiberSet = yield* RequestFiberSet
21
21
  const makeOp = Effect.sync(() => OperationId.make())
22
22
 
23
+ const addOp = Effect.fnUntraced(function*(id: OperationId, title: NonEmptyString2k) {
24
+ return yield* repo.save(new Operation({ id, title })).pipe(Effect.orDie)
25
+ })
26
+
27
+ const finishOp = Effect.fnUntraced(function*(id: OperationId, exit: Exit.Exit<unknown, unknown>) {
28
+ const op = yield* repo.get(id).pipe(Effect.orDie)
29
+ const result = Exit.isSuccess(exit)
30
+ ? new OperationSuccess()
31
+ : new OperationFailure({
32
+ message: Cause.hasInterruptsOnly(exit.cause)
33
+ ? NonEmptyString2k("Interrupted")
34
+ : Cause.hasDies(exit.cause)
35
+ ? NonEmptyString2k("Unknown error")
36
+ : Cause
37
+ .findErrorOption(exit.cause)
38
+ .pipe(
39
+ Option.flatMap((_) =>
40
+ typeof _ === "object" && _ !== null && "message" in _ && S.is(NonEmptyString2k)(_.message)
41
+ ? Option.some(_.message)
42
+ : Option.none()
43
+ ),
44
+ Option.getOrNull
45
+ )
46
+ })
47
+ return yield* repo.save(copy(op, { updatedAt: new Date(), result })).pipe(Effect.orDie)
48
+ })
49
+
23
50
  const register = (title: NonEmptyString2k) =>
24
51
  Effect.tap(
25
52
  makeOp,
@@ -30,53 +57,20 @@ const make = Effect.gen(function*() {
30
57
  )
31
58
  )
32
59
 
33
- const cleanup = Effect.sync(() => subHours(new Date(), 1)).pipe(
34
- Effect.andThen((before) => repo.query(where("updatedAt", "lt", before.toISOString()))),
35
- Effect.andThen((ops) => pipe(ops, batch(100, Effect.succeed, (items) => repo.removeAndPublish(items)))),
36
- setupRequestContextFromCurrent("Operations.cleanup")
37
- )
60
+ const cleanup = Effect
61
+ .gen(function*() {
62
+ const before = subHours(new Date(), 1)
63
+ const ops = yield* repo.query(where("updatedAt", "lt", before.toISOString()))
64
+ return yield* pipe(ops, batch(100, Effect.succeed, (items) => repo.removeAndPublish(items)))
65
+ })
66
+ .pipe(setupRequestContextFromCurrent("Operations.cleanup"))
38
67
 
39
- function addOp(id: OperationId, title: NonEmptyString2k) {
40
- return repo.save(new Operation({ id, title })).pipe(Effect.orDie)
41
- }
42
- function findOp(id: OperationId) {
43
- return repo.find(id)
44
- }
45
- function finishOp(id: OperationId, exit: Exit.Exit<unknown, unknown>) {
46
- return Effect
47
- .flatMap(repo.get(id).pipe(Effect.orDie), (_) =>
48
- repo
49
- .save(
50
- copy(_, {
51
- updatedAt: new Date(),
52
- result: Exit.isSuccess(exit)
53
- ? new OperationSuccess()
54
- : new OperationFailure({
55
- message: Cause.hasInterruptsOnly(exit.cause)
56
- ? NonEmptyString2k("Interrupted")
57
- : Cause.hasDies(exit.cause)
58
- ? NonEmptyString2k("Unknown error")
59
- : Cause
60
- .findErrorOption(exit.cause)
61
- .pipe(
62
- Option.flatMap((_) =>
63
- typeof _ === "object" && _ !== null && "message" in _ && S.is(NonEmptyString2k)(_.message)
64
- ? Option.some(_.message)
65
- : Option.none()
66
- ),
67
- Option.getOrNull
68
- )
69
- })
70
- })
71
- )
72
- .pipe(Effect.orDie))
73
- }
74
- function update(id: OperationId, progress: OperationProgress) {
75
- return Effect.flatMap(
76
- repo.get(id).pipe(Effect.orDie),
77
- (_) => repo.save(copy(_, { updatedAt: new Date(), progress })).pipe(Effect.orDie)
78
- )
79
- }
68
+ const findOp = (id: OperationId) => repo.find(id)
69
+
70
+ const update = Effect.fnUntraced(function*(id: OperationId, progress: OperationProgress) {
71
+ const op = yield* repo.get(id).pipe(Effect.orDie)
72
+ return yield* repo.save(copy(op, { updatedAt: new Date(), progress })).pipe(Effect.orDie)
73
+ })
80
74
 
81
75
  function fork<R, R2, E, E2, A, A2>(
82
76
  self: (id: OperationId) => Effect.Effect<A, E, R>,
@@ -87,29 +81,18 @@ const make = Effect.gen(function*() {
87
81
  never,
88
82
  Exclude<R, Scope.Scope> | Exclude<R2, Scope.Scope>
89
83
  > {
90
- return Effect
91
- .flatMap(
92
- Scope.make(),
93
- (scope) =>
94
- register(title)
95
- .pipe(
96
- Scope.provide(scope),
97
- Effect.flatMap((id) =>
98
- reqFiberSet
99
- .forkDaemonReportUnexpected(Scope.use(
100
- self(id).pipe(Effect.withSpan(title, {}, { captureStackTrace: false })),
101
- scope
102
- ))
103
- .pipe(Effect.map((fiber): RunningOperation<A, E> => ({ fiber, id })))
104
- ),
105
- Effect.tap(({ id }) =>
106
- Effect.interruptible(fnc(id)).pipe(
107
- Effect.forkScoped,
108
- Scope.provide(scope)
109
- )
110
- )
111
- )
84
+ return Effect.gen(function*() {
85
+ const scope = yield* Scope.make()
86
+ const id = yield* Scope.provide(register(title), scope)
87
+ const fiber = yield* reqFiberSet.forkDaemonReportUnexpected(
88
+ Scope.use(
89
+ self(id).pipe(Effect.withSpan(title, {}, { captureStackTrace: false })),
90
+ scope
91
+ )
112
92
  )
93
+ yield* Scope.provide(Effect.forkScoped(Effect.interruptible(fnc(id))), scope)
94
+ return { fiber, id } satisfies RunningOperation<A, E>
95
+ })
113
96
  }
114
97
 
115
98
  const fork2: {
@@ -122,24 +105,20 @@ const make = Effect.gen(function*() {
122
105
  ): Effect.Effect<RunningOperation<A, E>, never, Exclude<R, Scope.Scope>>
123
106
  } = dual(
124
107
  2,
125
- <R, E, A>(self: (opId: OperationId) => Effect.Effect<A, E, R>, title: NonEmptyString2k) =>
126
- Effect.flatMap(
127
- Scope.make(),
128
- (scope) =>
129
- register(title)
130
- .pipe(
131
- Scope.provide(scope),
132
- Effect
133
- .flatMap((id) =>
134
- reqFiberSet
135
- .forkDaemonReportUnexpected(Scope.use(
136
- self(id).pipe(Effect.withSpan(title, {}, { captureStackTrace: false })),
137
- scope
138
- ))
139
- .pipe(Effect.map((fiber): RunningOperation<A, E> => ({ fiber, id })))
140
- )
141
- )
108
+ Effect.fnUntraced(function*<R, E, A>(
109
+ self: (opId: OperationId) => Effect.Effect<A, E, R>,
110
+ title: NonEmptyString2k
111
+ ) {
112
+ const scope = yield* Scope.make()
113
+ const id = yield* Scope.provide(register(title), scope)
114
+ const fiber = yield* reqFiberSet.forkDaemonReportUnexpected(
115
+ Scope.use(
116
+ self(id).pipe(Effect.withSpan(title, {}, { captureStackTrace: false })),
117
+ scope
118
+ )
142
119
  )
120
+ return { fiber, id } satisfies RunningOperation<A, E>
121
+ })
143
122
  )
144
123
 
145
124
  const forkOperation: {
@@ -152,28 +131,21 @@ const make = Effect.gen(function*() {
152
131
  ): Effect.Effect<RunningOperation<A, E>, never, Exclude<R, Scope.Scope>>
153
132
  } = dual(
154
133
  2,
155
- <R, E, A>(self: Effect.Effect<A, E, R>, title: NonEmptyString2k) =>
156
- Effect.flatMap(
157
- Scope.make(),
158
- (scope) =>
159
- register(title)
160
- .pipe(
161
- Scope.provide(scope),
162
- Effect
163
- .flatMap((id) =>
164
- reqFiberSet
165
- .forkDaemonReportUnexpected(Scope.use(
166
- self.pipe(Effect.withSpan(title, {}, { captureStackTrace: false })),
167
- scope
168
- ))
169
- .pipe(Effect.map((fiber): RunningOperation<A, E> => ({ fiber, id })))
170
- )
171
- )
134
+ Effect.fnUntraced(function*<R, E, A>(self: Effect.Effect<A, E, R>, title: NonEmptyString2k) {
135
+ const scope = yield* Scope.make()
136
+ const id = yield* Scope.provide(register(title), scope)
137
+ const fiber = yield* reqFiberSet.forkDaemonReportUnexpected(
138
+ Scope.use(
139
+ self.pipe(Effect.withSpan(title, {}, { captureStackTrace: false })),
140
+ scope
141
+ )
172
142
  )
143
+ return { fiber, id } satisfies RunningOperation<A, E>
144
+ })
173
145
  )
174
146
 
175
147
  function forkOperationFunction<R, E, A, Inp>(fnc: (inp: Inp) => Effect.Effect<A, E, R>, title: NonEmptyString2k) {
176
- return (inp: Inp) => fnc(inp).pipe((_) => forkOperation(_, title))
148
+ return (inp: Inp) => forkOperation(fnc(inp), title)
177
149
  }
178
150
 
179
151
  return {
@@ -194,14 +166,7 @@ export class Operations extends Context.Opaque<Operations>()("effect-app/Operati
194
166
  .use((_) =>
195
167
  _.cleanup.pipe(
196
168
  Effect.exit,
197
- Effect
198
- .flatMap((_) => {
199
- if (Exit.isSuccess(_)) {
200
- return Effect.void
201
- } else {
202
- return reportAppError(_.cause)
203
- }
204
- }),
169
+ Effect.flatMap((exit) => Exit.isSuccess(exit) ? Effect.void : reportAppError(exit.cause)),
205
170
  Effect.schedule(Schedule.fixed(Duration.minutes(20))),
206
171
  Effect.map((_) => _ as never),
207
172
  MainFiberSet.run