Update dependency typescript to v7 - autoclosed #54
@@ -1,146 +1,157 @@
|
|||||||
import { type Context, Effect, Equal, type Fiber, Option, Pipeable, Predicate, type Scope, Stream, SubscriptionRef } from "effect"
|
import { type Context, Effect, Equal, Exit, type Fiber, Option, Pipeable, Predicate, type Scope, Stream, SubscriptionRef } from "effect"
|
||||||
import { Subscribable } from "effect-lens"
|
import { AsyncResult } from "effect/unstable/reactivity"
|
||||||
import * as Result from "./Result.js"
|
import * as Lens from "./Lens.js"
|
||||||
|
import type * as Subscribable from "./Subscribable.js"
|
||||||
|
|
||||||
|
|
||||||
export const MutationTypeId: unique symbol = Symbol.for("@effect-fc/Mutation/Mutation")
|
export const MutationTypeId: unique symbol = Symbol.for("@effect-fc/Mutation/Mutation")
|
||||||
export type MutationTypeId = typeof MutationTypeId
|
export type MutationTypeId = typeof MutationTypeId
|
||||||
|
|
||||||
export interface Mutation<in out K extends Mutation.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
|
export interface Mutation<in out K extends Mutation.AnyKey, in out A, in out E = never, in out R = never>
|
||||||
extends Pipeable.Pipeable {
|
extends Pipeable.Pipeable {
|
||||||
readonly [MutationTypeId]: MutationTypeId
|
readonly [MutationTypeId]: MutationTypeId
|
||||||
|
|
||||||
readonly context: Context.Context<Scope.Scope | 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 latestKey: Subscribable.Subscribable<Option.Option<K>>
|
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
|
||||||
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
||||||
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
readonly result: Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>
|
||||||
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<Result.Final<A, E, P>>>
|
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>>
|
||||||
|
|
||||||
mutate(key: K): Effect.Effect<Result.Final<A, E, P>>
|
mutate(key: K): Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>
|
||||||
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>>
|
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export declare namespace Mutation {
|
export declare namespace Mutation {
|
||||||
export type AnyKey = readonly any[]
|
export type AnyKey = readonly any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MutationImpl<in out K extends Mutation.AnyKey, in out A, in out E = never, in out R = never, in out P = never>
|
export class MutationImpl<in out K extends Mutation.AnyKey, in out A, in out E = never, in out R = never>
|
||||||
extends Pipeable.Class implements Mutation<K, A, E, R, P> {
|
extends Pipeable.Class implements Mutation<K, A, E, R> {
|
||||||
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
|
readonly [MutationTypeId]: MutationTypeId = MutationTypeId
|
||||||
readonly latestKey: Subscribable.Subscribable<Option.Option<K>>
|
|
||||||
readonly fiber: Subscribable.Subscribable<Option.Option<Fiber.Fiber<A, E>>>
|
|
||||||
readonly result: Subscribable.Subscribable<Result.Result<A, E, P>>
|
|
||||||
readonly latestFinalResult: Subscribable.Subscribable<Option.Option<Result.Final<A, E, P>>>
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly context: Context.Context<Scope.Scope | 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 latestKeyRef: SubscriptionRef.SubscriptionRef<Option.Option<K>>,
|
readonly latestKey: Lens.Lens<Option.Option<K>>,
|
||||||
readonly fiberRef: SubscriptionRef.SubscriptionRef<Option.Option<Fiber.Fiber<A, E>>>,
|
readonly fiber: Lens.Lens<Option.Option<Fiber.Fiber<A, E>>>,
|
||||||
readonly resultRef: SubscriptionRef.SubscriptionRef<Result.Result<A, E, P>>,
|
readonly result: Lens.Lens<AsyncResult.AsyncResult<A, E>>,
|
||||||
readonly latestFinalResultRef: SubscriptionRef.SubscriptionRef<Option.Option<Result.Final<A, E, P>>>,
|
readonly latestFinalResult: Lens.Lens<Option.Option<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>>,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
this.latestKey = fromSubscriptionRef(latestKeyRef)
|
|
||||||
this.fiber = fromSubscriptionRef(fiberRef)
|
|
||||||
this.result = fromSubscriptionRef(resultRef)
|
|
||||||
this.latestFinalResult = fromSubscriptionRef(latestFinalResultRef)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutate(key: K): Effect.Effect<Result.Final<A, E, P>> {
|
mutate(key: K): Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>> {
|
||||||
return SubscriptionRef.set(this.latestKeyRef, Option.some(key)).pipe(
|
return Lens.set(this.latestKey, Option.some(key)).pipe(
|
||||||
Effect.andThen(this.start(key)),
|
Effect.andThen(this.start(key)),
|
||||||
Effect.andThen(sub => this.watch(sub)),
|
Effect.flatMap(state => this.watch(state)),
|
||||||
Effect.provide(this.context),
|
Effect.provide(this.context),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<Result.Result<A, E, P>>> {
|
mutateSubscribable(key: K): Effect.Effect<Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>> {
|
||||||
return SubscriptionRef.set(this.latestKeyRef, Option.some(key)).pipe(
|
return Lens.set(this.latestKey, Option.some(key)).pipe(
|
||||||
Effect.andThen(this.start(key)),
|
Effect.andThen(this.start(key)),
|
||||||
Effect.tap(sub => Effect.forkScoped(this.watch(sub))),
|
Effect.tap(state => Effect.forkScoped(this.watch(state))),
|
||||||
Effect.provide(this.context),
|
Effect.provide(this.context),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
start(key: K): Effect.Effect<
|
start(key: K): Effect.Effect<
|
||||||
Subscribable.Subscribable<Result.Result<A, E, P>>,
|
Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | R
|
Scope.Scope | R
|
||||||
> {
|
> {
|
||||||
const self = this
|
return Effect.gen({ self: this }, function*() {
|
||||||
return Effect.gen(function*() {
|
const previous = yield* Lens.get(this.latestFinalResult)
|
||||||
const initial = yield* SubscriptionRef.get(self.latestFinalResultRef)
|
const state = Lens.fromSubscriptionRef(yield* SubscriptionRef.make<AsyncResult.AsyncResult<A, E>>(
|
||||||
const [sub, fiber] = yield* Result.unsafeForkEffect<A, E, R, P>(
|
Option.getOrElse(previous, () => AsyncResult.initial(false))
|
||||||
Effect.onExit(self.f(key), () => Effect.andThen(
|
))
|
||||||
Effect.all([Effect.fiberId, SubscriptionRef.get(self.fiberRef)]),
|
|
||||||
([currentFiberId, fiber]) => Option.match(fiber, {
|
|
||||||
onSome: v => Equal.equals(currentFiberId, v.id)
|
|
||||||
? SubscriptionRef.set(self.fiberRef, Option.none())
|
|
||||||
: Effect.succeed(undefined),
|
|
||||||
onNone: () => Effect.succeed(undefined),
|
|
||||||
}),
|
|
||||||
)),
|
|
||||||
|
|
||||||
{
|
const fiber = yield* Effect.forkScoped(Effect.andThen(
|
||||||
initial: Option.isSome(initial) ? Result.willFetch(initial.value) : Result.initial(),
|
Lens.update(state, AsyncResult.match({
|
||||||
initialProgress: self.initialProgress,
|
onInitial: () => AsyncResult.initial(true),
|
||||||
} as Result.unsafeForkEffect.Options<A, E, P>,
|
onSuccess: v => AsyncResult.success(v.value, {
|
||||||
)
|
waiting: true,
|
||||||
yield* SubscriptionRef.set(self.fiberRef, Option.some(fiber))
|
}),
|
||||||
return sub
|
onFailure: v => AsyncResult.failure(v.cause, {
|
||||||
|
waiting: true,
|
||||||
|
previousSuccess: v.previousSuccess,
|
||||||
|
})
|
||||||
|
})),
|
||||||
|
|
||||||
|
Effect.onExit(this.f(key), exit => Lens.update(
|
||||||
|
state,
|
||||||
|
previous => Exit.match(exit, {
|
||||||
|
onSuccess: v => AsyncResult.success(v),
|
||||||
|
onFailure: c => AsyncResult.match(previous, {
|
||||||
|
onInitial: () => AsyncResult.failure(c),
|
||||||
|
onSuccess: v => AsyncResult.failure(c, {
|
||||||
|
previousSuccess: Option.some(v),
|
||||||
|
}),
|
||||||
|
onFailure: v => AsyncResult.failure(c, {
|
||||||
|
previousSuccess: v.previousSuccess,
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
).pipe(
|
||||||
|
Effect.andThen(Effect.all([
|
||||||
|
Effect.fiberId,
|
||||||
|
Lens.get(this.fiber),
|
||||||
|
])),
|
||||||
|
Effect.flatMap(([fiberId, fiber]) => Option.match(fiber, {
|
||||||
|
onSome: v => Equal.equals(fiberId, v.id)
|
||||||
|
? Lens.set(this.fiber, Option.none())
|
||||||
|
: Effect.void,
|
||||||
|
onNone: () => Effect.void,
|
||||||
|
})),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
|
||||||
|
yield* Lens.set(this.fiber, Option.some(fiber))
|
||||||
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
sub: Subscribable.Subscribable<Result.Result<A, E, P>>
|
state: Subscribable.Subscribable<AsyncResult.AsyncResult<A, E>>
|
||||||
): Effect.Effect<Result.Final<A, E, P>> {
|
): Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>> {
|
||||||
return sub.get.pipe(
|
return state.get.pipe(
|
||||||
Effect.andThen(initial => Stream.runFoldEffect(
|
Effect.andThen(initial => Stream.runFoldEffect(
|
||||||
Stream.takeUntil(sub.changes, result => Result.isFinal(result) && !Result.hasFlag(result)),
|
state.changes,
|
||||||
() => initial,
|
() => initial,
|
||||||
(_, result) => Effect.as(SubscriptionRef.set(this.resultRef, result), result),
|
(_, result) => Effect.as(Lens.set(this.result, result), result),
|
||||||
) as Effect.Effect<Result.Final<A, E, P>>),
|
) as Effect.Effect<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>),
|
||||||
Effect.tap(result => SubscriptionRef.set(this.latestFinalResultRef, Option.some(result))),
|
Effect.tap(result => Lens.set(this.latestFinalResult, Option.some(result))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const isMutation = (u: unknown): u is Mutation<readonly unknown[], unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, MutationTypeId)
|
export const isMutation = (u: unknown): u is Mutation<readonly unknown[], unknown, unknown, unknown> => Predicate.hasProperty(u, MutationTypeId)
|
||||||
|
|
||||||
|
|
||||||
export declare namespace make {
|
export declare namespace make {
|
||||||
export interface Options<K extends Mutation.AnyKey = never, A = void, E = never, R = never, P = never> {
|
export interface Options<K extends Mutation.AnyKey = never, A = void, E = never, R = never> {
|
||||||
readonly f: (key: K) => Effect.Effect<A, E, Result.forkEffect.InputContext<R, NoInfer<P>>>
|
readonly f: (key: K) => Effect.Effect<A, E, R>
|
||||||
readonly initialProgress?: P
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const make = Effect.fnUntraced(function* <const K extends Mutation.AnyKey = never, A = void, E = never, R = never, P = never>(
|
export const make = Effect.fnUntraced(function* <const K extends Mutation.AnyKey = never, A = void, E = never, R = never>(
|
||||||
options: make.Options<K, A, E, R, P>
|
options: make.Options<K, A, E, R>
|
||||||
): Effect.fn.Return<
|
): Effect.fn.Return<
|
||||||
Mutation<K, A, E, Result.forkEffect.OutputContext<R, P>, P>,
|
Mutation<K, A, E, R>,
|
||||||
never,
|
never,
|
||||||
Scope.Scope | Result.forkEffect.OutputContext<R, P>
|
Scope.Scope | R
|
||||||
> {
|
> {
|
||||||
return new MutationImpl(
|
return new MutationImpl(
|
||||||
yield* Effect.context<Scope.Scope | Result.forkEffect.OutputContext<R, P>>(),
|
yield* Effect.context<Scope.Scope | R>(),
|
||||||
options.f as any,
|
options.f,
|
||||||
options.initialProgress as P,
|
|
||||||
|
|
||||||
yield* SubscriptionRef.make(Option.none<K>()),
|
Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none<K>())),
|
||||||
yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>()),
|
Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none<Fiber.Fiber<A, E>>())),
|
||||||
yield* SubscriptionRef.make(Result.initial<A, E, P>()),
|
Lens.fromSubscriptionRef(yield* SubscriptionRef.make<AsyncResult.AsyncResult<A, E>>(AsyncResult.initial())),
|
||||||
yield* SubscriptionRef.make(Option.none<Result.Final<A, E, P>>()),
|
Lens.fromSubscriptionRef(yield* SubscriptionRef.make(Option.none<AsyncResult.Success<A, E> | AsyncResult.Failure<A, E>>())),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const fromSubscriptionRef = <A>(ref: SubscriptionRef.SubscriptionRef<A>): Subscribable.Subscribable<A> => Subscribable.make({
|
|
||||||
get: SubscriptionRef.get(ref),
|
|
||||||
changes: SubscriptionRef.changes(ref),
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ extends Pipeable.Class implements Query<K, A, KE, KR, E, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const isQuery = (u: unknown): u is Query<readonly unknown[], unknown> => Predicate.hasProperty(u, QueryTypeId)
|
export const isQuery = (u: unknown): u is Query<readonly unknown[], unknown, unknown, unknown, unknown, unknown> => Predicate.hasProperty(u, QueryTypeId)
|
||||||
|
|
||||||
|
|
||||||
export declare namespace make {
|
export declare namespace make {
|
||||||
|
|||||||
Reference in New Issue
Block a user