@effect-app/infra 4.0.0-beta.121 → 4.0.0-beta.123
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.
- package/CHANGELOG.md +17 -0
- package/dist/CUPS.d.ts.map +1 -1
- package/dist/CUPS.js +8 -10
- package/dist/Model/Repository/ext.d.ts +15 -3
- package/dist/Model/Repository/ext.d.ts.map +1 -1
- package/dist/Model/Repository/ext.js +25 -2
- package/dist/Model/Repository/internal/internal.d.ts +1 -1
- package/dist/Model/Repository/internal/internal.d.ts.map +1 -1
- package/dist/Model/Repository/internal/internal.js +9 -8
- package/dist/Model/Repository/makeRepo.d.ts +3 -3
- package/dist/Model/Repository/makeRepo.d.ts.map +1 -1
- package/dist/Model/Repository/service.d.ts +21 -21
- package/dist/Model/Repository/service.d.ts.map +1 -1
- package/dist/Model/query/new-kid-interpreter.d.ts +2 -2
- package/dist/Operations.d.ts +2 -2
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Operations.js +54 -57
- package/dist/OperationsRepo.d.ts +2 -2
- package/dist/QueueMaker/SQLQueue.d.ts +2 -3
- package/dist/QueueMaker/SQLQueue.d.ts.map +1 -1
- package/dist/QueueMaker/SQLQueue.js +104 -115
- package/dist/QueueMaker/memQueue.d.ts +2 -2
- package/dist/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/QueueMaker/memQueue.js +51 -62
- package/dist/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/QueueMaker/sbqueue.js +34 -50
- package/dist/Store/ContextMapContainer.d.ts +1 -1
- package/dist/Store/Cosmos.d.ts.map +1 -1
- package/dist/Store/Cosmos.js +304 -306
- package/dist/Store/Disk.d.ts +1 -1
- package/dist/Store/Disk.d.ts.map +1 -1
- package/dist/Store/Disk.js +2 -2
- package/dist/Store/Memory.d.ts +1 -1
- package/dist/Store/Memory.d.ts.map +1 -1
- package/dist/Store/Memory.js +2 -2
- package/dist/Store/SQL/Pg.d.ts.map +1 -1
- package/dist/Store/SQL/Pg.js +147 -149
- package/dist/Store/SQL.d.ts.map +1 -1
- package/dist/Store/SQL.js +6 -6
- package/dist/Store/utils.d.ts.map +1 -1
- package/dist/Store/utils.js +3 -4
- package/dist/adapters/ServiceBus.d.ts.map +1 -1
- package/dist/adapters/ServiceBus.js +7 -9
- package/dist/api/internal/auth.d.ts.map +1 -1
- package/dist/api/internal/auth.js +1 -1
- package/dist/api/routing/middleware/middleware.d.ts.map +1 -1
- package/dist/api/routing/middleware/middleware.js +2 -2
- package/dist/errorReporter.d.ts +3 -3
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +16 -23
- package/package.json +14 -14
- package/src/CUPS.ts +7 -9
- package/src/Model/Repository/ext.ts +71 -6
- package/src/Model/Repository/internal/internal.ts +13 -25
- package/src/Model/Repository/makeRepo.ts +4 -4
- package/src/Model/Repository/service.ts +22 -21
- package/src/Operations.ts +76 -111
- package/src/QueueMaker/SQLQueue.ts +119 -150
- package/src/QueueMaker/memQueue.ts +81 -102
- package/src/QueueMaker/sbqueue.ts +51 -81
- package/src/Store/Cosmos.ts +481 -484
- package/src/Store/Disk.ts +52 -53
- package/src/Store/Memory.ts +49 -50
- package/src/Store/SQL/Pg.ts +247 -250
- package/src/Store/SQL.ts +420 -426
- package/src/Store/utils.ts +23 -22
- package/src/adapters/ServiceBus.ts +106 -110
- package/src/api/internal/auth.ts +8 -6
- package/src/api/routing/middleware/middleware.ts +10 -11
- package/src/errorReporter.ts +58 -72
- package/test/dist/auth.test.d.ts.map +1 -0
- package/test/dist/fixtures.d.ts +1 -1
- package/test/dist/repository-ext.test.d.ts.map +1 -0
- 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: (
|
|
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
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
|
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
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return repo.
|
|
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
|
-
.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
126
|
-
Effect.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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)
|
|
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
|