@effect-app/vue 1.25.2 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/query2.ts ADDED
@@ -0,0 +1,231 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
5
+ import { isHttpRequestError, isHttpResponseError } from "@effect-app/core/http/http-client"
6
+ import * as Result from "@effect-rx/rx/Result"
7
+ import type {
8
+ QueryKey,
9
+ QueryObserverOptions,
10
+ QueryObserverResult,
11
+ RefetchOptions,
12
+ UseQueryReturnType
13
+ } from "@tanstack/vue-query"
14
+ import { useQuery } from "@tanstack/vue-query"
15
+ import { Cause, Effect, Option, Runtime, S } from "effect-app"
16
+ import { ServiceUnavailableError } from "effect-app/client"
17
+ import { computed, ref } from "vue"
18
+ import type { ComputedRef, Ref, WatchSource } from "vue"
19
+ import { makeQueryKey, reportRuntimeError } from "./internal.js"
20
+
21
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
22
+ export interface QueryObserverOptionsCustom<
23
+ TQueryFnData = unknown,
24
+ TError = Error,
25
+ TData = TQueryFnData,
26
+ TQueryData = TQueryFnData,
27
+ TQueryKey extends QueryKey = QueryKey,
28
+ TPageParam = never
29
+ > extends
30
+ Omit<QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey, TPageParam>, "queryKey" | "queryFn">
31
+ {}
32
+
33
+ export interface KnownFiberFailure<E> extends Runtime.FiberFailure {
34
+ readonly [Runtime.FiberFailureCauseId]: Cause.Cause<E>
35
+ }
36
+
37
+ export const makeQuery2 = <R>(runtime: Ref<Runtime.Runtime<R>>) => {
38
+ // TODO: options
39
+ // declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): UseQueryReturnType<TData, TError>;
40
+ // declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>, queryClient?: QueryClient): UseQueryDefinedReturnType<TData, TError>;
41
+ // declare function useQuery<TQueryFnData = unknown, TError = DefaultError, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey>(options: UseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, queryClient?: QueryClient): UseQueryReturnType<TData, TError>;
42
+ const useSafeQuery_ = <I, A, E>(
43
+ q:
44
+ | {
45
+ readonly handler: (
46
+ req: I
47
+ ) => Effect<
48
+ A,
49
+ E,
50
+ R
51
+ >
52
+ mapPath: (req: I) => string
53
+ name: string
54
+ }
55
+ | {
56
+ readonly handler: Effect<
57
+ A,
58
+ E,
59
+ R
60
+ >
61
+ mapPath: string
62
+ name: string
63
+ },
64
+ arg?: I | WatchSource<I>,
65
+ options: QueryObserverOptionsCustom<unknown, KnownFiberFailure<E>, A> = {} // TODO
66
+ ) => {
67
+ const runPromise = Runtime.runPromise(runtime.value)
68
+ const arr = arg
69
+ const req: { value: I } = !arg
70
+ ? undefined
71
+ : typeof arr === "function"
72
+ ? ({
73
+ get value() {
74
+ return (arr as any)()
75
+ }
76
+ } as any)
77
+ : ref(arg)
78
+ const queryKey = makeQueryKey(q.name)
79
+ const handler = q.handler
80
+ const r = useQuery<unknown, KnownFiberFailure<E>, A>(
81
+ Effect.isEffect(handler)
82
+ ? {
83
+ ...options,
84
+ retry: (retryCount, error) => {
85
+ if (Runtime.isFiberFailure(error)) {
86
+ const cause = error[Runtime.FiberFailureCauseId]
87
+ const sq = Cause.squash(cause)
88
+ if (!isHttpRequestError(sq) && !isHttpResponseError(sq) && !S.is(ServiceUnavailableError)(sq)) {
89
+ return false
90
+ }
91
+ }
92
+
93
+ return retryCount < 5
94
+ },
95
+ queryKey,
96
+ queryFn: ({ signal }) =>
97
+ runPromise(
98
+ handler
99
+ .pipe(
100
+ Effect.tapDefect(reportRuntimeError),
101
+ Effect.withSpan(`query ${q.name}`, { captureStackTrace: false })
102
+ ),
103
+ { signal }
104
+ )
105
+ }
106
+ : {
107
+ ...options,
108
+ retry: (retryCount, error) => {
109
+ if (Runtime.isFiberFailure(error)) {
110
+ const cause = error[Runtime.FiberFailureCauseId]
111
+ const sq = Cause.squash(cause)
112
+ if (!isHttpRequestError(sq) && !isHttpResponseError(sq) && !S.is(ServiceUnavailableError)(sq)) {
113
+ return false
114
+ }
115
+ }
116
+
117
+ return retryCount < 5
118
+ },
119
+ queryKey: [...queryKey, req],
120
+ queryFn: ({ signal }) =>
121
+ runPromise(
122
+ handler(req.value)
123
+ .pipe(
124
+ Effect.tapDefect(reportRuntimeError),
125
+ Effect.withSpan(`query ${q.name}`, { captureStackTrace: false })
126
+ ),
127
+ { signal }
128
+ )
129
+ }
130
+ )
131
+
132
+ const result = computed(() =>
133
+ swrToQuery({
134
+ error: r.error.value ?? undefined,
135
+ data: r.data.value,
136
+ isValidating: r.isFetching.value
137
+ })
138
+ )
139
+ const latestSuccess = computed(() => Option.getOrUndefined(Result.value(result.value)))
140
+ return [
141
+ result,
142
+ latestSuccess,
143
+ // one thing to keep in mind is that span will be disconnected as Context does not pass from outside.
144
+ (options?: RefetchOptions) => Effect.promise(() => r.refetch(options)),
145
+ r
146
+ ] as const
147
+ }
148
+
149
+ function swrToQuery<E, A>(r: {
150
+ error: KnownFiberFailure<E> | undefined
151
+ data: A | undefined
152
+ isValidating: boolean
153
+ }): Result.Result<A, E> {
154
+ if (r.error) {
155
+ return Result.failureWithPrevious(
156
+ r.error[Runtime.FiberFailureCauseId],
157
+ r.data === undefined ? Option.none() : Option.some(Result.success(r.data)),
158
+ r.isValidating
159
+ )
160
+ }
161
+ if (r.data !== undefined) {
162
+ return Result.success<A, E>(r.data, r.isValidating)
163
+ }
164
+
165
+ return Result.initial(r.isValidating)
166
+ }
167
+
168
+ function useSafeQuery<E, A>(
169
+ self: {
170
+ handler: Effect<A, E, R>
171
+ mapPath: string
172
+ name: string
173
+ },
174
+ options?: QueryObserverOptionsCustom // TODO
175
+ ): readonly [
176
+ ComputedRef<Result.Result<A, E>>,
177
+ ComputedRef<A | undefined>,
178
+ (options?: RefetchOptions) => Effect<QueryObserverResult<A, KnownFiberFailure<E>>>,
179
+ UseQueryReturnType<any, any>
180
+ ]
181
+ function useSafeQuery<Arg, E, A>(
182
+ self: {
183
+ handler: (arg: Arg) => Effect<A, E, R>
184
+ mapPath: (arg: Arg) => string
185
+ name: string
186
+ },
187
+ arg: Arg | WatchSource<Arg>,
188
+ options?: QueryObserverOptionsCustom // TODO
189
+ ): readonly [
190
+ ComputedRef<Result.Result<A, E>>,
191
+ ComputedRef<A | undefined>,
192
+ (options?: RefetchOptions) => Effect<QueryObserverResult<A, KnownFiberFailure<E>>>,
193
+ UseQueryReturnType<any, any>
194
+ ]
195
+ function useSafeQuery(
196
+ self: any,
197
+ /*
198
+ q:
199
+ | {
200
+ handler: (
201
+ req: I
202
+ ) => Effect<
203
+ A,
204
+ E,
205
+ R
206
+ >
207
+ mapPath: (req: I) => string
208
+ name: string
209
+ }
210
+ | {
211
+ handler: Effect<
212
+ A,
213
+ E,
214
+ R
215
+ >
216
+ mapPath: string
217
+ name: string
218
+ },
219
+ */
220
+ argOrOptions?: any,
221
+ options?: any
222
+ ) {
223
+ return Effect.isEffect(self.handler)
224
+ ? useSafeQuery_(self, undefined, argOrOptions)
225
+ : useSafeQuery_(self, argOrOptions, options)
226
+ }
227
+ return useSafeQuery
228
+ }
229
+
230
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
231
+ export interface MakeQuery2<R> extends ReturnType<typeof makeQuery2<R>> {}