diff --git a/packages/extension-query/src/MutationRunner.ts b/packages/extension-query/src/MutationRunner.ts index 9eb1cb9..881966c 100644 --- a/packages/extension-query/src/MutationRunner.ts +++ b/packages/extension-query/src/MutationRunner.ts @@ -1,134 +1,47 @@ -// import { BrowserStream } from "@effect/platform-browser" -// import * as AsyncData from "@typed/async-data" -// import { type Cause, Effect, Fiber, identity, Option, Ref, type Scope, Stream, SubscriptionRef } from "effect" +import * as AsyncData from "@typed/async-data" +import { type Context, Effect, Ref, SubscriptionRef } from "effect" +import type * as QueryClient from "./QueryClient.js" -// export interface MutationRunner { -// readonly mutation: (...args: K) => Effect.Effect - -// readonly stateRef: SubscriptionRef.SubscriptionRef> - -// readonly forkMutate: Effect.Effect> -// } +export interface MutationRunner { + readonly context: Context.Context + readonly stateRef: SubscriptionRef.SubscriptionRef> + readonly mutate: (...key: K) => Effect.Effect +} -// export interface MakeProps { -// readonly mutation: (...args: K) => Effect.Effect -// } +export interface MakeProps { + readonly QueryClient: QueryClient.GenericTagClass + readonly mutation: (...key: K) => Effect.Effect +} -// export const make = ( -// { key, query }: MakeProps -// ): Effect.Effect, never, R> => Effect.gen(function*() { -// const context = yield* Effect.context() +export const make = ( + { + QueryClient, + mutation, + }: MakeProps +): Effect.Effect< + MutationRunner, R>, + never, + R | QueryClient.TagClassShape | EH +> => Effect.gen(function*() { + const context = yield* Effect.context | EH>() + const stateRef = yield* SubscriptionRef.make(AsyncData.noData>()) -// const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) + const mutate = (...key: K) => QueryClient.pipe( + Effect.flatMap(client => client.ErrorHandler), + Effect.flatMap(errorHandler => mutation(...key).pipe( + errorHandler.handle, + Effect.tapErrorCause(c => Ref.set(stateRef, AsyncData.failure(c))), + Effect.tap(v => Ref.set(stateRef, AsyncData.success(v))), + )), -// const interrupt = fiberRef.pipe( -// Effect.flatMap(Option.match({ -// onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( -// Effect.andThen(Fiber.interrupt(fiber)) -// ), -// onNone: () => Effect.void, -// })) -// ) + Effect.provide(context), + ) -// const forkInterrupt = fiberRef.pipe( -// Effect.flatMap(Option.match({ -// onSome: fiber => Ref.set(fiberRef, Option.none()).pipe( -// Effect.andThen(Fiber.interrupt(fiber).pipe( -// Effect.asVoid, -// Effect.forkDaemon, -// )) -// ), -// onNone: () => Effect.forkDaemon(Effect.void), -// })) -// ) - -// const forkFetch = interrupt.pipe( -// Effect.andThen( -// Ref.set(stateRef, AsyncData.loading()).pipe( -// Effect.andThen(latestKeyRef), -// Effect.flatMap(identity), -// Effect.flatMap(key => query(key).pipe( -// Effect.matchCauseEffect({ -// onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), -// onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), -// }) -// )), - -// Effect.provide(context), -// Effect.fork, -// ) -// ), - -// Effect.flatMap(fiber => -// Ref.set(fiberRef, Option.some(fiber)).pipe( -// Effect.andThen(Fiber.join(fiber)), -// Effect.andThen(Ref.set(fiberRef, Option.none())), -// ) -// ), - -// Effect.forkDaemon, -// ) - -// const forkRefresh = interrupt.pipe( -// Effect.andThen( -// Ref.update(stateRef, previous => { -// if (AsyncData.isSuccess(previous) || AsyncData.isFailure(previous)) -// return AsyncData.refreshing(previous) -// if (AsyncData.isRefreshing(previous)) -// return AsyncData.refreshing(previous.previous) -// return AsyncData.loading() -// }).pipe( -// Effect.andThen(latestKeyRef), -// Effect.flatMap(identity), -// Effect.flatMap(key => query(key).pipe( -// Effect.matchCauseEffect({ -// onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), -// onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), -// }) -// )), - -// Effect.provide(context), -// Effect.fork, -// ) -// ), - -// Effect.flatMap(fiber => -// Ref.set(fiberRef, Option.some(fiber)).pipe( -// Effect.andThen(Fiber.join(fiber)), -// Effect.andThen(Ref.set(fiberRef, Option.none())), -// ) -// ), - -// Effect.forkDaemon, -// ) - -// const fetchOnKeyChange = Effect.addFinalizer(() => interrupt).pipe( -// Effect.andThen(Stream.runForEach(key, latestKey => -// Ref.set(latestKeyRef, Option.some(latestKey)).pipe( -// Effect.andThen(forkFetch) -// ) -// )) -// ) - -// const refreshOnWindowFocus = Stream.runForEach( -// BrowserStream.fromEventListenerWindow("focus"), -// () => forkRefresh, -// ) - -// return { -// query, - -// latestKeyRef, -// stateRef, -// fiberRef, - -// forkInterrupt, -// forkFetch, -// forkRefresh, - -// fetchOnKeyChange, -// refreshOnWindowFocus, -// } -// }) + return { + context, + stateRef, + mutate, + } +})