7 Commits

Author SHA1 Message Date
Julien Valverdé
e9e17ac211 Fix
All checks were successful
Lint / lint (push) Successful in 12s
2025-03-16 04:11:25 +01:00
Julien Valverdé
1f0ff725ff Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 04:05:39 +01:00
Julien Valverdé
447d89982c Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 03:34:54 +01:00
Julien Valverdé
778ee27795 ErrorHandler refactoring
All checks were successful
Lint / lint (push) Successful in 16s
2025-03-16 03:33:01 +01:00
Julien Valverdé
077816efb6 Fix
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 03:23:12 +01:00
Julien Valverdé
e4bacd1ca7 Working QueryClient refactoring
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 03:19:12 +01:00
Julien Valverdé
0e2c0db28f QueryClient refactoring
All checks were successful
Lint / lint (push) Successful in 13s
2025-03-16 02:52:49 +01:00
7 changed files with 57 additions and 63 deletions

View File

@@ -5,7 +5,7 @@ import { Layer } from "effect"
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import { ReffuseRuntime } from "reffuse"
import { AppQueryClientLive, AppQueryErrorHandlerLive } from "./query"
import { AppQueryClient, AppQueryErrorHandler } from "./query"
import { GlobalContext } from "./reffuse"
import { routeTree } from "./routeTree.gen"
@@ -15,8 +15,8 @@ const layer = Layer.empty.pipe(
Layer.provideMerge(Geolocation.layer),
Layer.provideMerge(Permissions.layer),
Layer.provideMerge(FetchHttpClient.layer),
Layer.provideMerge(AppQueryClientLive),
Layer.provideMerge(AppQueryErrorHandlerLive),
Layer.provideMerge(AppQueryClient.Live),
Layer.provideMerge(AppQueryErrorHandler.Live),
)
const router = createRouter({ routeTree })

View File

@@ -2,9 +2,8 @@ import { HttpClientError } from "@effect/platform"
import { ErrorHandler, QueryClient } from "@reffuse/extension-query"
export class AppQueryErrorHandler extends ErrorHandler.Tag("AppQueryErrorHandler")<AppQueryErrorHandler,
export class AppQueryErrorHandler extends ErrorHandler.Service("AppQueryErrorHandler")<AppQueryErrorHandler,
HttpClientError.HttpClientError
>() {}
export const AppQueryErrorHandlerLive = ErrorHandler.layer(AppQueryErrorHandler)
export const [AppQueryClient, AppQueryClientLive] = QueryClient.make({ ErrorHandler: AppQueryErrorHandler })
export class AppQueryClient extends QueryClient.Service({ ErrorHandler: AppQueryErrorHandler })<AppQueryClient>() {}

View File

@@ -2,7 +2,6 @@ import { HttpClient } from "@effect/platform"
import { Clipboard, Geolocation, Permissions } from "@effect/platform-browser"
import { LazyRefExtension } from "@reffuse/extension-lazyref"
import { QueryExtension } from "@reffuse/extension-query"
import { Context } from "effect"
import { Reffuse, ReffuseContext } from "reffuse"
import { AppQueryClient, AppQueryErrorHandler } from "./query"
@@ -12,7 +11,7 @@ export const GlobalContext = ReffuseContext.make<
| Geolocation.Geolocation
| Permissions.Permissions
| HttpClient.HttpClient
| Context.Tag.Service<typeof AppQueryClient>
| AppQueryClient
| AppQueryErrorHandler
>()

View File

