From 2e8dfbc988ad3d03d5ffc5194442fe942575fa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Valverd=C3=A9?= Date: Fri, 14 Mar 2025 22:00:53 +0100 Subject: [PATCH] QueryClient --- packages/extension-query/src/ErrorHandler.ts | 6 +-- packages/extension-query/src/QueryClient.ts | 10 ++-- .../extension-query/src/QueryExtension.ts | 5 +- packages/extension-query/src/QueryRunner.ts | 46 ++++++++++++------- packages/extension-query/src/index.ts | 2 + 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/packages/extension-query/src/ErrorHandler.ts b/packages/extension-query/src/ErrorHandler.ts index 1975a25..f602f62 100644 --- a/packages/extension-query/src/ErrorHandler.ts +++ b/packages/extension-query/src/ErrorHandler.ts @@ -3,7 +3,7 @@ import { type Cause, type Context, Effect, Layer, Queue, Stream } from "effect" export interface ErrorHandler { readonly errors: Stream.Stream> - readonly handle: (self: Effect.Effect) => Effect.Effect + readonly handle: (self: Effect.Effect) => Effect.Effect, R> } export const Tag = (id: Id) => < @@ -17,10 +17,10 @@ export const layer = ( const errors = Stream.fromQueue(queue) const handle = ( - self: Effect.Effect + self: Effect.Effect ) => Effect.tapErrorCause(self, cause => Queue.offer(queue, cause as Cause.Cause) - ) as Effect.Effect + ) as Effect.Effect, R> return { errors, handle } })) diff --git a/packages/extension-query/src/QueryClient.ts b/packages/extension-query/src/QueryClient.ts index 76ea7b4..c2f90d0 100644 --- a/packages/extension-query/src/QueryClient.ts +++ b/packages/extension-query/src/QueryClient.ts @@ -6,13 +6,9 @@ export interface QueryClient { readonly ErrorHandler: Context.Tag> } -export const makeTag = < - EH = never, - HandledE = never, ->(): Context.Tag< - QueryClient, - QueryClient -> => Context.GenericTag("@reffuse/extension-query/QueryClient") + +export type Tag = Context.Tag, QueryClient> +export const makeTag = (): Tag => Context.GenericTag("@reffuse/extension-query/QueryClient") export interface LayerProps { diff --git a/packages/extension-query/src/QueryExtension.ts b/packages/extension-query/src/QueryExtension.ts index fa79845..606ce22 100644 --- a/packages/extension-query/src/QueryExtension.ts +++ b/packages/extension-query/src/QueryExtension.ts @@ -2,7 +2,7 @@ import type * as AsyncData from "@typed/async-data" import { type Cause, type Context, Effect, type Fiber, Layer, type Option, type Stream, type SubscriptionRef } from "effect" import * as React from "react" import { ReffuseExtension, type ReffuseHelpers } from "reffuse" -import type * as QueryClient from "./QueryClient.js" +import * as QueryClient from "./QueryClient.js" import * as QueryRunner from "./QueryRunner.js" import type * as QueryService from "./QueryService.js" @@ -26,10 +26,11 @@ export interface UseQueryResult { export const QueryExtension = ReffuseExtension.make(() => ({ useQuery( - this: ReffuseHelpers.ReffuseHelpers>, + this: ReffuseHelpers.ReffuseHelpers | EH>, props: UseQueryProps, ): UseQueryResult> { const runner = this.useMemo(() => QueryRunner.make({ + QueryClient: QueryClient.makeTag(), key: props.key, query: props.query, }), [props.key]) diff --git a/packages/extension-query/src/QueryRunner.ts b/packages/extension-query/src/QueryRunner.ts index c1401ba..46ec4a4 100644 --- a/packages/extension-query/src/QueryRunner.ts +++ b/packages/extension-query/src/QueryRunner.ts @@ -1,10 +1,11 @@ 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 { type Cause, type Context, Effect, Fiber, identity, Option, Ref, type Scope, Stream, SubscriptionRef } from "effect" +import type * as QueryClient from "./QueryClient.js" export interface QueryRunner { - readonly query: (key: K) => Effect.Effect + readonly context: Context.Context readonly latestKeyRef: SubscriptionRef.SubscriptionRef> readonly stateRef: SubscriptionRef.SubscriptionRef> @@ -19,18 +20,27 @@ export interface QueryRunner { } -export interface MakeProps { +export interface MakeProps { + readonly QueryClient: QueryClient.Tag readonly key: Stream.Stream readonly query: (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, + key, + query, + }: MakeProps +): Effect.Effect< + QueryRunner, R>, + never, + R | QueryClient.QueryClient | EH +> => Effect.gen(function*() { + const context = yield* Effect.context | EH>() const latestKeyRef = yield* SubscriptionRef.make(Option.none()) - const stateRef = yield* SubscriptionRef.make(AsyncData.noData()) + const stateRef = yield* SubscriptionRef.make(AsyncData.noData>()) const fiberRef = yield* SubscriptionRef.make(Option.none>()) const interrupt = fiberRef.pipe( @@ -54,13 +64,17 @@ export const make = ( })) ) - const run = latestKeyRef.pipe( - 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)), - }) + const run = QueryClient.pipe( + Effect.flatMap(client => client.ErrorHandler), + Effect.flatMap(errorHandler => latestKeyRef.pipe( + Effect.flatMap(identity), + Effect.flatMap(key => query(key).pipe( + errorHandler.handle, + Effect.matchCauseEffect({ + onSuccess: v => Ref.set(stateRef, AsyncData.success(v)), + onFailure: c => Ref.set(stateRef, AsyncData.failure(c)), + }), + )), )), Effect.provide(context), @@ -118,7 +132,7 @@ export const make = ( ) return { - query, + context, latestKeyRef, stateRef, diff --git a/packages/extension-query/src/index.ts b/packages/extension-query/src/index.ts index 790fe0c..bbf2696 100644 --- a/packages/extension-query/src/index.ts +++ b/packages/extension-query/src/index.ts @@ -1,3 +1,5 @@ +export * as ErrorHandler from "./ErrorHandler.js" +export * as QueryClient from "./QueryClient.js" export * from "./QueryExtension.js" export * as QueryRunner from "./QueryRunner.js" export * as QueryService from "./QueryService.js"