@@ -35,6 +35,8 @@ extends Pipeable.Pipeable {
|
|||||||
field<const P extends PropertyPath.Paths<I>>(
|
field<const P extends PropertyPath.Paths<I>>(
|
||||||
path: P
|
path: P
|
||||||
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>>
|
): Effect.Effect<FormField<PropertyPath.ValueFromPath<A, P>, PropertyPath.ValueFromPath<I, P>>>
|
||||||
|
|
||||||
|
readonly run: Effect.Effect<void>
|
||||||
readonly submit: Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException>
|
readonly submit: Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +91,49 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly canSubmit: Subscribable.Subscribable<boolean, never, never>
|
readonly canSubmit: Subscribable.Subscribable<boolean>
|
||||||
|
|
||||||
|
get run(): Effect.Effect<void> {
|
||||||
|
return this.runSemaphore.withPermits(1)(Stream.runForEach(
|
||||||
|
this.encodedValue.changes.pipe(
|
||||||
|
Option.isSome(this.debounce) ? Stream.debounce(this.debounce.value) : identity
|
||||||
|
),
|
||||||
|
|
||||||
|
encodedValue => this.validationFiber.pipe(
|
||||||
|
Effect.andThen(Option.match({
|
||||||
|
onSome: Fiber.interrupt,
|
||||||
|
onNone: () => Effect.void,
|
||||||
|
})),
|
||||||
|
Effect.andThen(
|
||||||
|
Effect.forkScoped(Effect.onExit(
|
||||||
|
Schema.decode(this.schema, { errors: "all" })(encodedValue),
|
||||||
|
exit => Effect.andThen(
|
||||||
|
Exit.matchEffect(exit, {
|
||||||
|
onSuccess: v => Effect.andThen(
|
||||||
|
Ref.set(this.value, Option.some(v)),
|
||||||
|
Ref.set(this.error, Option.none()),
|
||||||
|
),
|
||||||
|
onFailure: c => Option.match(Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), {
|
||||||
|
onSome: e => Ref.set(this.error, Option.some(e)),
|
||||||
|
onNone: () => Effect.void,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
Ref.set(this.validationFiber, Option.none()),
|
||||||
|
),
|
||||||
|
)).pipe(
|
||||||
|
Effect.tap(fiber => Ref.set(this.validationFiber, Option.some(fiber))),
|
||||||
|
Effect.andThen(Fiber.join),
|
||||||
|
Effect.andThen(value => this.autosubmit
|
||||||
|
? Effect.asVoid(Effect.forkScoped(this.submitValue(value)))
|
||||||
|
: Effect.void
|
||||||
|
),
|
||||||
|
Effect.forkScoped,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Effect.provide(this.context),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
get submit(): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException> {
|
get submit(): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>, Cause.NoSuchElementException> {
|
||||||
return this.value.pipe(
|
return this.value.pipe(
|
||||||
@@ -97,6 +141,7 @@ extends Pipeable.Class() implements Form<A, I, R, MA, ME, MR, MP> {
|
|||||||
Effect.andThen(value => this.submitValue(value)),
|
Effect.andThen(value => this.submitValue(value)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
submitValue(value: A): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>> {
|
submitValue(value: A): Effect.Effect<Option.Option<Result.Final<MA, ME, MP>>> {
|
||||||
return Effect.whenEffect(
|
return Effect.whenEffect(
|
||||||
Effect.tap(
|
Effect.tap(
|
||||||
@@ -158,51 +203,6 @@ export const make = Effect.fnUntraced(function* <A, I = A, R = never, MA = void,
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const run = <A, I, R, MA, ME, MR, MP>(
|
|
||||||
self: Form<A, I, R, MA, ME, MR, MP>
|
|
||||||
): Effect.Effect<void> => {
|
|
||||||
const _self = self as FormImpl<A, I, R, MA, ME, MR, MP>
|
|
||||||
return _self.runSemaphore.withPermits(1)(Stream.runForEach(
|
|
||||||
_self.encodedValue.changes.pipe(
|
|
||||||
Option.isSome(_self.debounce) ? Stream.debounce(_self.debounce.value) : identity
|
|
||||||
),
|
|
||||||
|
|
||||||
encodedValue => _self.validationFiber.pipe(
|
|
||||||
Effect.andThen(Option.match({
|
|
||||||
onSome: Fiber.interrupt,
|
|
||||||
onNone: () => Effect.void,
|
|
||||||
})),
|
|
||||||
Effect.andThen(
|
|
||||||
Effect.forkScoped(Effect.onExit(
|
|
||||||
Schema.decode(_self.schema, { errors: "all" })(encodedValue),
|
|
||||||
exit => Effect.andThen(
|
|
||||||
Exit.matchEffect(exit, {
|
|
||||||
onSuccess: v => Effect.andThen(
|
|
||||||
Ref.set(_self.value, Option.some(v)),
|
|
||||||
Ref.set(_self.error, Option.none()),
|
|
||||||
),
|
|
||||||
onFailure: c => Option.match(Chunk.findFirst(Cause.failures(c), e => e._tag === "ParseError"), {
|
|
||||||
onSome: e => Ref.set(_self.error, Option.some(e)),
|
|
||||||
onNone: () => Effect.void,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
Ref.set(_self.validationFiber, Option.none()),
|
|
||||||
),
|
|
||||||
)).pipe(
|
|
||||||
Effect.tap(fiber => Ref.set(_self.validationFiber, Option.some(fiber))),
|
|
||||||
Effect.andThen(Fiber.join),
|
|
||||||
Effect.andThen(value => _self.autosubmit
|
|
||||||
? Effect.asVoid(Effect.forkScoped(_self.submitValue(value)))
|
|
||||||
: Effect.void
|
|
||||||
),
|
|
||||||
Effect.forkScoped,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Effect.provide(_self.context),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
export declare namespace service {
|
export declare namespace service {
|
||||||
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
export interface Options<in out A, in out I = A, in out R = never, in out MA = void, in out ME = never, in out MR = never, in out MP = never>
|
||||||
extends make.Options<A, I, R, MA, ME, MR, MP> {}
|
extends make.Options<A, I, R, MA, ME, MR, MP> {}
|
||||||
@@ -216,7 +216,7 @@ export const service = <A, I = A, R = never, MA = void, ME = never, MR = never,
|
|||||||
Scope.Scope | R | Result.forkEffect.OutputContext<MA, ME, MR, MP>
|
Scope.Scope | R | Result.forkEffect.OutputContext<MA, ME, MR, MP>
|
||||||
> => Effect.tap(
|
> => Effect.tap(
|
||||||
make(options),
|
make(options),
|
||||||
form => Effect.forkScoped(run(form)),
|
form => Effect.forkScoped(form.run),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extends Pipeable.Class() implements Mutation<K, A, E, R, P> {
|
|||||||
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
|
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly context: Context.Context<Scope.Scope | NoInfer<R>>,
|
readonly context: Context.Context<Scope.Scope | R>,
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
readonly f: (key: K) => Effect.Effect<A, E, R>,
|
||||||
readonly initialProgress: P,
|
readonly initialProgress: P,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user