Skip to content

Commit 5f99aed

Browse files
tim-smarteffect-bot
authored andcommitted
accept multiple steps in constructor
1 parent b33e4cc commit 5f99aed

File tree

2 files changed

+109
-116
lines changed

2 files changed

+109
-116
lines changed

.changeset/public-books-unite.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,25 @@ import { Effect, ExecutionPlan, Schedule } from "effect"
1414
declare const layerBad: Layer.Layer<AiLanguageModel.AiLanguageModel>
1515
declare const layerGood: Layer.Layer<AiLanguageModel.AiLanguageModel>
1616

17-
const ThePlan = ExecutionPlan.make({
18-
// First try with the bad layer 2 times with a 3 second delay between attempts
19-
provide: layerBad,
20-
attempts: 2,
21-
schedule: Schedule.spaced(3000)
22-
}).pipe(
17+
const ThePlan = ExecutionPlan.make(
18+
{
19+
// First try with the bad layer 2 times with a 3 second delay between attempts
20+
provide: layerBad,
21+
attempts: 2,
22+
schedule: Schedule.spaced(3000)
23+
},
2324
// Then try with the bad layer 3 times with a 1 second delay between attempts
24-
ExecutionPlan.orElse({
25+
{
2526
provide: layerBad,
2627
attempts: 3,
2728
schedule: Schedule.spaced(1000)
28-
}),
29+
},
2930
// Finally try with the good layer.
3031
//
3132
// If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided.
32-
ExecutionPlan.orElse({
33+
{
3334
provide: layerGood
34-
})
35+
}
3536
)
3637

3738
declare const effect: Effect.Effect<

packages/effect/src/ExecutionPlan.ts

Lines changed: 98 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* @experimental
44
*/
55
import type { NonEmptyReadonlyArray } from "./Array.js"
6+
import * as Arr from "./Array.js"
67
import type * as Context from "./Context.js"
78
import * as Effect from "./Effect.js"
89
import { dual } from "./Function.js"
@@ -11,6 +12,7 @@ import * as Layer from "./Layer.js"
1112
import type { Pipeable } from "./Pipeable.js"
1213
import { pipeArguments } from "./Pipeable.js"
1314
import type * as Schedule from "./Schedule.js"
15+
import type * as Types from "./Types.js"
1416

1517
/**
1618
* @since 3.16.0
@@ -45,27 +47,32 @@ export const isExecutionPlan: (u: unknown) => u is ExecutionPlan<unknown, unknow
4547
* declare const layerBad: Layer.Layer<AiLanguageModel.AiLanguageModel>
4648
* declare const layerGood: Layer.Layer<AiLanguageModel.AiLanguageModel>
4749
*
48-
* const ThePlan = ExecutionPlan.make({
49-
* // First try with the bad layer 2 times with a 3 second delay between attempts
50-
* provide: layerBad,
51-
* attempts: 2,
52-
* schedule: Schedule.spaced(3000)
53-
* }).pipe(
50+
* const ThePlan = ExecutionPlan.make(
51+
* {
52+
* // First try with the bad layer 2 times with a 3 second delay between attempts
53+
* provide: layerBad,
54+
* attempts: 2,
55+
* schedule: Schedule.spaced(3000)
56+
* },
5457
* // Then try with the bad layer 3 times with a 1 second delay between attempts
55-
* ExecutionPlan.orElse({
58+
* {
5659
* provide: layerBad,
5760
* attempts: 3,
5861
* schedule: Schedule.spaced(1000)
59-
* }),
62+
* },
6063
* // Finally try with the good layer.
6164
* //
6265
* // If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided.
63-
* ExecutionPlan.orElse({
66+
* {
6467
* provide: layerGood
65-
* })
68+
* }
6669
* )
6770
*
68-
* declare const effect: Effect.Effect<void, never, AiLanguageModel.AiLanguageModel>
71+
* declare const effect: Effect.Effect<
72+
* void,
73+
* never,
74+
* AiLanguageModel.AiLanguageModel
75+
* >
6976
* const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect, ThePlan)
7077
* ```
7178
*
@@ -76,9 +83,9 @@ export const isExecutionPlan: (u: unknown) => u is ExecutionPlan<unknown, unknow
7683
export interface ExecutionPlan<in out Provides, in In = unknown, out E = never, out R = never> extends Pipeable {
7784
readonly [TypeId]: TypeId
7885
readonly steps: NonEmptyReadonlyArray<{
79-
readonly schedule?: Schedule.Schedule<unknown, In, R>
86+
readonly schedule?: Schedule.Schedule<unknown, In, R> | undefined
8087
readonly attempts?: number | undefined
81-
readonly while?: (input: In) => Effect.Effect<boolean, E, R>
88+
readonly while?: ((input: In) => Effect.Effect<boolean, E, R>) | undefined
8289
readonly provide: Context.Context<Provides> | Layer.Layer<Provides, E, R>
8390
}>
8491
readonly withRequirements: Effect.Effect<ExecutionPlan<Provides, In, E>, never, R>
@@ -95,27 +102,32 @@ export interface ExecutionPlan<in out Provides, in In = unknown, out E = never,
95102
* declare const layerBad: Layer.Layer<AiLanguageModel.AiLanguageModel>
96103
* declare const layerGood: Layer.Layer<AiLanguageModel.AiLanguageModel>
97104
*
98-
* const ThePlan = ExecutionPlan.make({
99-
* // First try with the bad layer 2 times with a 3 second delay between attempts
100-
* provide: layerBad,
101-
* attempts: 2,
102-
* schedule: Schedule.spaced(3000)
103-
* }).pipe(
105+
* const ThePlan = ExecutionPlan.make(
106+
* {
107+
* // First try with the bad layer 2 times with a 3 second delay between attempts
108+
* provide: layerBad,
109+
* attempts: 2,
110+
* schedule: Schedule.spaced(3000)
111+
* },
104112
* // Then try with the bad layer 3 times with a 1 second delay between attempts
105-
* ExecutionPlan.orElse({
113+
* {
106114
* provide: layerBad,
107115
* attempts: 3,
108116
* schedule: Schedule.spaced(1000)
109-
* }),
117+
* },
110118
* // Finally try with the good layer.
111119
* //
112120
* // If `attempts` is omitted, the plan will only attempt once, unless a schedule is provided.
113-
* ExecutionPlan.orElse({
121+
* {
114122
* provide: layerGood
115-
* })
123+
* }
116124
* )
117125
*
118-
* declare const effect: Effect.Effect<void, never, AiLanguageModel.AiLanguageModel>
126+
* declare const effect: Effect.Effect<
127+
* void,
128+
* never,
129+
* AiLanguageModel.AiLanguageModel
130+
* >
119131
* const withPlan: Effect.Effect<void> = Effect.withExecutionPlan(effect, ThePlan)
120132
* ```
121133
*
@@ -124,40 +136,60 @@ export interface ExecutionPlan<in out Provides, in In = unknown, out E = never,
124136
* @experimental
125137
*/
126138
export const make = <
127-
Provides,
128-
Out,
129-
WhileIn = unknown,
130-
SIn = unknown,
131-
LE = never,
132-
LR = never,
133-
WhileE = never,
134-
WhileR = never,
135-
SR = never
136-
>(options: {
137-
readonly provide: Context.Context<Provides> | Layer.Layer<Provides, LE, LR>
138-
readonly attempts?: number | undefined
139-
readonly while?:
140-
| ((input: WhileIn) => boolean | Effect.Effect<boolean, WhileE, WhileR>)
141-
| undefined
142-
readonly schedule?: Schedule.Schedule<Out, SIn, SR> | undefined
143-
}): ExecutionPlan<Provides, WhileIn & SIn, LE | WhileE, LR | SR | WhileR> => {
144-
if (options.attempts && options.attempts < 1) {
145-
throw new Error("ExecutionPlan.make: attempts must be greater than 0")
146-
}
147-
return makeProto([
148-
{
149-
schedule: options.schedule,
150-
attempts: options.attempts,
151-
while: options.while
152-
? (input: WhileIn) =>
139+
const Steps extends NonEmptyReadonlyArray<make.Step>
140+
>(...steps: Steps & { [K in keyof Steps]: make.Step }): ExecutionPlan<
141+
Steps[number]["provide"] extends Context.Context<infer Provides> | Layer.Layer<infer Provides, infer _E, infer _R>
142+
? Provides
143+
: never,
144+
Types.UnionToIntersection<
145+
| (Steps[number]["while"] extends (input: infer In) => any ? In : never)
146+
| (Steps[number]["schedule"] extends Schedule.Schedule<infer _Out, infer In, infer _R> ? In : never)
147+
>,
148+
| (Steps[number]["provide"] extends Layer.Layer<infer _P, infer _E, infer _R> ? _E
149+
: never)
150+
| (Steps[number]["while"] extends (input: infer _I) => Effect.Effect<infer _A, infer _E, infer _R> ? _E : never),
151+
| (Steps[number]["provide"] extends Layer.Layer<infer _P, infer _E, infer _R> ? _R
152+
: never)
153+
| (Steps[number]["while"] extends (input: infer _I) => Effect.Effect<infer _A, infer _E, infer _R> ? _R : never)
154+
| (Steps[number]["schedule"] extends Schedule.Schedule<infer _Out, infer _In, infer _R> ? _R : never)
155+
> =>
156+
makeProto(Arr.map(steps as Steps, (step) => {
157+
if (step.attempts && step.attempts < 1) {
158+
throw new Error("ExecutionPlan.make: step.attempts must be greater than 0")
159+
}
160+
return {
161+
schedule: step.schedule,
162+
attempts: step.attempts,
163+
while: step.while
164+
? (input: any) =>
153165
Effect.suspend(() => {
154-
const result = options.while!(input)
166+
const result = step.while!(input)
155167
return typeof result === "boolean" ? Effect.succeed(result) : result
156168
})
157169
: undefined,
158-
provide: options.provide
170+
provide: step.provide
159171
}
160-
] as any)
172+
}))
173+
174+
/**
175+
* @since 3.16.0
176+
* @experimental
177+
*/
178+
export declare namespace make {
179+
/**
180+
* @since 3.16.0
181+
* @experimental
182+
*/
183+
export type Step = {
184+
readonly provide:
185+
| Context.Context<any>
186+
| Context.Context<never>
187+
| Layer.Layer<any, any, any>
188+
| Layer.Layer<never, any, any>
189+
readonly attempts?: number
190+
readonly while?: (input: any) => boolean | Effect.Effect<boolean, any, any>
191+
readonly schedule?: Schedule.Schedule<any, any, any>
192+
}
161193
}
162194

163195
const Proto: Omit<ExecutionPlan<any, any, any, any>, "steps"> = {
@@ -190,81 +222,41 @@ const makeProto = <Provides, In, PlanE, PlanR>(steps: ExecutionPlan<Provides, In
190222
export const orElse: {
191223
<
192224
Provides2,
193-
Out,
194-
Err2 = never,
195-
Req2 = never,
196225
In2 = unknown,
197-
SIn = unknown,
198-
SR = never,
199-
WhileE = never,
200-
WhileR = never
201-
>(
202-
options: ExecutionPlan<Provides2, In2, Err2, Req2> | {
203-
readonly provide: Context.Context<Provides2> | Layer.Layer<Provides2, Err2, Req2>
204-
readonly attempts?: number | undefined
205-
readonly while?:
206-
| ((input: In2) => boolean | Effect.Effect<boolean, WhileE, WhileR>)
207-
| undefined
208-
readonly schedule?: Schedule.Schedule<Out, SIn, SR> | undefined
209-
}
210-
): <
226+
Err2 = never,
227+
Req2 = never
228+
>(other: ExecutionPlan<Provides2, In2, Err2, Req2>): <
211229
Provides,
212230
In,
213231
PlanE,
214232
PlanR
215233
>(
216234
self: ExecutionPlan<Provides, In, PlanE, PlanR>
217-
) => ExecutionPlan<Provides & Provides2, In & In2 & SIn, PlanE | Err2 | WhileE, PlanR | Req2 | SR | WhileR>
235+
) => ExecutionPlan<Provides & Provides2, In & In2, PlanE | Err2, PlanR | Req2>
218236
<
219237
Provides,
220238
In,
221239
PlanE,
222240
PlanR,
223241
Provides2,
224-
Out,
225-
Err2 = never,
226-
Req2 = never,
227242
In2 = unknown,
228-
SIn = unknown,
229-
SR = never,
230-
WhileE = never,
231-
WhileR = never
243+
Err2 = never,
244+
Req2 = never
232245
>(
233246
self: ExecutionPlan<Provides, In, PlanE, PlanR>,
234-
options: ExecutionPlan<Provides2, In2, Err2, Req2> | {
235-
readonly provide: Context.Context<Provides2> | Layer.Layer<Provides2, Err2, Req2>
236-
readonly attempts?: number | undefined
237-
readonly while?:
238-
| ((input: In2) => boolean | Effect.Effect<boolean, WhileE, WhileR>)
239-
| undefined
240-
readonly schedule?: Schedule.Schedule<Out, SIn, SR> | undefined
241-
}
242-
): ExecutionPlan<Provides & Provides2, In & In2 & SIn, PlanE | Err2 | WhileE, PlanR | Req2 | SR | WhileR>
247+
other: ExecutionPlan<Provides2, In2, Err2, Req2>
248+
): ExecutionPlan<Provides & Provides2, In & In2, PlanE | Err2, PlanR | Req2>
243249
} = dual(2, <
244250
Provides,
245251
In,
246252
PlanE,
247253
PlanR,
248254
Provides2,
249-
Out,
250-
Err2 = never,
251-
Req2 = never,
252255
In2 = unknown,
253-
SIn = unknown,
254-
SR = never,
255-
WhileE = never,
256-
WhileR = never
256+
Err2 = never,
257+
Req2 = never
257258
>(
258259
self: ExecutionPlan<Provides, In, PlanE, PlanR>,
259-
options: ExecutionPlan<Provides2, In2, Err2, Req2> | {
260-
readonly provide: Context.Context<Provides2> | Layer.Layer<Provides2, Err2, Req2>
261-
readonly attempts?: number | undefined
262-
readonly while?:
263-
| ((input: In2) => boolean | Effect.Effect<boolean, WhileE, WhileR>)
264-
| undefined
265-
readonly schedule?: Schedule.Schedule<Out, SIn, SR> | undefined
266-
}
267-
): ExecutionPlan<Provides & Provides2, In & In2 & SIn, PlanE | Err2 | WhileE, PlanR | Req2 | SR | WhileR> => {
268-
const other: ExecutionPlan<any, any, any, any> = isExecutionPlan(options) ? options : make(options as any)
269-
return makeProto(self.steps.concat(other.steps as any) as any)
270-
})
260+
other: ExecutionPlan<Provides2, In2, Err2, Req2>
261+
): ExecutionPlan<Provides & Provides2, In & In2, PlanE | Err2, PlanR | Req2> =>
262+
makeProto(self.steps.concat(other.steps as any) as any))

0 commit comments

Comments
 (0)