@effectify/solid-query 0.4.5 → 0.4.6
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/dist/package.json +36 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +5 -0
- package/dist/src/lib/internal/make-use-effect-mutation.d.ts +3 -0
- package/dist/src/lib/internal/make-use-effect-mutation.js +13 -0
- package/dist/src/lib/internal/make-use-effect-query.d.ts +3 -0
- package/dist/src/lib/internal/make-use-effect-query.js +21 -0
- package/dist/src/lib/internal/make-use-rx-subsciption-ref.d.ts +6 -0
- package/dist/src/lib/internal/make-use-rx-subsciption-ref.js +53 -0
- package/dist/src/lib/internal/make-use-rx-subscribe.d.ts +5 -0
- package/dist/src/lib/internal/make-use-rx-subscribe.js +37 -0
- package/dist/src/lib/internal/query-data-helpers.d.ts +75 -0
- package/dist/src/lib/internal/query-data-helpers.js +107 -0
- package/dist/src/lib/tanstack-query-effect.d.ts +28 -0
- package/dist/src/lib/tanstack-query-effect.jsx +45 -0
- package/dist/src/lib/types.d.ts +31 -0
- package/dist/src/lib/types.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@effectify/solid-query",
|
|
3
|
+
"version": "0.4.5",
|
|
4
|
+
"description": "Integration of Effect with TanStack Query for Solid.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"@effectify/source": "./src/index.ts",
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"!**/*.tsbuildinfo"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"tslib": "catalog:",
|
|
26
|
+
"@tanstack/solid-query": "catalog:",
|
|
27
|
+
"@tanstack/query-core": "catalog:",
|
|
28
|
+
"effect": "catalog:",
|
|
29
|
+
"solid-js": "catalog:"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typescript": "catalog:"
|
|
33
|
+
},
|
|
34
|
+
"optionalDependencies": {},
|
|
35
|
+
"peerDependencies": {}
|
|
36
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type UseMutationResult } from '@tanstack/solid-query';
|
|
2
|
+
import type { EffectfulError, EffectfulMutationOptions, Runner } from '../types.js';
|
|
3
|
+
export declare const makeUseEffectMutation: <R>(createRunner: Runner<R>) => <TData, TError extends EffectfulError, TVariables>(options: EffectfulMutationOptions<TData, TError, TVariables, R>) => UseMutationResult<TData, Error, TVariables>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useMutation } from '@tanstack/solid-query';
|
|
2
|
+
export const makeUseEffectMutation = (createRunner) => (options) => {
|
|
3
|
+
const effectRunner = createRunner();
|
|
4
|
+
const [spanName] = options.mutationKey;
|
|
5
|
+
const mutationFn = () => (variables) => {
|
|
6
|
+
const effect = options.mutationFn(variables);
|
|
7
|
+
return effectRunner()(spanName)(effect);
|
|
8
|
+
};
|
|
9
|
+
return useMutation(() => ({
|
|
10
|
+
...options,
|
|
11
|
+
mutationFn: mutationFn(),
|
|
12
|
+
}));
|
|
13
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type UseQueryResult } from '@tanstack/solid-query';
|
|
2
|
+
import type { EffectfulError, EffectfulQueryOptions, QueryKey, Runner } from '../types.js';
|
|
3
|
+
export declare const makeUseEffectQuery: <R>(createRunner: Runner<R>) => <TData, TError extends EffectfulError, TQueryKey extends QueryKey = QueryKey>({ gcTime, staleTime, ...options }: EffectfulQueryOptions<TData, TError, R, TQueryKey>) => UseQueryResult<TData, Error>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { skipToken } from '@tanstack/query-core';
|
|
2
|
+
import { useQuery } from '@tanstack/solid-query';
|
|
3
|
+
import * as Duration from 'effect/Duration';
|
|
4
|
+
import { createMemo } from 'solid-js';
|
|
5
|
+
export const makeUseEffectQuery = (createRunner) => ({ gcTime, staleTime, ...options }) => {
|
|
6
|
+
const effectRunner = createRunner();
|
|
7
|
+
const [spanName] = options.queryKey;
|
|
8
|
+
const queryFn = createMemo(() => (context) => {
|
|
9
|
+
const effect = options.queryFn(context);
|
|
10
|
+
return effect.pipe(effectRunner()(spanName));
|
|
11
|
+
})();
|
|
12
|
+
return useQuery(() => ({
|
|
13
|
+
...options,
|
|
14
|
+
queryKey: options.queryKey, // Aseguramos que queryKey es no-undefined
|
|
15
|
+
queryFn: options.queryFn === skipToken ? skipToken : queryFn,
|
|
16
|
+
...(staleTime !== undefined && {
|
|
17
|
+
staleTime: Duration.toMillis(staleTime),
|
|
18
|
+
}),
|
|
19
|
+
...(gcTime !== undefined && { gcTime: Duration.toMillis(gcTime) }),
|
|
20
|
+
}));
|
|
21
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import type * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
3
|
+
import * as SubscriptionRef from 'effect/SubscriptionRef';
|
|
4
|
+
import { type Context } from 'solid-js';
|
|
5
|
+
import type { Subscribable, SubscriptionOptions } from '../types.js';
|
|
6
|
+
export declare const makeUseRxSubscriptionRef: <R, E>(RuntimeContext: Context<ManagedRuntime.ManagedRuntime<R, E> | null>) => <A, E2>(subscribable: Subscribable<A, E2> | Effect.Effect<Subscribable<A, E2>, never, R> | Effect.Effect<SubscriptionRef.SubscriptionRef<A>, never, R>, onNext: (value: A) => void, opts?: SubscriptionOptions) => A;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import * as Fiber from 'effect/Fiber';
|
|
3
|
+
import * as Stream from 'effect/Stream';
|
|
4
|
+
import * as SubscriptionRef from 'effect/SubscriptionRef';
|
|
5
|
+
import { createEffect, createSignal, onCleanup, useContext } from 'solid-js';
|
|
6
|
+
export const makeUseRxSubscriptionRef = (RuntimeContext) => (subscribable, onNext, opts) => {
|
|
7
|
+
const options = {
|
|
8
|
+
skipInitial: opts?.skipInitial ?? true,
|
|
9
|
+
};
|
|
10
|
+
const runtime = useContext(RuntimeContext);
|
|
11
|
+
if (!runtime) {
|
|
12
|
+
throw new Error('Runtime context not found. Make sure to wrap your app with RuntimeProvider');
|
|
13
|
+
}
|
|
14
|
+
const setInitialValue = () => {
|
|
15
|
+
const initialValue = Effect.gen(function* () {
|
|
16
|
+
const resolved = Effect.isEffect(subscribable) ? yield* subscribable : subscribable;
|
|
17
|
+
const resolvedValue = SubscriptionRef.SubscriptionRefTypeId in resolved ? yield* SubscriptionRef.get(resolved) : resolved.get();
|
|
18
|
+
if (!options?.skipInitial) {
|
|
19
|
+
onNext(resolvedValue);
|
|
20
|
+
}
|
|
21
|
+
return resolvedValue;
|
|
22
|
+
});
|
|
23
|
+
const newVal = runtime.runSync(initialValue);
|
|
24
|
+
return newVal;
|
|
25
|
+
};
|
|
26
|
+
const [value, setValue] = createSignal(setInitialValue());
|
|
27
|
+
createEffect(() => {
|
|
28
|
+
const fiber = Effect.gen(function* () {
|
|
29
|
+
const resolved = Effect.isEffect(subscribable) ? yield* subscribable : subscribable;
|
|
30
|
+
const adaptedSubscribable = SubscriptionRef.SubscriptionRefTypeId in resolved
|
|
31
|
+
? {
|
|
32
|
+
changes: resolved.changes,
|
|
33
|
+
get: () => runtime.runSync(SubscriptionRef.get(resolved)),
|
|
34
|
+
}
|
|
35
|
+
: resolved;
|
|
36
|
+
const currentValue = adaptedSubscribable.get();
|
|
37
|
+
setValue(() => currentValue);
|
|
38
|
+
let hasEmittedInitial = false;
|
|
39
|
+
return yield* adaptedSubscribable.changes.pipe(Stream.tap((val) => Effect.sync(() => {
|
|
40
|
+
setValue(() => val);
|
|
41
|
+
if (options?.skipInitial && !hasEmittedInitial) {
|
|
42
|
+
hasEmittedInitial = true;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
onNext(val);
|
|
46
|
+
})), Stream.runDrain, Effect.forever, Effect.forkDaemon);
|
|
47
|
+
}).pipe(runtime.runSync);
|
|
48
|
+
onCleanup(() => {
|
|
49
|
+
runtime.runCallback(Fiber.interrupt(fiber));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return value();
|
|
53
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import type * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
3
|
+
import * as Stream from 'effect/Stream';
|
|
4
|
+
import { type Context } from 'solid-js';
|
|
5
|
+
export declare const makeUseRxSubscribe: <R, E>(RuntimeContext: Context<ManagedRuntime.ManagedRuntime<R, E> | null>) => <E2, A>(stream: Stream.Stream<A, E2, R> | Effect.Effect<Stream.Stream<A, E2, R>, E2, R>, initialValue: A, onNext: (value: A) => void, onError?: (error: E2) => void) => import("solid-js").Accessor<A | undefined>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import * as Exit from 'effect/Exit';
|
|
3
|
+
import * as Fiber from 'effect/Fiber';
|
|
4
|
+
import * as Stream from 'effect/Stream';
|
|
5
|
+
import { createSignal, onCleanup, useContext } from 'solid-js';
|
|
6
|
+
export const makeUseRxSubscribe = (RuntimeContext) => {
|
|
7
|
+
return (stream, initialValue, onNext, onError) => {
|
|
8
|
+
const runtime = useContext(RuntimeContext);
|
|
9
|
+
if (!runtime) {
|
|
10
|
+
throw new Error('Runtime context not found. Make sure to wrap your app with RuntimeProvider');
|
|
11
|
+
}
|
|
12
|
+
const [value, setValue] = createSignal(initialValue);
|
|
13
|
+
const [fiberRef, setFiberRef] = createSignal(null);
|
|
14
|
+
const finalStream = Effect.isEffect(stream) ? Stream.unwrap(stream) : stream;
|
|
15
|
+
const subscription = finalStream.pipe(Stream.tap((a) => Effect.sync(() => {
|
|
16
|
+
setValue(() => a);
|
|
17
|
+
onNext(a);
|
|
18
|
+
})), Stream.catchAll((e) => Stream.fromEffect(Effect.sync(() => {
|
|
19
|
+
onError?.(e);
|
|
20
|
+
return;
|
|
21
|
+
}))), Stream.runDrain, Effect.forever, Effect.forkDaemon);
|
|
22
|
+
runtime.runCallback(subscription, {
|
|
23
|
+
onExit: (exit) => {
|
|
24
|
+
if (Exit.isSuccess(exit)) {
|
|
25
|
+
setFiberRef(exit.value);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
onCleanup(() => {
|
|
30
|
+
if (fiberRef() !== null) {
|
|
31
|
+
// biome-ignore lint/style/noNonNullAssertion: <testing>
|
|
32
|
+
runtime.runCallback(Fiber.interrupt(fiberRef()));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return value;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { QueryClient } from '@tanstack/query-core';
|
|
2
|
+
type DeepMutable<T> = {
|
|
3
|
+
-readonly [P in keyof T]: T[P] extends object ? DeepMutable<T[P]> : T[P];
|
|
4
|
+
};
|
|
5
|
+
export type QueryDataUpdater<TData> = (draft: DeepMutable<TData>) => void;
|
|
6
|
+
type QueryKey<TKey extends string, TVariables = void> = TVariables extends void ? readonly [TKey] : readonly [TKey, TVariables];
|
|
7
|
+
/**
|
|
8
|
+
* Creates a type-safe query key factory that can be used with or without variables
|
|
9
|
+
* @template TKey The string literal type for the query key
|
|
10
|
+
* @template TVariables Optional variables type. If not provided, the factory will not accept variables
|
|
11
|
+
* @param key The query key string
|
|
12
|
+
* @returns A function that creates a query key tuple
|
|
13
|
+
*
|
|
14
|
+
* @example Without variables:
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const userKey = createQueryKey("user");
|
|
17
|
+
* const key = userKey(); // returns ["user"]
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example With variables:
|
|
21
|
+
* ```typescript
|
|
22
|
+
* type UserVars = { id: string };
|
|
23
|
+
* const userKey = createQueryKey<"user", UserVars>("user");
|
|
24
|
+
* const key = userKey({ id: "123" }); // returns ["user", { id: "123" }]
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function createQueryKey<TKey extends string, TVariables = void>(key: TKey): TVariables extends void ? () => QueryKey<TKey> : (variables: TVariables) => QueryKey<TKey, TVariables>;
|
|
28
|
+
type QueryDataHelpers<TData, TVariables> = {
|
|
29
|
+
removeQuery: (variables: TVariables) => void;
|
|
30
|
+
removeAllQueries: () => void;
|
|
31
|
+
setData: (variables: TVariables, updater: QueryDataUpdater<TData>) => TData | undefined;
|
|
32
|
+
invalidateQuery: (variables: TVariables) => Promise<void>;
|
|
33
|
+
invalidateAllQueries: () => Promise<void>;
|
|
34
|
+
refetchQuery: (variables: TVariables) => Promise<void>;
|
|
35
|
+
refetchAllQueries: () => Promise<void>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Creates a set of helpers to manage query data in the cache
|
|
39
|
+
* @template TData The type of data stored in the query
|
|
40
|
+
* @template TVariables Automatically inferred from the queryKey function parameter
|
|
41
|
+
* @param queryKey A function that creates a query key tuple from variables
|
|
42
|
+
* @returns An object with methods to remove, update, invalidate, and invalidate all query data
|
|
43
|
+
*
|
|
44
|
+
* @example Without variables:
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const userKey = createQueryKey("user");
|
|
47
|
+
* type User = { name: string };
|
|
48
|
+
*
|
|
49
|
+
* // Types are inferred from userKey
|
|
50
|
+
* const helpers = createQueryDataHelpers<User>(userKey);
|
|
51
|
+
* helpers.setData(undefined, (draft) => {
|
|
52
|
+
* draft.name = "New Name";
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example With variables and explicit types:
|
|
57
|
+
* ```typescript
|
|
58
|
+
* type UserVars = { id: string };
|
|
59
|
+
* type User = { id: string; name: string };
|
|
60
|
+
*
|
|
61
|
+
* const userKey = createQueryKey<"user", UserVars>("user");
|
|
62
|
+
* const helpers = createQueryDataHelpers<User, UserVars>(userKey);
|
|
63
|
+
*
|
|
64
|
+
* helpers.setData({ id: "123" }, (draft) => {
|
|
65
|
+
* draft.name = "New Name";
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // Other helper methods
|
|
69
|
+
* await helpers.invalidateQuery({ id: "123" });
|
|
70
|
+
* await helpers.refetchQuery({ id: "123" });
|
|
71
|
+
* helpers.removeQuery({ id: "123" });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare const makeCreateQueryDataHelpers: (queryClient: QueryClient) => <TData, TVariables = void>(queryKey: (variables: TVariables) => readonly [string, ...unknown[]]) => QueryDataHelpers<TData, TVariables>;
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Simple deep clone function to replace mutative
|
|
2
|
+
function deepClone(obj) {
|
|
3
|
+
if (obj === null || typeof obj !== 'object') {
|
|
4
|
+
return obj;
|
|
5
|
+
}
|
|
6
|
+
if (obj instanceof Date) {
|
|
7
|
+
return new Date(obj.getTime());
|
|
8
|
+
}
|
|
9
|
+
if (Array.isArray(obj)) {
|
|
10
|
+
return obj.map((item) => deepClone(item));
|
|
11
|
+
}
|
|
12
|
+
if (typeof obj === 'object') {
|
|
13
|
+
const cloned = {};
|
|
14
|
+
for (const key in obj) {
|
|
15
|
+
if (Object.hasOwn(obj, key)) {
|
|
16
|
+
cloned[key] = deepClone(obj[key]);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return cloned;
|
|
20
|
+
}
|
|
21
|
+
return obj;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates a type-safe query key factory that can be used with or without variables
|
|
25
|
+
* @template TKey The string literal type for the query key
|
|
26
|
+
* @template TVariables Optional variables type. If not provided, the factory will not accept variables
|
|
27
|
+
* @param key The query key string
|
|
28
|
+
* @returns A function that creates a query key tuple
|
|
29
|
+
*
|
|
30
|
+
* @example Without variables:
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const userKey = createQueryKey("user");
|
|
33
|
+
* const key = userKey(); // returns ["user"]
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example With variables:
|
|
37
|
+
* ```typescript
|
|
38
|
+
* type UserVars = { id: string };
|
|
39
|
+
* const userKey = createQueryKey<"user", UserVars>("user");
|
|
40
|
+
* const key = userKey({ id: "123" }); // returns ["user", { id: "123" }]
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function createQueryKey(key) {
|
|
44
|
+
return ((variables) => variables === undefined ? [key] : [key, variables]);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Creates a set of helpers to manage query data in the cache
|
|
48
|
+
* @template TData The type of data stored in the query
|
|
49
|
+
* @template TVariables Automatically inferred from the queryKey function parameter
|
|
50
|
+
* @param queryKey A function that creates a query key tuple from variables
|
|
51
|
+
* @returns An object with methods to remove, update, invalidate, and invalidate all query data
|
|
52
|
+
*
|
|
53
|
+
* @example Without variables:
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const userKey = createQueryKey("user");
|
|
56
|
+
* type User = { name: string };
|
|
57
|
+
*
|
|
58
|
+
* // Types are inferred from userKey
|
|
59
|
+
* const helpers = createQueryDataHelpers<User>(userKey);
|
|
60
|
+
* helpers.setData(undefined, (draft) => {
|
|
61
|
+
* draft.name = "New Name";
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example With variables and explicit types:
|
|
66
|
+
* ```typescript
|
|
67
|
+
* type UserVars = { id: string };
|
|
68
|
+
* type User = { id: string; name: string };
|
|
69
|
+
*
|
|
70
|
+
* const userKey = createQueryKey<"user", UserVars>("user");
|
|
71
|
+
* const helpers = createQueryDataHelpers<User, UserVars>(userKey);
|
|
72
|
+
*
|
|
73
|
+
* helpers.setData({ id: "123" }, (draft) => {
|
|
74
|
+
* draft.name = "New Name";
|
|
75
|
+
* });
|
|
76
|
+
*
|
|
77
|
+
* // Other helper methods
|
|
78
|
+
* await helpers.invalidateQuery({ id: "123" });
|
|
79
|
+
* await helpers.refetchQuery({ id: "123" });
|
|
80
|
+
* helpers.removeQuery({ id: "123" });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export const makeCreateQueryDataHelpers = (queryClient) => (queryKey) => {
|
|
84
|
+
const [namespaceKey] = queryKey(undefined);
|
|
85
|
+
return {
|
|
86
|
+
removeQuery: (variables) => {
|
|
87
|
+
queryClient.removeQueries({ queryKey: queryKey(variables) });
|
|
88
|
+
},
|
|
89
|
+
removeAllQueries: () => {
|
|
90
|
+
queryClient.removeQueries({ queryKey: [namespaceKey], exact: false });
|
|
91
|
+
},
|
|
92
|
+
setData: (variables, updater) => {
|
|
93
|
+
return queryClient.setQueryData(queryKey(variables), (oldData) => {
|
|
94
|
+
if (oldData === undefined) {
|
|
95
|
+
return oldData;
|
|
96
|
+
}
|
|
97
|
+
const clonedData = deepClone(oldData);
|
|
98
|
+
updater(clonedData);
|
|
99
|
+
return clonedData;
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
invalidateQuery: (variables) => queryClient.invalidateQueries({ queryKey: queryKey(variables) }),
|
|
103
|
+
invalidateAllQueries: () => queryClient.invalidateQueries({ queryKey: [namespaceKey], exact: false }),
|
|
104
|
+
refetchQuery: (variables) => queryClient.refetchQueries({ queryKey: queryKey(variables) }),
|
|
105
|
+
refetchAllQueries: () => queryClient.refetchQueries({ queryKey: [namespaceKey], exact: false }),
|
|
106
|
+
};
|
|
107
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type QueryClient } from '@tanstack/solid-query';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import type * as Layer from 'effect/Layer';
|
|
4
|
+
import * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
5
|
+
import { type Component, type JSX } from 'solid-js';
|
|
6
|
+
export declare const tanstackQueryEffect: <R, E>({ layer, queryClient, }: {
|
|
7
|
+
layer: Layer.Layer<R, E, never>;
|
|
8
|
+
queryClient: QueryClient;
|
|
9
|
+
}) => {
|
|
10
|
+
useRunner: () => import("solid-js").Accessor<(<A, E2>(span: string) => (effect: Effect.Effect<A, E2, R>) => Promise<A>)>;
|
|
11
|
+
RuntimeProvider: Component<{
|
|
12
|
+
children: JSX.Element;
|
|
13
|
+
}>;
|
|
14
|
+
useRuntime: () => ManagedRuntime.ManagedRuntime<R, E>;
|
|
15
|
+
useEffectQuery: <TData, TError extends import("./types.js").EffectfulError, TQueryKey extends import("./types.js").QueryKey = import("./types.js").QueryKey>({ gcTime, staleTime, ...options }: import("./types.js").EffectfulQueryOptions<TData, TError, R, TQueryKey>) => import("@tanstack/solid-query").UseQueryResult<TData, Error>;
|
|
16
|
+
useEffectMutation: <TData, TError_1 extends import("./types.js").EffectfulError, TVariables>(options: import("./types.js").EffectfulMutationOptions<TData, TError_1, TVariables, R>) => import("@tanstack/solid-query").UseMutationResult<TData, Error, TVariables>;
|
|
17
|
+
useRxSubscribe: <E2_1, A>(stream: import("effect/Stream").Stream<A, E2_1, R> | Effect.Effect<import("effect/Stream").Stream<A, E2_1, R>, E2_1, R>, initialValue: A, onNext: (value: A) => void, onError?: ((error: E2_1) => void) | undefined) => import("solid-js").Accessor<A | undefined>;
|
|
18
|
+
useRxSubscriptionRef: <A_1, E2_1>(subscribable: import("./types.js").Subscribable<A_1, E2_1> | Effect.Effect<import("./types.js").Subscribable<A_1, E2_1>, never, R> | Effect.Effect<import("effect/SubscriptionRef").SubscriptionRef<A_1>, never, R>, onNext: (value: A_1) => void, opts?: import("./types.js").SubscriptionOptions) => A_1;
|
|
19
|
+
createQueryDataHelpers: <TData, TVariables_1 = void>(queryKey: (variables: TVariables_1) => readonly [string, ...unknown[]]) => {
|
|
20
|
+
removeQuery: (variables: TVariables_1) => void;
|
|
21
|
+
removeAllQueries: () => void;
|
|
22
|
+
setData: (variables: TVariables_1, updater: import("./internal/query-data-helpers.js").QueryDataUpdater<TData>) => TData | undefined;
|
|
23
|
+
invalidateQuery: (variables: TVariables_1) => Promise<void>;
|
|
24
|
+
invalidateAllQueries: () => Promise<void>;
|
|
25
|
+
refetchQuery: (variables: TVariables_1) => Promise<void>;
|
|
26
|
+
refetchAllQueries: () => Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { QueryClientProvider } from '@tanstack/solid-query';
|
|
2
|
+
import * as Effect from 'effect/Effect';
|
|
3
|
+
import * as ManagedRuntime from 'effect/ManagedRuntime';
|
|
4
|
+
import { createContext, createMemo, onCleanup, useContext } from 'solid-js';
|
|
5
|
+
import { makeUseEffectMutation } from './internal/make-use-effect-mutation.js';
|
|
6
|
+
import { makeUseEffectQuery } from './internal/make-use-effect-query.js';
|
|
7
|
+
import { makeUseRxSubscriptionRef } from './internal/make-use-rx-subsciption-ref.js';
|
|
8
|
+
import { makeUseRxSubscribe } from './internal/make-use-rx-subscribe.js';
|
|
9
|
+
import { makeCreateQueryDataHelpers } from './internal/query-data-helpers.js';
|
|
10
|
+
export const tanstackQueryEffect = ({ layer, queryClient, }) => {
|
|
11
|
+
const RuntimeContext = createContext(null);
|
|
12
|
+
const useRunner = () => {
|
|
13
|
+
const runtime = useContext(RuntimeContext);
|
|
14
|
+
if (!runtime) {
|
|
15
|
+
throw new Error('Runtime context not found. Make sure to wrap your app with RuntimeProvider');
|
|
16
|
+
}
|
|
17
|
+
return createMemo(() => (span) => (effect) => effect.pipe(Effect.withSpan(span), Effect.tapErrorCause(Effect.logError), runtime.runPromise));
|
|
18
|
+
};
|
|
19
|
+
const RuntimeProvider = (props) => {
|
|
20
|
+
const runtime = ManagedRuntime.make(layer);
|
|
21
|
+
onCleanup(() => {
|
|
22
|
+
runtime.dispose();
|
|
23
|
+
});
|
|
24
|
+
return (<RuntimeContext.Provider value={runtime}>
|
|
25
|
+
<QueryClientProvider client={queryClient}>{props.children}</QueryClientProvider>
|
|
26
|
+
</RuntimeContext.Provider>);
|
|
27
|
+
};
|
|
28
|
+
const useRuntime = () => {
|
|
29
|
+
const runtime = useContext(RuntimeContext);
|
|
30
|
+
if (!runtime) {
|
|
31
|
+
throw new Error('Runtime context not found. Make sure to wrap your app with RuntimeProvider');
|
|
32
|
+
}
|
|
33
|
+
return runtime;
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
useRunner,
|
|
37
|
+
RuntimeProvider,
|
|
38
|
+
useRuntime,
|
|
39
|
+
useEffectQuery: makeUseEffectQuery(useRunner),
|
|
40
|
+
useEffectMutation: makeUseEffectMutation(useRunner),
|
|
41
|
+
useRxSubscribe: makeUseRxSubscribe(RuntimeContext),
|
|
42
|
+
useRxSubscriptionRef: makeUseRxSubscriptionRef(RuntimeContext),
|
|
43
|
+
createQueryDataHelpers: makeCreateQueryDataHelpers(queryClient),
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { QueryFunctionContext, skipToken } from '@tanstack/query-core';
|
|
2
|
+
import type { UseMutationOptions, UseQueryOptions } from '@tanstack/solid-query';
|
|
3
|
+
import type { DurationInput } from 'effect/Duration';
|
|
4
|
+
import type * as Effect from 'effect/Effect';
|
|
5
|
+
import type * as Stream from 'effect/Stream';
|
|
6
|
+
import type { Accessor } from 'solid-js';
|
|
7
|
+
export type QueryKey = readonly [string, Record<string, unknown>?];
|
|
8
|
+
export type EffectfulError = {
|
|
9
|
+
_tag: string;
|
|
10
|
+
};
|
|
11
|
+
export type Runner<R> = () => Accessor<(<A, E>(span: string) => (effect: Effect.Effect<A, E, R>) => Promise<A>)>;
|
|
12
|
+
export type EffectfulMutationOptions<TData, TError extends EffectfulError, TVariables, R> = Omit<UseMutationOptions<TData, Error, TVariables>, // Actualizado a UseMutationOptions
|
|
13
|
+
// Actualizado a UseMutationOptions
|
|
14
|
+
'mutationFn' | 'onSuccess' | 'onError' | 'onSettled' | 'onMutate' | 'retry' | 'retryDelay'> & {
|
|
15
|
+
mutationKey: QueryKey;
|
|
16
|
+
mutationFn: (variables: TVariables) => Effect.Effect<TData, TError, R>;
|
|
17
|
+
};
|
|
18
|
+
export type EffectfulQueryFunction<TData, TError, TQueryKey extends QueryKey = QueryKey, R = never, TPageParam = never> = (context: QueryFunctionContext<TQueryKey, TPageParam>) => Effect.Effect<TData, TError, R>;
|
|
19
|
+
export type EffectfulQueryOptions<TData, TError, R, TQueryKey extends QueryKey = QueryKey, TPageParam = never> = Omit<UseQueryOptions<TData, Error, TData, TQueryKey>, 'queryKey' | 'queryFn' | 'retry' | 'retryDelay' | 'staleTime' | 'gcTime'> & {
|
|
20
|
+
queryKey: TQueryKey;
|
|
21
|
+
queryFn: EffectfulQueryFunction<TData, TError, TQueryKey, R, TPageParam> | typeof skipToken;
|
|
22
|
+
staleTime?: DurationInput;
|
|
23
|
+
gcTime?: DurationInput;
|
|
24
|
+
};
|
|
25
|
+
export interface Subscribable<A, E = never> {
|
|
26
|
+
readonly changes: Stream.Stream<A, E>;
|
|
27
|
+
readonly get: () => A;
|
|
28
|
+
}
|
|
29
|
+
export interface SubscriptionOptions {
|
|
30
|
+
readonly skipInitial?: boolean;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|