This commit is contained in:
@@ -1,12 +1,11 @@
|
|||||||
import * as AsyncData from "@typed/async-data"
|
import * as AsyncData from "@typed/async-data"
|
||||||
import { type Context, Effect, type Fiber, Queue, Ref, Stream, SubscriptionRef } from "effect"
|
import { Effect, type Fiber, Queue, Ref, Stream, SubscriptionRef } from "effect"
|
||||||
import type * as QueryClient from "../QueryClient.js"
|
import type * as QueryClient from "./QueryClient.js"
|
||||||
import * as QueryProgress from "../QueryProgress.js"
|
import * as QueryProgress from "./QueryProgress.js"
|
||||||
import * as QueryState from "./QueryState.js"
|
import { QueryState } from "./internal/index.js"
|
||||||
|
|
||||||
|
|
||||||
export interface MutationRunner<K extends readonly unknown[], A, E, R> {
|
export interface MutationRunner<K extends readonly unknown[], A, E> {
|
||||||
readonly context: Context.Context<R>
|
|
||||||
readonly stateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<A, E>>
|
readonly stateRef: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<A, E>>
|
||||||
|
|
||||||
readonly mutate: (...key: K) => Effect.Effect<AsyncData.Success<A> | AsyncData.Failure<E>>
|
readonly mutate: (...key: K) => Effect.Effect<AsyncData.Success<A> | AsyncData.Failure<E>>
|
||||||
@@ -17,6 +16,11 @@ export interface MutationRunner<K extends readonly unknown[], A, E, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const Tag = <const Id extends string>(id: Id) => <
|
||||||
|
Self, K extends readonly unknown[], A, E = never,
|
||||||
|
>() => Effect.Tag(id)<Self, MutationRunner<K, A, E>>()
|
||||||
|
|
||||||
|
|
||||||
export interface MakeProps<K extends readonly unknown[], A, FallbackA, E, HandledE, R> {
|
export interface MakeProps<K extends readonly unknown[], A, FallbackA, E, HandledE, R> {
|
||||||
readonly QueryClient: QueryClient.GenericTagClass<FallbackA, HandledE>
|
readonly QueryClient: QueryClient.GenericTagClass<FallbackA, HandledE>
|
||||||
readonly mutation: (key: K) => Effect.Effect<A, E, R | QueryProgress.QueryProgress>
|
readonly mutation: (key: K) => Effect.Effect<A, E, R | QueryProgress.QueryProgress>
|
||||||
@@ -28,7 +32,7 @@ export const make = <K extends readonly unknown[], A, FallbackA, E, HandledE, R>
|
|||||||
mutation,
|
mutation,
|
||||||
}: MakeProps<K, A, FallbackA, E, HandledE, R>
|
}: MakeProps<K, A, FallbackA, E, HandledE, R>
|
||||||
): Effect.Effect<
|
): Effect.Effect<
|
||||||
MutationRunner<K, A | FallbackA, Exclude<E, HandledE>, R>,
|
MutationRunner<K, A | FallbackA, Exclude<E, HandledE>>,
|
||||||
never,
|
never,
|
||||||
R | QueryClient.TagClassShape<FallbackA, HandledE>
|
R | QueryClient.TagClassShape<FallbackA, HandledE>
|
||||||
> => Effect.gen(function*() {
|
> => Effect.gen(function*() {
|
||||||
@@ -37,20 +41,13 @@ export const make = <K extends readonly unknown[], A, FallbackA, E, HandledE, R>
|
|||||||
|
|
||||||
const queryStateTag = QueryState.makeTag<A | FallbackA, Exclude<E, HandledE>>()
|
const queryStateTag = QueryState.makeTag<A | FallbackA, Exclude<E, HandledE>>()
|
||||||
|
|
||||||
const run = (key: K) => Effect.Do.pipe(
|
const run = (key: K) => Effect.all([QueryClient, queryStateTag]).pipe(
|
||||||
Effect.bind("state", () => queryStateTag),
|
Effect.flatMap(([client, state]) => state.set(AsyncData.loading()).pipe(
|
||||||
Effect.bind("client", () => QueryClient),
|
|
||||||
|
|
||||||
Effect.flatMap(({ state, client }) => state.set(AsyncData.loading()).pipe(
|
|
||||||
Effect.andThen(mutation(key)),
|
Effect.andThen(mutation(key)),
|
||||||
client.errorHandler.handle,
|
client.errorHandler.handle,
|
||||||
Effect.matchCauseEffect({
|
Effect.matchCauseEffect({
|
||||||
onSuccess: v => Effect.succeed(AsyncData.success(v)).pipe(
|
onSuccess: v => Effect.tap(Effect.succeed(AsyncData.success(v)), state.set),
|
||||||
Effect.tap(state.set)
|
onFailure: c => Effect.tap(Effect.succeed(AsyncData.failure(c)), state.set),
|
||||||
),
|
|
||||||
onFailure: c => Effect.succeed(AsyncData.failure(c)).pipe(
|
|
||||||
Effect.tap(state.set)
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
|
|
||||||
@@ -64,11 +61,11 @@ export const make = <K extends readonly unknown[], A, FallbackA, E, HandledE, R>
|
|||||||
value => Ref.set(globalStateRef, value),
|
value => Ref.set(globalStateRef, value),
|
||||||
))
|
))
|
||||||
|
|
||||||
const forkMutate = (...key: K) => Effect.Do.pipe(
|
const forkMutate = (...key: K) => Effect.all([
|
||||||
Effect.bind("stateRef", () => Ref.make(AsyncData.noData<A | FallbackA, Exclude<E, HandledE>>())),
|
Ref.make(AsyncData.noData<A | FallbackA, Exclude<E, HandledE>>()),
|
||||||
Effect.bind("stateQueue", () => Queue.unbounded<AsyncData.AsyncData<A | FallbackA, Exclude<E, HandledE>>>()),
|
Queue.unbounded<AsyncData.AsyncData<A | FallbackA, Exclude<E, HandledE>>>(),
|
||||||
|
]).pipe(
|
||||||
Effect.flatMap(({ stateRef, stateQueue }) =>
|
Effect.flatMap(([stateRef, stateQueue]) =>
|
||||||
Effect.addFinalizer(() => Queue.shutdown(stateQueue)).pipe(
|
Effect.addFinalizer(() => Queue.shutdown(stateQueue)).pipe(
|
||||||
Effect.andThen(run(key)),
|
Effect.andThen(run(key)),
|
||||||
Effect.scoped,
|
Effect.scoped,
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import type * as AsyncData from "@typed/async-data"
|
|
||||||
import { Effect, type Fiber, type Stream, type SubscriptionRef } from "effect"
|
|
||||||
|
|
||||||
|
|
||||||
export interface MutationService<K extends readonly unknown[], A, E> {
|
|
||||||
readonly state: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<A, E>>
|
|
||||||
readonly mutate: (...key: K) => Effect.Effect<AsyncData.Success<A> | AsyncData.Failure<E>>
|
|
||||||
readonly forkMutate: (...key: K) => Effect.Effect<readonly [
|
|
||||||
fiber: Fiber.RuntimeFiber<AsyncData.Success<A> | AsyncData.Failure<E>>,
|
|
||||||
state: Stream.Stream<AsyncData.AsyncData<A, E>>,
|
|
||||||
]>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Tag = <const Id extends string>(id: Id) => <
|
|
||||||
Self, K extends readonly unknown[], A, E = never,
|
|
||||||
>() => Effect.Tag(id)<Self, MutationService<K, A, E>>()
|
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
import type * as AsyncData from "@typed/async-data"
|
import { type Effect, type Stream } from "effect"
|
||||||
import { type Context, Effect, type Fiber, Layer, type Stream, type SubscriptionRef } from "effect"
|
|
||||||
import * as React from "react"
|
|
||||||
import { ReffuseExtension, type ReffuseNamespace } from "reffuse"
|
import { ReffuseExtension, type ReffuseNamespace } from "reffuse"
|
||||||
import { MutationRunner } from "./internal/index.js"
|
import * as MutationRunner from "./MutationRunner.js"
|
||||||
import type * as MutationService from "./MutationService.js"
|
|
||||||
import * as QueryClient from "./QueryClient.js"
|
import * as QueryClient from "./QueryClient.js"
|
||||||
import type * as QueryProgress from "./QueryProgress.js"
|
import type * as QueryProgress from "./QueryProgress.js"
|
||||||
import * as QueryRunner from "./QueryRunner.js"
|
import * as QueryRunner from "./QueryRunner.js"
|
||||||
@@ -15,25 +12,10 @@ export interface UseQueryProps<K extends readonly unknown[], A, E, R> {
|
|||||||
readonly options?: QueryRunner.RunOptions
|
readonly options?: QueryRunner.RunOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface UseMutationProps<K extends readonly unknown[], A, E, R> {
|
export interface UseMutationProps<K extends readonly unknown[], A, E, R> {
|
||||||
readonly mutation: (key: K) => Effect.Effect<A, E, R | QueryProgress.QueryProgress>
|
readonly mutation: (key: K) => Effect.Effect<A, E, R | QueryProgress.QueryProgress>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseMutationResult<K extends readonly unknown[], A, E> {
|
|
||||||
readonly state: SubscriptionRef.SubscriptionRef<AsyncData.AsyncData<A, E>>
|
|
||||||
|
|
||||||
readonly mutate: (...key: K) => Effect.Effect<AsyncData.Success<A> | AsyncData.Failure<E>>
|
|
||||||
readonly forkMutate: (...key: K) => Effect.Effect<readonly [
|
|
||||||
fiber: Fiber.RuntimeFiber<AsyncData.Success<A> | AsyncData.Failure<E>>,
|
|
||||||
state: Stream.Stream<AsyncData.AsyncData<A, E>>,
|
|
||||||
]>
|
|
||||||
|
|
||||||
readonly layer: <Self, Id extends string>(
|
|
||||||
tag: Context.TagClass<Self, Id, MutationService.MutationService<K, A, E>>
|
|
||||||
) => Layer.Layer<Self>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const QueryExtension = ReffuseExtension.make(() => ({
|
export const QueryExtension = ReffuseExtension.make(() => ({
|
||||||
useQuery<
|
useQuery<
|
||||||
@@ -70,23 +52,10 @@ export const QueryExtension = ReffuseExtension.make(() => ({
|
|||||||
>(
|
>(
|
||||||
this: ReffuseNamespace.ReffuseNamespace<R | QueryClient.TagClassShape<FallbackA, HandledE>>,
|
this: ReffuseNamespace.ReffuseNamespace<R | QueryClient.TagClassShape<FallbackA, HandledE>>,
|
||||||
props: UseMutationProps<QK, QA, QE, QR>,
|
props: UseMutationProps<QK, QA, QE, QR>,
|
||||||
): UseMutationResult<QK, QA | FallbackA, Exclude<QE, HandledE>> {
|
): MutationRunner.MutationRunner<QK, QA | FallbackA, Exclude<QE, HandledE>> {
|
||||||
const runner = this.useMemo(() => MutationRunner.make({
|
return this.useMemo(() => MutationRunner.make({
|
||||||
QueryClient: QueryClient.makeGenericTagClass<FallbackA, HandledE>(),
|
QueryClient: QueryClient.makeGenericTagClass<FallbackA, HandledE>(),
|
||||||
mutation: props.mutation,
|
mutation: props.mutation,
|
||||||
}), [])
|
}), [])
|
||||||
|
|
||||||
return React.useMemo(() => ({
|
|
||||||
state: runner.stateRef,
|
|
||||||
|
|
||||||
mutate: runner.mutate,
|
|
||||||
forkMutate: runner.forkMutate,
|
|
||||||
|
|
||||||
layer: tag => Layer.succeed(tag, {
|
|
||||||
state: runner.stateRef,
|
|
||||||
mutate: runner.mutate,
|
|
||||||
forkMutate: runner.forkMutate,
|
|
||||||
}),
|
|
||||||
}), [runner])
|
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export * as MutationService from "./MutationService.js"
|
export * as MutationRunner from "./MutationRunner.js"
|
||||||
export * as QueryClient from "./QueryClient.js"
|
export * as QueryClient from "./QueryClient.js"
|
||||||
export * as QueryErrorHandler from "./QueryErrorHandler.js"
|
export * as QueryErrorHandler from "./QueryErrorHandler.js"
|
||||||
export * from "./QueryExtension.js"
|
export * from "./QueryExtension.js"
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export * as MutationRunner from "./MutationRunner.js"
|
|
||||||
export * as QueryState from "./QueryState.js"
|
export * as QueryState from "./QueryState.js"
|
||||||
|
|||||||
Reference in New Issue
Block a user