@@ -1,4 +1,5 @@
import { type Cause, type Context, Effect, Layer, Queue, Stream } from "effect"
import { type Cause, Context, Effect, Layer, Queue, Stream } from "effect"
import type { Mutable } from "effect/Types"
export interface ErrorHandler<E> {
@@ -9,13 +10,14 @@ export interface ErrorHandler<E> {
export type Error<T> = T extends ErrorHandler<infer E> ? E : never
export const Tag = <const Id extends string>(id: Id) => <
Self, E = never,
>() => Effect.Tag(id)<Self, ErrorHandler<E>>()
export interface ServiceResult<Self, Id extends string, E> extends Context.TagClass<Self, Id, ErrorHandler<E>> {
readonly Live: Layer.Layer<Self>
}
export const layer = <Self, Id extends string, E>(
tag: Context.TagClass<Self, Id, ErrorHandler<E>>
): Layer.Layer<Self> => Layer.effect(tag, Effect.gen(function*() {
export const Service = <const Id extends string>(id: Id) => (
<Self, E = never>(): ServiceResult<Self, Id, E> => {
const TagClass = Context.Tag(id)() as ServiceResult<Self, Id, E>
(TagClass as Mutable<typeof TagClass>).Live = Layer.effect(TagClass, Effect.gen(function*() {
const queue = yield* Queue.unbounded<Cause.Cause<E>>()
const errors = Stream.fromQueue(queue)
@@ -26,8 +28,10 @@ export const layer = <Self, Id extends string, E>(
) as Effect.Effect<A, Exclude<SelfE, E>, R>
return { errors, handle }
}))
}))
return TagClass
}
)
export class DefaultErrorHandler extends Tag("@reffuse/extension-query/DefaultErrorHandler")<DefaultErrorHandler>() {}
export const DefaultErrorHandlerLive = layer(DefaultErrorHandler)
export class DefaultErrorHandler extends Service("@reffuse/extension-query/DefaultErrorHandler")<DefaultErrorHandler>() {}

View File

@@ -1,4 +1,5 @@
import { Context, Effect, Layer } from "effect"
import { Context, Layer } from "effect"
import type { Mutable } from "effect/Types"
import * as ErrorHandler from "./ErrorHandler.js"
@@ -6,42 +7,33 @@ export interface QueryClient<EH, HandledE> {
readonly ErrorHandler: Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>>
}
export type Tag<EH, HandledE> = Context.Tag<QueryClient<EH, HandledE>, QueryClient<EH, HandledE>>
export const makeTag = <EH = never, HandledE = never>(): Tag<EH, HandledE> => Context.GenericTag("@reffuse/extension-query/QueryClient")
const id = "@reffuse/extension-query/QueryClient"
export type TagClassShape<EH, HandledE> = Context.TagClassShape<typeof id, QueryClient<EH, HandledE>>
export type GenericTagClass<EH, HandledE> = Context.TagClass<TagClassShape<EH, HandledE>, typeof id, QueryClient<EH, HandledE>>
export const makeGenericTagClass = <EH = never, HandledE = never>(): GenericTagClass<EH, HandledE> => Context.Tag(id)()
export interface MakeProps<EH, HandledE> {
export interface ServiceProps<EH, HandledE> {
readonly ErrorHandler?: Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>>
}
export type MakeResult<EH, HandledE> = [
tag: Tag<EH, HandledE>,
layer: Layer.Layer<
| QueryClient<EH, HandledE>
| (EH extends ErrorHandler.DefaultErrorHandler
? ErrorHandler.DefaultErrorHandler
: never)
>,
]
export interface ServiceResult<Self, EH, HandledE> extends Context.TagClass<Self, typeof id, QueryClient<EH, HandledE>> {
readonly Live: Layer.Layer<Self>
}
export const make = <
export const Service = <
EH = ErrorHandler.DefaultErrorHandler,
HandledE = never,
HandledE = ErrorHandler.Error<Context.Tag.Service<ErrorHandler.DefaultErrorHandler>>,
>(
props?: MakeProps<EH, HandledE>
): MakeResult<EH, HandledE> => [
makeTag(),
Layer.empty.pipe(
Layer.provideMerge(
Layer.effect(makeTag<EH, HandledE>(), Effect.succeed({
props?: ServiceProps<EH, HandledE>
) => (
<Self>(): ServiceResult<Self, EH, HandledE> => {
const TagClass = Context.Tag(id)() as ServiceResult<Self, EH, HandledE>
(TagClass as Mutable<typeof TagClass>).Live = Layer.succeed(TagClass, {
ErrorHandler: (props?.ErrorHandler ?? ErrorHandler.DefaultErrorHandler) as Context.Tag<EH, ErrorHandler.ErrorHandler<HandledE>>
}))
),
Layer.provideMerge((props?.ErrorHandler
? Layer.empty
: ErrorHandler.DefaultErrorHandlerLive
) as Layer.Layer<ErrorHandler.DefaultErrorHandler>),
),
]
})
return TagClass
}
)

View File

@@ -34,11 +34,11 @@ export const QueryExtension = ReffuseExtension.make(() => ({
QR extends R,
R,
>(
this: ReffuseHelpers.ReffuseHelpers<R | QueryClient.QueryClient<EH, HandledE> | EH>,
this: ReffuseHelpers.ReffuseHelpers<R | QueryClient.TagClassShape<EH, HandledE> | EH>,
props: UseQueryProps<QK, QA, QE, QR>,
): UseQueryResult<QK, QA, Exclude<QE, HandledE>> {
const runner = this.useMemo(() => QueryRunner.make({
QueryClient: QueryClient.makeTag<EH, HandledE>(),
QueryClient: QueryClient.makeGenericTagClass<EH, HandledE>(),
key: props.key,
query: props.query,
}), [props.key])

View File

@@ -21,7 +21,7 @@ export interface QueryRunner<K extends readonly unknown[], A, E, R> {
export interface MakeProps<EH, K extends readonly unknown[], A, E, HandledE, R> {
readonly QueryClient: QueryClient.Tag<EH, HandledE>
readonly QueryClient: QueryClient.GenericTagClass<EH, HandledE>
readonly key: Stream.Stream<K>
readonly query: (key: K) => Effect.Effect<A, E, R>
}
@@ -35,9 +35,9 @@ export const make = <EH, K extends readonly unknown[], A, E, HandledE, R>(
): Effect.Effect<
QueryRunner<K, A, Exclude<E, HandledE>, R>,
never,
R | QueryClient.QueryClient<EH, HandledE> | EH
R | QueryClient.TagClassShape<EH, HandledE> | EH
> => Effect.gen(function*() {
const context = yield* Effect.context<R | QueryClient.QueryClient<EH, HandledE> | EH>()
const context = yield* Effect.context<R | QueryClient.TagClassShape<EH, HandledE> | EH>()
const latestKeyRef = yield* SubscriptionRef.make(Option.none<K>())
const stateRef = yield* SubscriptionRef.make(AsyncData.noData<A, Exclude<E, HandledE>>())