@effect-app/vue 2.94.0 → 4.0.0-beta.1
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/CHANGELOG.md +20 -0
- package/dist/errorReporter.d.ts +2 -2
- package/dist/errorReporter.d.ts.map +1 -1
- package/dist/errorReporter.js +9 -9
- package/dist/experimental/commander.d.ts +49 -69
- package/dist/experimental/commander.d.ts.map +1 -1
- package/dist/experimental/commander.js +27 -29
- package/dist/experimental/confirm.d.ts +11 -5
- package/dist/experimental/confirm.d.ts.map +1 -1
- package/dist/experimental/confirm.js +19 -6
- package/dist/experimental/intl.d.ts +2 -21
- package/dist/experimental/intl.d.ts.map +1 -1
- package/dist/experimental/intl.js +4 -4
- package/dist/experimental/makeUseCommand.js +2 -2
- package/dist/experimental/toast.d.ts +3 -35
- package/dist/experimental/toast.d.ts.map +1 -1
- package/dist/experimental/toast.js +19 -5
- package/dist/experimental/withToast.d.ts +6 -4
- package/dist/experimental/withToast.d.ts.map +1 -1
- package/dist/experimental/withToast.js +10 -8
- package/dist/form.d.ts +2 -2
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +47 -47
- package/dist/lib.d.ts +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +12 -10
- package/dist/makeClient.d.ts +31 -28
- package/dist/makeClient.d.ts.map +1 -1
- package/dist/makeClient.js +31 -32
- package/dist/mutate.d.ts +5 -5
- package/dist/mutate.d.ts.map +1 -1
- package/dist/mutate.js +14 -14
- package/dist/query.d.ts +16 -14
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +37 -28
- package/dist/routeParams.d.ts +2 -4
- package/dist/routeParams.d.ts.map +1 -1
- package/dist/routeParams.js +3 -15
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +4 -4
- package/package.json +19 -20
- package/src/errorReporter.ts +11 -11
- package/src/experimental/commander.ts +83 -86
- package/src/experimental/confirm.ts +21 -6
- package/src/experimental/intl.ts +3 -3
- package/src/experimental/makeUseCommand.ts +1 -1
- package/src/experimental/toast.ts +23 -4
- package/src/experimental/withToast.ts +10 -7
- package/src/form.ts +56 -64
- package/src/lib.ts +11 -9
- package/src/makeClient.ts +70 -63
- package/src/mutate.ts +18 -19
- package/src/query.ts +56 -49
- package/src/routeParams.ts +9 -23
- package/src/runtime.ts +6 -6
- package/test/Mutation.test.ts +52 -53
- package/test/dist/form.test.d.ts.map +1 -1
- package/test/dist/stubs.d.ts +103 -45
- package/test/dist/stubs.d.ts.map +1 -1
- package/test/dist/stubs.js +8 -8
- package/test/form.test.ts +7 -6
- package/test/stubs.ts +43 -41
- package/tsconfig.json +1 -27
package/src/mutate.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import * as
|
|
2
|
+
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
3
3
|
import { type InvalidateOptions, type InvalidateQueryFilters, type QueryClient, useQueryClient } from "@tanstack/vue-query"
|
|
4
4
|
import { type Cause, Effect, type Exit, Option } from "effect-app"
|
|
5
5
|
import { type Req } from "effect-app/client"
|
|
@@ -19,7 +19,7 @@ export const getQueryKey = (h: { id: string; options?: ClientForOptions }) => {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function mutationResultToVue<A, E>(
|
|
22
|
-
mutationResult:
|
|
22
|
+
mutationResult: AsyncResult.AsyncResult<A, E>
|
|
23
23
|
): Res<A, E> {
|
|
24
24
|
switch (mutationResult._tag) {
|
|
25
25
|
case "Initial": {
|
|
@@ -49,20 +49,20 @@ export interface Res<A, E> {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export function make<A, E, R>(self: Effect.Effect<A, E, R>) {
|
|
52
|
-
const result = shallowRef(
|
|
52
|
+
const result = shallowRef(AsyncResult.initial() as AsyncResult.AsyncResult<A, E>)
|
|
53
53
|
|
|
54
54
|
const execute = Effect
|
|
55
55
|
.sync(() => {
|
|
56
|
-
result.value =
|
|
56
|
+
result.value = AsyncResult.waiting(result.value)
|
|
57
57
|
})
|
|
58
58
|
.pipe(
|
|
59
59
|
Effect.andThen(self),
|
|
60
60
|
Effect.exit,
|
|
61
|
-
Effect.
|
|
61
|
+
Effect.map(AsyncResult.fromExit),
|
|
62
62
|
Effect.flatMap((r) => Effect.sync(() => result.value = r))
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
-
const latestSuccess = computed(() => Option.getOrUndefined(
|
|
65
|
+
const latestSuccess = computed(() => Option.getOrUndefined(AsyncResult.value(result.value)))
|
|
66
66
|
|
|
67
67
|
return tuple(result, latestSuccess, execute)
|
|
68
68
|
}
|
|
@@ -103,38 +103,38 @@ export interface MutationOptions<A, E, R, A2 = A, E2 = E, R2 = R, I = void> exte
|
|
|
103
103
|
export const asResult: {
|
|
104
104
|
<A, E, R>(
|
|
105
105
|
handler: Effect.Effect<A, E, R>
|
|
106
|
-
): readonly [ComputedRef<
|
|
106
|
+
): readonly [ComputedRef<AsyncResult.AsyncResult<A, E>>, Effect.Effect<Exit.Exit<A, E>, never, R>]
|
|
107
107
|
<Args extends readonly any[], A, E, R>(
|
|
108
108
|
handler: (...args: Args) => Effect.Effect<A, E, R>
|
|
109
|
-
): readonly [ComputedRef<
|
|
109
|
+
): readonly [ComputedRef<AsyncResult.AsyncResult<A, E>>, (...args: Args) => Effect.Effect<Exit.Exit<A, E>, never, R>]
|
|
110
110
|
} = <Args extends readonly any[], A, E, R>(
|
|
111
111
|
handler: Effect.Effect<A, E, R> | ((...args: Args) => Effect.Effect<A, E, R>)
|
|
112
112
|
) => {
|
|
113
|
-
const state = shallowRef<
|
|
113
|
+
const state = shallowRef<AsyncResult.AsyncResult<A, E>>(AsyncResult.initial())
|
|
114
114
|
|
|
115
115
|
const act = Effect.isEffect(handler)
|
|
116
116
|
? Effect
|
|
117
117
|
.sync(() => {
|
|
118
|
-
state.value =
|
|
118
|
+
state.value = AsyncResult.initial(true)
|
|
119
119
|
})
|
|
120
120
|
.pipe(
|
|
121
|
-
Effect.
|
|
121
|
+
Effect.andThen(Effect.suspend(() =>
|
|
122
122
|
handler.pipe(
|
|
123
123
|
Effect.exit,
|
|
124
|
-
Effect.tap((exit) => Effect.sync(() => (state.value =
|
|
124
|
+
Effect.tap((exit) => Effect.sync(() => (state.value = AsyncResult.fromExit(exit))))
|
|
125
125
|
)
|
|
126
126
|
))
|
|
127
127
|
)
|
|
128
128
|
: (...args: Args) =>
|
|
129
129
|
Effect
|
|
130
130
|
.sync(() => {
|
|
131
|
-
state.value =
|
|
131
|
+
state.value = AsyncResult.initial(true)
|
|
132
132
|
})
|
|
133
133
|
.pipe(
|
|
134
|
-
Effect.
|
|
134
|
+
Effect.andThen(Effect.suspend(() =>
|
|
135
135
|
handler(...args).pipe(
|
|
136
136
|
Effect.exit,
|
|
137
|
-
Effect.tap((exit) => Effect.sync(() => (state.value =
|
|
137
|
+
Effect.tap((exit) => Effect.sync(() => (state.value = AsyncResult.fromExit(exit))))
|
|
138
138
|
)
|
|
139
139
|
))
|
|
140
140
|
)
|
|
@@ -171,7 +171,7 @@ export const invalidateQueries = (
|
|
|
171
171
|
Effect.annotateCurrentSpan({ queryKey, opts }),
|
|
172
172
|
Effect.forEach(opts, (_) => invalidateQueries(_.filters, _.options), { concurrency: "inherit" })
|
|
173
173
|
)
|
|
174
|
-
.pipe(Effect.withSpan("client.query.invalidation", { captureStackTrace: false }))
|
|
174
|
+
.pipe(Effect.withSpan("client.query.invalidation", {}, { captureStackTrace: false }))
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
if (!queryKey) return Effect.void
|
|
@@ -187,12 +187,11 @@ export const invalidateQueries = (
|
|
|
187
187
|
// TODO: should we do this in general on any mutation, regardless of invalidation?
|
|
188
188
|
Effect.sleep(0)
|
|
189
189
|
),
|
|
190
|
-
Effect.withSpan("client.query.invalidation", { captureStackTrace: false })
|
|
190
|
+
Effect.withSpan("client.query.invalidation", {}, { captureStackTrace: false })
|
|
191
191
|
)
|
|
192
192
|
})
|
|
193
193
|
|
|
194
|
-
const handle = <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
|
195
|
-
Effect.tapBoth(self, { onFailure: () => invalidateCache, onSuccess: () => invalidateCache })
|
|
194
|
+
const handle = <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.ensuring(self, invalidateCache)
|
|
196
195
|
|
|
197
196
|
return handle
|
|
198
197
|
}
|
package/src/query.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
5
|
-
import * as
|
|
6
|
-
import { isHttpClientError } from "@effect/platform/HttpClientError"
|
|
5
|
+
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"
|
|
7
6
|
import { type DefaultError, type Enabled, type InitialDataFunction, type NonUndefinedGuard, type PlaceholderDataFunction, type QueryKey, type QueryObserverOptions, type QueryObserverResult, type RefetchOptions, useQuery as useTanstackQuery, useQueryClient, type UseQueryDefinedReturnType, type UseQueryReturnType } from "@tanstack/vue-query"
|
|
8
|
-
import { Array, Cause, Effect,
|
|
7
|
+
import { Array, Cause, Effect, Exit, flow, Option, S, type ServiceMap } from "effect-app"
|
|
9
8
|
import { type Req } from "effect-app/client"
|
|
10
9
|
import type { RequestHandler, RequestHandlerWithInput } from "effect-app/client/clientFor"
|
|
11
10
|
import { ServiceUnavailableError } from "effect-app/client/errors"
|
|
12
11
|
import { type Span } from "effect/Tracer"
|
|
12
|
+
import { isHttpClientError } from "effect/unstable/http/HttpClientError"
|
|
13
13
|
import { computed, type ComputedRef, type MaybeRefOrGetter, ref, shallowRef, watch, type WatchSource } from "vue"
|
|
14
14
|
import { makeQueryKey, reportRuntimeError } from "./lib.js"
|
|
15
15
|
|
|
@@ -74,11 +74,15 @@ export interface CustomDefinedPlaceholderQueryOptions<
|
|
|
74
74
|
| PlaceholderDataFunction<NonFunctionGuard<TQueryData>, TError, NonFunctionGuard<TQueryData>, TQueryKey>
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
export
|
|
78
|
-
readonly
|
|
77
|
+
export class KnownFiberFailure<E> extends Error {
|
|
78
|
+
readonly error: unknown
|
|
79
|
+
constructor(public effectCause: Cause.Cause<E>) {
|
|
80
|
+
super("Query failed with cause: " + Cause.squash(effectCause))
|
|
81
|
+
this.error = Cause.squash(effectCause)
|
|
82
|
+
}
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
export const makeQuery = <R>(getRuntime: () =>
|
|
85
|
+
export const makeQuery = <R>(getRuntime: () => ServiceMap.ServiceMap<R>) => {
|
|
82
86
|
const useQuery_: {
|
|
83
87
|
<I, A, E, Request extends Req, Name extends string>(
|
|
84
88
|
q:
|
|
@@ -89,7 +93,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
89
93
|
arg: I | WatchSource<I> | undefined,
|
|
90
94
|
options?: CustomUndefinedInitialQueryOptions<A, E, TData>
|
|
91
95
|
): readonly [
|
|
92
|
-
ComputedRef<
|
|
96
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
93
97
|
ComputedRef<TData | undefined>,
|
|
94
98
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>, never, never>,
|
|
95
99
|
UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
|
|
@@ -99,7 +103,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
99
103
|
arg: I | WatchSource<I> | undefined,
|
|
100
104
|
options: CustomDefinedInitialQueryOptions<A, E, TData>
|
|
101
105
|
): readonly [
|
|
102
|
-
ComputedRef<
|
|
106
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
103
107
|
ComputedRef<TData>,
|
|
104
108
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>, never, never>,
|
|
105
109
|
UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
|
|
@@ -109,7 +113,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
109
113
|
arg: I | WatchSource<I> | undefined,
|
|
110
114
|
options: CustomDefinedPlaceholderQueryOptions<A, E, TData>
|
|
111
115
|
): readonly [
|
|
112
|
-
ComputedRef<
|
|
116
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
113
117
|
ComputedRef<TData>,
|
|
114
118
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>, never, never>,
|
|
115
119
|
UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
|
|
@@ -126,7 +130,14 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
126
130
|
options?: any
|
|
127
131
|
// TODO
|
|
128
132
|
) => {
|
|
129
|
-
|
|
133
|
+
// we wrap into KnownFiberFailure because we want to keep the full cause of the failure.
|
|
134
|
+
const runPromise = flow(Effect.runPromiseExitWith(getRuntime()), (_) =>
|
|
135
|
+
_.then(
|
|
136
|
+
Exit.match({
|
|
137
|
+
onFailure: (cause) => Promise.reject(new KnownFiberFailure(cause)),
|
|
138
|
+
onSuccess: (value) => Promise.resolve(value)
|
|
139
|
+
})
|
|
140
|
+
))
|
|
130
141
|
const arr = arg
|
|
131
142
|
const req: { value: I } = !arg
|
|
132
143
|
? undefined
|
|
@@ -145,10 +156,8 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
145
156
|
? {
|
|
146
157
|
...options,
|
|
147
158
|
retry: (retryCount, error) => {
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
const sq = Cause.squash(cause)
|
|
151
|
-
if (!isHttpClientError(sq) && !S.is(ServiceUnavailableError)(sq)) {
|
|
159
|
+
if (error instanceof KnownFiberFailure) {
|
|
160
|
+
if (!isHttpClientError(error.error) && !S.is(ServiceUnavailableError)(error.error)) {
|
|
152
161
|
return false
|
|
153
162
|
}
|
|
154
163
|
}
|
|
@@ -160,8 +169,8 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
160
169
|
runPromise(
|
|
161
170
|
handler
|
|
162
171
|
.pipe(
|
|
163
|
-
Effect.
|
|
164
|
-
Effect.withSpan(`query ${q.id}`, { captureStackTrace: false }),
|
|
172
|
+
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause)),
|
|
173
|
+
Effect.withSpan(`query ${q.id}`, {}, { captureStackTrace: false }),
|
|
165
174
|
meta?.["span"] ? Effect.withParentSpan(meta["span"] as Span) : (_) => _
|
|
166
175
|
),
|
|
167
176
|
{ signal }
|
|
@@ -170,10 +179,8 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
170
179
|
: {
|
|
171
180
|
...options,
|
|
172
181
|
retry: (retryCount, error) => {
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
const sq = Cause.squash(cause)
|
|
176
|
-
if (!isHttpClientError(sq) && !S.is(ServiceUnavailableError)(sq)) {
|
|
182
|
+
if (error instanceof KnownFiberFailure) {
|
|
183
|
+
if (!isHttpClientError(error.error) && !S.is(ServiceUnavailableError)(error.error)) {
|
|
177
184
|
return false
|
|
178
185
|
}
|
|
179
186
|
}
|
|
@@ -185,8 +192,8 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
185
192
|
runPromise(
|
|
186
193
|
handler(req.value)
|
|
187
194
|
.pipe(
|
|
188
|
-
Effect.
|
|
189
|
-
Effect.withSpan(`query ${q.id}`, { captureStackTrace: false }),
|
|
195
|
+
Effect.tapCauseIf(Cause.hasDies, (cause) => reportRuntimeError(cause)),
|
|
196
|
+
Effect.withSpan(`query ${q.id}`, {}, { captureStackTrace: false }),
|
|
190
197
|
meta?.["span"] ? Effect.withParentSpan(meta["span"] as Span) : (_) => _
|
|
191
198
|
),
|
|
192
199
|
{ signal }
|
|
@@ -195,7 +202,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
195
202
|
)
|
|
196
203
|
|
|
197
204
|
const latestSuccess = shallowRef<TData>()
|
|
198
|
-
const result = computed(():
|
|
205
|
+
const result = computed((): AsyncResult.AsyncResult<TData, E> =>
|
|
199
206
|
swrToQuery({
|
|
200
207
|
error: r.error.value ?? undefined,
|
|
201
208
|
data: r.data.value === undefined ? latestSuccess.value : r.data.value, // we fall back to existing data, as tanstack query might loose it when the key changes
|
|
@@ -203,13 +210,13 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
203
210
|
})
|
|
204
211
|
)
|
|
205
212
|
// not using `computed` here as we have a circular dependency
|
|
206
|
-
watch(result, (value) => latestSuccess.value = Option.getOrUndefined(
|
|
213
|
+
watch(result, (value) => latestSuccess.value = Option.getOrUndefined(AsyncResult.value(value)), { immediate: true })
|
|
207
214
|
|
|
208
215
|
return [
|
|
209
216
|
result,
|
|
210
217
|
computed(() => latestSuccess.value),
|
|
211
218
|
// one thing to keep in mind is that span will be disconnected as Context does not pass from outside.
|
|
212
|
-
// TODO: consider how we should handle the Result here which is `QueryObserverResult<A,
|
|
219
|
+
// TODO: consider how we should handle the Result here which is `QueryObserverResult<A, E>`
|
|
213
220
|
// and always ends up in the success channel, even when error..
|
|
214
221
|
(options?: RefetchOptions) =>
|
|
215
222
|
Effect.currentSpan.pipe(
|
|
@@ -224,21 +231,21 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
224
231
|
error: KnownFiberFailure<E> | undefined
|
|
225
232
|
data: A | undefined
|
|
226
233
|
isValidating: boolean
|
|
227
|
-
}):
|
|
228
|
-
if (r.error) {
|
|
229
|
-
return
|
|
230
|
-
r.error
|
|
234
|
+
}): AsyncResult.AsyncResult<A, E> {
|
|
235
|
+
if (r.error !== undefined) {
|
|
236
|
+
return AsyncResult.failureWithPrevious(
|
|
237
|
+
r.error.effectCause,
|
|
231
238
|
{
|
|
232
|
-
previous: r.data === undefined ? Option.none() : Option.some(
|
|
239
|
+
previous: r.data === undefined ? Option.none() : Option.some(AsyncResult.success(r.data)),
|
|
233
240
|
waiting: r.isValidating
|
|
234
241
|
}
|
|
235
242
|
)
|
|
236
243
|
}
|
|
237
244
|
if (r.data !== undefined) {
|
|
238
|
-
return
|
|
245
|
+
return AsyncResult.success<A, E>(r.data, { waiting: r.isValidating })
|
|
239
246
|
}
|
|
240
247
|
|
|
241
|
-
return
|
|
248
|
+
return AsyncResult.initial(r.isValidating)
|
|
242
249
|
}
|
|
243
250
|
|
|
244
251
|
const useQuery: {
|
|
@@ -256,7 +263,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
256
263
|
<TData = A>(
|
|
257
264
|
options: CustomDefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
|
|
258
265
|
): readonly [
|
|
259
|
-
ComputedRef<
|
|
266
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
260
267
|
ComputedRef<TData>,
|
|
261
268
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
262
269
|
UseQueryReturnType<any, any>
|
|
@@ -264,7 +271,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
264
271
|
<TData = A>(
|
|
265
272
|
options: CustomDefinedPlaceholderQueryOptions<A, E, TData>
|
|
266
273
|
): readonly [
|
|
267
|
-
ComputedRef<
|
|
274
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
268
275
|
ComputedRef<TData>,
|
|
269
276
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>, never, never>,
|
|
270
277
|
UseQueryDefinedReturnType<TData, KnownFiberFailure<E>>
|
|
@@ -274,7 +281,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
274
281
|
* Effect results are passed to the caller, including errors.
|
|
275
282
|
*/
|
|
276
283
|
<TData = A>(options?: CustomUndefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>): readonly [
|
|
277
|
-
ComputedRef<
|
|
284
|
+
ComputedRef<AsyncResult.AsyncResult<A, E>>,
|
|
278
285
|
ComputedRef<A | undefined>,
|
|
279
286
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
280
287
|
UseQueryReturnType<any, any>
|
|
@@ -295,7 +302,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
295
302
|
arg: Arg | WatchSource<Arg>,
|
|
296
303
|
options: CustomDefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
|
|
297
304
|
): readonly [
|
|
298
|
-
ComputedRef<
|
|
305
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
299
306
|
ComputedRef<TData>,
|
|
300
307
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
301
308
|
UseQueryReturnType<any, any>
|
|
@@ -308,7 +315,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
308
315
|
arg: Arg | WatchSource<Arg>,
|
|
309
316
|
options: CustomDefinedPlaceholderQueryOptions<A, KnownFiberFailure<E>, TData>
|
|
310
317
|
): readonly [
|
|
311
|
-
ComputedRef<
|
|
318
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
312
319
|
ComputedRef<TData>,
|
|
313
320
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
314
321
|
UseQueryReturnType<any, any>
|
|
@@ -321,7 +328,7 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
321
328
|
arg: Arg | WatchSource<Arg>,
|
|
322
329
|
options?: CustomUndefinedInitialQueryOptions<A, KnownFiberFailure<E>, TData>
|
|
323
330
|
): readonly [
|
|
324
|
-
ComputedRef<
|
|
331
|
+
ComputedRef<AsyncResult.AsyncResult<TData, E>>,
|
|
325
332
|
ComputedRef<TData | undefined>,
|
|
326
333
|
(options?: RefetchOptions) => Effect.Effect<QueryObserverResult<TData, KnownFiberFailure<E>>>,
|
|
327
334
|
UseQueryReturnType<any, any>
|
|
@@ -343,31 +350,31 @@ export const makeQuery = <R>(getRuntime: () => Runtime.Runtime<R>) => {
|
|
|
343
350
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
344
351
|
export interface MakeQuery2<R> extends ReturnType<typeof makeQuery<R>> {}
|
|
345
352
|
|
|
346
|
-
function orPrevious<E, A>(result:
|
|
347
|
-
return
|
|
348
|
-
?
|
|
353
|
+
function orPrevious<E, A>(result: AsyncResult.AsyncResult<A, E>) {
|
|
354
|
+
return AsyncResult.isFailure(result) && Option.isSome(result.previousSuccess)
|
|
355
|
+
? AsyncResult.success(result.previousSuccess.value, { waiting: result.waiting })
|
|
349
356
|
: result
|
|
350
357
|
}
|
|
351
358
|
|
|
352
359
|
export function composeQueries<
|
|
353
|
-
R extends Record<string,
|
|
360
|
+
R extends Record<string, AsyncResult.AsyncResult<any, any>>
|
|
354
361
|
>(
|
|
355
362
|
results: R,
|
|
356
363
|
renderPreviousOnFailure?: boolean
|
|
357
|
-
):
|
|
364
|
+
): AsyncResult.AsyncResult<
|
|
358
365
|
{
|
|
359
|
-
[Property in keyof R]: R[Property] extends
|
|
366
|
+
[Property in keyof R]: R[Property] extends AsyncResult.AsyncResult<infer A, any> ? A
|
|
360
367
|
: never
|
|
361
368
|
},
|
|
362
369
|
{
|
|
363
|
-
[Property in keyof R]: R[Property] extends
|
|
370
|
+
[Property in keyof R]: R[Property] extends AsyncResult.AsyncResult<any, infer E> ? E
|
|
364
371
|
: never
|
|
365
372
|
}[keyof R]
|
|
366
373
|
> {
|
|
367
374
|
const values = renderPreviousOnFailure
|
|
368
375
|
? Object.values(results).map(orPrevious)
|
|
369
376
|
: Object.values(results)
|
|
370
|
-
const error = values.find(
|
|
377
|
+
const error = values.find(AsyncResult.isFailure)
|
|
371
378
|
if (error) {
|
|
372
379
|
return error
|
|
373
380
|
}
|
|
@@ -375,7 +382,7 @@ export function composeQueries<
|
|
|
375
382
|
if (initial.value !== undefined) {
|
|
376
383
|
return initial.value
|
|
377
384
|
}
|
|
378
|
-
const loading = Array.findFirst(values, (x) =>
|
|
385
|
+
const loading = Array.findFirst(values, (x) => AsyncResult.isInitial(x) && x.waiting ? Option.some(x) : Option.none())
|
|
379
386
|
if (loading.value !== undefined) {
|
|
380
387
|
return loading.value
|
|
381
388
|
}
|
|
@@ -383,10 +390,10 @@ export function composeQueries<
|
|
|
383
390
|
const isRefreshing = values.some((x) => x.waiting)
|
|
384
391
|
|
|
385
392
|
const r = Object.entries(results).reduce((prev, [key, value]) => {
|
|
386
|
-
prev[key] =
|
|
393
|
+
prev[key] = AsyncResult.value(value).value
|
|
387
394
|
return prev
|
|
388
395
|
}, {} as any)
|
|
389
|
-
return
|
|
396
|
+
return AsyncResult.success(r, { waiting: isRefreshing })
|
|
390
397
|
}
|
|
391
398
|
|
|
392
399
|
export const useUpdateQuery = () => {
|
package/src/routeParams.ts
CHANGED
|
@@ -12,34 +12,18 @@ export function getQueryParam(search: ParsedQuery, param: string) {
|
|
|
12
12
|
return v ?? null
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export const getQueryParamO = flow(getQueryParam, Option.
|
|
15
|
+
export const getQueryParamO = flow(getQueryParam, Option.fromNullishOr)
|
|
16
16
|
|
|
17
|
-
export
|
|
18
|
-
const dec = flow(S.decodeUnknownEither(t), (x) =>
|
|
19
|
-
x._tag === "Right"
|
|
20
|
-
? Option.some(x.right)
|
|
21
|
-
: Option.none())
|
|
22
|
-
return dec
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const parseOptUnknown = <E, A>(t: S.Schema<A, E, never>) => {
|
|
26
|
-
const dec = flow(S.decodeUnknownEither(t), (x) =>
|
|
27
|
-
x._tag === "Right"
|
|
28
|
-
? Option.some(x.right)
|
|
29
|
-
: Option.none())
|
|
30
|
-
return dec
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function parseRouteParamsOption<NER extends Record<string, Schema<any, any, never>>>(
|
|
34
|
-
query: Record<string, any>,
|
|
35
|
-
t: NER // enforce non empty
|
|
17
|
+
export function parseRouteParamsOption<NER extends Record<string, S.Codec<any, any>>>(query: Record<string, any>, t: NER // enforce non empty
|
|
36
18
|
): {
|
|
37
19
|
[K in keyof NER]: Option.Option<Schema.Type<NER[K]>>
|
|
38
20
|
} {
|
|
39
21
|
return typedKeysOf(t).reduce(
|
|
40
22
|
(prev, cur) => {
|
|
41
23
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
42
|
-
prev[cur] = getQueryParamO(query, cur as string).pipe(
|
|
24
|
+
prev[cur] = getQueryParamO(query, cur as string).pipe(
|
|
25
|
+
Option.flatMap(S.decodeUnknownOption(t[cur]!))
|
|
26
|
+
)
|
|
43
27
|
|
|
44
28
|
return prev
|
|
45
29
|
},
|
|
@@ -49,7 +33,7 @@ export function parseRouteParamsOption<NER extends Record<string, Schema<any, an
|
|
|
49
33
|
)
|
|
50
34
|
}
|
|
51
35
|
|
|
52
|
-
export function parseRouteParams<NER extends Record<string,
|
|
36
|
+
export function parseRouteParams<NER extends Record<string, S.Codec<any, any>>>(
|
|
53
37
|
query: Record<string, any>,
|
|
54
38
|
t: NER // enforce non empty
|
|
55
39
|
): {
|
|
@@ -58,7 +42,9 @@ export function parseRouteParams<NER extends Record<string, Schema<any, any, nev
|
|
|
58
42
|
return typedKeysOf(t).reduce(
|
|
59
43
|
(prev, cur) => {
|
|
60
44
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
61
|
-
prev[cur] = S.decodeUnknownSync(t[cur]!)(
|
|
45
|
+
prev[cur] = S.decodeUnknownSync(t[cur]!)(
|
|
46
|
+
(query as any)[cur]
|
|
47
|
+
)
|
|
62
48
|
|
|
63
49
|
return prev
|
|
64
50
|
},
|
package/src/runtime.ts
CHANGED
|
@@ -3,12 +3,12 @@ import { Effect, Layer, Logger } from "effect-app"
|
|
|
3
3
|
|
|
4
4
|
export function makeAppRuntime<A, E>(layer: Layer.Layer<A, E>) {
|
|
5
5
|
return Effect.gen(function*() {
|
|
6
|
-
|
|
7
|
-
Layer.provide(Logger.
|
|
8
|
-
)
|
|
9
|
-
const mrt = ManagedRuntime.make(
|
|
10
|
-
yield* mrt.
|
|
11
|
-
return Object.assign(mrt
|
|
6
|
+
const l = layer.pipe(
|
|
7
|
+
Layer.provide(Logger.layer([Logger.consolePretty()]))
|
|
8
|
+
) as Layer.Layer<A, never>
|
|
9
|
+
const mrt = ManagedRuntime.make(l)
|
|
10
|
+
yield* mrt.servicesEffect
|
|
11
|
+
return Object.assign(mrt, {
|
|
12
12
|
[Symbol.dispose]() {
|
|
13
13
|
return Effect.runSync(mrt.disposeEffect)
|
|
14
14
|
},
|