@sylphx/lens-solid 1.0.2

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.
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @sylphx/lens-solid - Primitives
3
+ *
4
+ * SolidJS reactive primitives for Lens queries and mutations.
5
+ * Uses SolidJS fine-grained reactivity for optimal performance.
6
+ */
7
+ import type { MutationResult, QueryResult } from "@sylphx/lens-client";
8
+ import { type Accessor } from "solid-js";
9
+ /** Query result with reactive signals */
10
+ export interface CreateQueryResult<T> {
11
+ /** Reactive data accessor */
12
+ data: Accessor<T | null>;
13
+ /** Reactive loading state */
14
+ loading: Accessor<boolean>;
15
+ /** Reactive error state */
16
+ error: Accessor<Error | null>;
17
+ /** Refetch the query */
18
+ refetch: () => void;
19
+ }
20
+ /** Mutation result with reactive signals */
21
+ export interface CreateMutationResult<TInput, TOutput> {
22
+ /** Reactive data accessor */
23
+ data: Accessor<TOutput | null>;
24
+ /** Reactive loading state */
25
+ loading: Accessor<boolean>;
26
+ /** Reactive error state */
27
+ error: Accessor<Error | null>;
28
+ /** Execute the mutation */
29
+ mutate: (input: TInput) => Promise<MutationResult<TOutput>>;
30
+ /** Reset state */
31
+ reset: () => void;
32
+ }
33
+ /** Lazy query result */
34
+ export interface CreateLazyQueryResult<T> {
35
+ /** Reactive data accessor */
36
+ data: Accessor<T | null>;
37
+ /** Reactive loading state */
38
+ loading: Accessor<boolean>;
39
+ /** Reactive error state */
40
+ error: Accessor<Error | null>;
41
+ /** Execute the query */
42
+ execute: () => Promise<T>;
43
+ /** Reset state */
44
+ reset: () => void;
45
+ }
46
+ /** Query options */
47
+ export interface CreateQueryOptions {
48
+ /** Skip the query (don't execute) */
49
+ skip?: boolean;
50
+ }
51
+ /** Mutation function type */
52
+ export type MutationFn<TInput, TOutput> = (input: TInput) => Promise<MutationResult<TOutput>>;
53
+ /**
54
+ * Create a reactive query from a QueryResult.
55
+ * Automatically subscribes to updates and manages cleanup.
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * import { createQuery } from '@sylphx/lens-solid';
60
+ *
61
+ * function UserProfile(props: { userId: string }) {
62
+ * const user = createQuery(() => client.queries.getUser({ id: props.userId }));
63
+ *
64
+ * return (
65
+ * <Show when={!user.loading()} fallback={<Spinner />}>
66
+ * <Show when={user.data()} fallback={<NotFound />}>
67
+ * {(data) => <h1>{data().name}</h1>}
68
+ * </Show>
69
+ * </Show>
70
+ * );
71
+ * }
72
+ * ```
73
+ */
74
+ export declare function createQuery<T>(queryFn: () => QueryResult<T>, options?: CreateQueryOptions): CreateQueryResult<T>;
75
+ /**
76
+ * Create a reactive mutation with loading/error state.
77
+ *
78
+ * @example
79
+ * ```tsx
80
+ * import { createMutation } from '@sylphx/lens-solid';
81
+ *
82
+ * function CreatePostForm() {
83
+ * const createPost = createMutation(client.mutations.createPost);
84
+ *
85
+ * const handleSubmit = async (e: Event) => {
86
+ * e.preventDefault();
87
+ * try {
88
+ * const result = await createPost.mutate({ title: 'Hello World' });
89
+ * console.log('Created:', result.data);
90
+ * } catch (err) {
91
+ * console.error('Failed:', err);
92
+ * }
93
+ * };
94
+ *
95
+ * return (
96
+ * <form onSubmit={handleSubmit}>
97
+ * <button type="submit" disabled={createPost.loading()}>
98
+ * {createPost.loading() ? 'Creating...' : 'Create'}
99
+ * </button>
100
+ * <Show when={createPost.error()}>
101
+ * {(err) => <p class="error">{err().message}</p>}
102
+ * </Show>
103
+ * </form>
104
+ * );
105
+ * }
106
+ * ```
107
+ */
108
+ export declare function createMutation<TInput, TOutput>(mutationFn: MutationFn<TInput, TOutput>): CreateMutationResult<TInput, TOutput>;
109
+ /**
110
+ * Create a lazy query that executes on demand.
111
+ *
112
+ * @example
113
+ * ```tsx
114
+ * import { createLazyQuery } from '@sylphx/lens-solid';
115
+ *
116
+ * function SearchUsers() {
117
+ * const [searchTerm, setSearchTerm] = createSignal('');
118
+ * const search = createLazyQuery(() =>
119
+ * client.queries.searchUsers({ query: searchTerm() })
120
+ * );
121
+ *
122
+ * const handleSearch = async () => {
123
+ * const results = await search.execute();
124
+ * console.log('Found:', results);
125
+ * };
126
+ *
127
+ * return (
128
+ * <div>
129
+ * <input
130
+ * value={searchTerm()}
131
+ * onInput={(e) => setSearchTerm(e.currentTarget.value)}
132
+ * />
133
+ * <button onClick={handleSearch} disabled={search.loading()}>
134
+ * Search
135
+ * </button>
136
+ * <Show when={search.data()}>
137
+ * {(users) => (
138
+ * <ul>
139
+ * <For each={users()}>
140
+ * {(user) => <li>{user.name}</li>}
141
+ * </For>
142
+ * </ul>
143
+ * )}
144
+ * </Show>
145
+ * </div>
146
+ * );
147
+ * }
148
+ * ```
149
+ */
150
+ export declare function createLazyQuery<T>(queryFn: () => QueryResult<T>): CreateLazyQueryResult<T>;
151
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,KAAK,QAAQ,EAA2B,MAAM,UAAU,CAAC;AAMlE,yCAAyC;AACzC,MAAM,WAAW,iBAAiB,CAAC,CAAC;IACnC,6BAA6B;IAC7B,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,6BAA6B;IAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,2BAA2B;IAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,wBAAwB;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB,CAAC,MAAM,EAAE,OAAO;IACpD,6BAA6B;IAC7B,IAAI,EAAE,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAC/B,6BAA6B;IAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,2BAA2B;IAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,2BAA2B;IAC3B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,kBAAkB;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAwB;AACxB,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACvC,6BAA6B;IAC7B,IAAI,EAAE,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,6BAA6B;IAC7B,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3B,2BAA2B;IAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9B,wBAAwB;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC1B,kBAAkB;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,oBAAoB;AACpB,MAAM,WAAW,kBAAkB;IAClC,qCAAqC;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CACf;AAED,6BAA6B;AAC7B,MAAM,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;AAM9F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC5B,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,EAC7B,OAAO,CAAC,EAAE,kBAAkB,GAC1B,iBAAiB,CAAC,CAAC,CAAC,CAgEtB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,EAC7C,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,CAmCvC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAoC1F"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for SolidJS Primitives
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=primitives.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.test.d.ts","sourceRoot":"","sources":["../src/primitives.test.tsx"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@sylphx/lens-solid",
3
+ "version": "1.0.2",
4
+ "description": "SolidJS bindings for Lens API framework",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "bun build ./src/index.ts --outdir ./dist --target browser && bun run build:types",
16
+ "build:types": "tsc --emitDeclarationOnly --outDir ./dist",
17
+ "typecheck": "tsc --noEmit",
18
+ "test": "bun test"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "src"
23
+ ],
24
+ "keywords": [
25
+ "lens",
26
+ "solid",
27
+ "solidjs",
28
+ "reactive",
29
+ "signals"
30
+ ],
31
+ "author": "SylphxAI",
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "@sylphx/lens-client": "workspace:*"
35
+ },
36
+ "peerDependencies": {
37
+ "solid-js": ">=1.8.0"
38
+ },
39
+ "devDependencies": {
40
+ "@solidjs/testing-library": "^0.8.10",
41
+ "solid-js": "^1.9.5",
42
+ "typescript": "^5.9.3"
43
+ }
44
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @sylphx/lens-solid - Context
3
+ *
4
+ * SolidJS context for Lens client injection.
5
+ */
6
+
7
+ import type { LensClient } from "@sylphx/lens-client";
8
+ import { type ParentComponent, createContext, useContext } from "solid-js";
9
+
10
+ // =============================================================================
11
+ // Context
12
+ // =============================================================================
13
+
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ const LensClientContext = createContext<LensClient<any, any>>();
16
+
17
+ // =============================================================================
18
+ // Provider
19
+ // =============================================================================
20
+
21
+ export interface LensProviderProps {
22
+ /** Lens client instance */
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ client: LensClient<any, any>;
25
+ }
26
+
27
+ /**
28
+ * Provider for Lens client in SolidJS.
29
+ *
30
+ * @example
31
+ * ```tsx
32
+ * import { createClient, httpLink } from '@sylphx/lens-client';
33
+ * import { LensProvider } from '@sylphx/lens-solid';
34
+ * import type { AppRouter } from './server';
35
+ *
36
+ * const client = createClient<AppRouter>({
37
+ * links: [httpLink({ url: '/api' })],
38
+ * });
39
+ *
40
+ * function App() {
41
+ * return (
42
+ * <LensProvider client={client}>
43
+ * <UserProfile />
44
+ * </LensProvider>
45
+ * );
46
+ * }
47
+ * ```
48
+ */
49
+ export const LensProvider: ParentComponent<LensProviderProps> = (props) => {
50
+ return (
51
+ <LensClientContext.Provider value={props.client}>{props.children}</LensClientContext.Provider>
52
+ );
53
+ };
54
+
55
+ // =============================================================================
56
+ // Hook
57
+ // =============================================================================
58
+
59
+ /**
60
+ * Get Lens client from context.
61
+ *
62
+ * @throws Error if used outside LensProvider
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * function UserProfile() {
67
+ * const client = useLensClient<AppRouter>();
68
+ * const user = createQuery(() => client.queries.getUser({ id: '123' }));
69
+ * return <h1>{user.data?.name}</h1>;
70
+ * }
71
+ * ```
72
+ */
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ export function useLensClient<TRouter = any>(): LensClient<any, any> & TRouter {
75
+ const client = useContext(LensClientContext);
76
+
77
+ if (!client) {
78
+ throw new Error(
79
+ "useLensClient must be used within a <LensProvider>. " +
80
+ "Make sure to wrap your app with <LensProvider client={client}>.",
81
+ );
82
+ }
83
+
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ return client as LensClient<any, any> & TRouter;
86
+ }
package/src/index.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @sylphx/lens-solid
3
+ *
4
+ * SolidJS bindings for Lens API framework.
5
+ * Reactive primitives that integrate with SolidJS fine-grained reactivity.
6
+ */
7
+
8
+ // =============================================================================
9
+ // Context & Provider
10
+ // =============================================================================
11
+
12
+ export { LensProvider, useLensClient, type LensProviderProps } from "./context";
13
+
14
+ // =============================================================================
15
+ // Reactive Primitives
16
+ // =============================================================================
17
+
18
+ export {
19
+ // Query primitives
20
+ createQuery,
21
+ createLazyQuery,
22
+ // Mutation primitive
23
+ createMutation,
24
+ // Types
25
+ type CreateQueryResult,
26
+ type CreateMutationResult,
27
+ type CreateLazyQueryResult,
28
+ type CreateQueryOptions,
29
+ type MutationFn,
30
+ } from "./primitives";
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Tests for SolidJS Primitives
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import type { MutationResult, QueryResult } from "@sylphx/lens-client";
7
+ import { createRoot } from "solid-js";
8
+ import { createLazyQuery, createMutation, createQuery } from "./primitives";
9
+
10
+ // =============================================================================
11
+ // Mock QueryResult
12
+ // =============================================================================
13
+
14
+ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T> & {
15
+ _setValue: (value: T) => void;
16
+ _setError: (error: Error) => void;
17
+ } {
18
+ let currentValue = initialValue;
19
+ const subscribers: Array<(value: T) => void> = [];
20
+ let resolved = false;
21
+ let resolvePromise: ((value: T) => void) | null = null;
22
+ let rejectPromise: ((error: Error) => void) | null = null;
23
+
24
+ const promise = new Promise<T>((resolve, reject) => {
25
+ resolvePromise = resolve;
26
+ rejectPromise = reject;
27
+ if (initialValue !== null) {
28
+ resolved = true;
29
+ resolve(initialValue);
30
+ }
31
+ });
32
+
33
+ const result = {
34
+ get value() {
35
+ return currentValue;
36
+ },
37
+ signal: { value: currentValue } as any,
38
+ loading: { value: initialValue === null } as any,
39
+ error: { value: null } as any,
40
+ subscribe(callback?: (data: T) => void): () => void {
41
+ if (callback) {
42
+ subscribers.push(callback);
43
+ if (currentValue !== null) {
44
+ callback(currentValue);
45
+ }
46
+ }
47
+ return () => {
48
+ const idx = subscribers.indexOf(callback!);
49
+ if (idx >= 0) subscribers.splice(idx, 1);
50
+ };
51
+ },
52
+ select() {
53
+ return result as unknown as QueryResult<T>;
54
+ },
55
+ then<TResult1 = T, TResult2 = never>(
56
+ onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
57
+ onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
58
+ ): Promise<TResult1 | TResult2> {
59
+ return promise.then(onfulfilled, onrejected);
60
+ },
61
+ // Test helpers
62
+ _setValue(value: T) {
63
+ currentValue = value;
64
+ subscribers.forEach((cb) => cb(value));
65
+ if (!resolved && resolvePromise) {
66
+ resolved = true;
67
+ resolvePromise(value);
68
+ }
69
+ },
70
+ _setError(error: Error) {
71
+ if (!resolved && rejectPromise) {
72
+ resolved = true;
73
+ rejectPromise(error);
74
+ }
75
+ },
76
+ };
77
+
78
+ return result as QueryResult<T> & {
79
+ _setValue: (value: T) => void;
80
+ _setError: (error: Error) => void;
81
+ };
82
+ }
83
+
84
+ // =============================================================================
85
+ // Tests: createQuery
86
+ // =============================================================================
87
+
88
+ describe("createQuery", () => {
89
+ test("returns loading state initially", () => {
90
+ createRoot((dispose) => {
91
+ const mockQuery = createMockQueryResult<{ id: string; name: string }>();
92
+ const query = createQuery(() => mockQuery);
93
+
94
+ expect(query.loading()).toBe(true);
95
+ expect(query.data()).toBe(null);
96
+ expect(query.error()).toBe(null);
97
+
98
+ dispose();
99
+ });
100
+ });
101
+
102
+ test("returns data when query resolves", async () => {
103
+ await new Promise<void>((resolve) => {
104
+ createRoot(async (dispose) => {
105
+ // Create mock with initial value so promise resolves immediately
106
+ const mockQuery = createMockQueryResult<{ id: string; name: string }>({
107
+ id: "123",
108
+ name: "John",
109
+ });
110
+ const query = createQuery(() => mockQuery);
111
+
112
+ // Wait for promise to resolve
113
+ await new Promise((r) => setTimeout(r, 10));
114
+
115
+ expect(query.data()).toEqual({ id: "123", name: "John" });
116
+ expect(query.loading()).toBe(false);
117
+ expect(query.error()).toBe(null);
118
+
119
+ dispose();
120
+ resolve();
121
+ });
122
+ });
123
+ });
124
+
125
+ test("skips query when skip option is true", () => {
126
+ createRoot((dispose) => {
127
+ const mockQuery = createMockQueryResult<{ id: string }>();
128
+ const query = createQuery(() => mockQuery, { skip: true });
129
+
130
+ expect(query.loading()).toBe(false);
131
+ expect(query.data()).toBe(null);
132
+
133
+ dispose();
134
+ });
135
+ });
136
+ });
137
+
138
+ // =============================================================================
139
+ // Tests: createMutation
140
+ // =============================================================================
141
+
142
+ describe("createMutation", () => {
143
+ test("executes mutation and returns result", async () => {
144
+ await new Promise<void>((resolve) => {
145
+ createRoot(async (dispose) => {
146
+ const mutationFn = async (input: { name: string }): Promise<
147
+ MutationResult<{ id: string; name: string }>
148
+ > => {
149
+ return { data: { id: "new-id", name: input.name } };
150
+ };
151
+
152
+ const mutation = createMutation(mutationFn);
153
+
154
+ expect(mutation.loading()).toBe(false);
155
+ expect(mutation.data()).toBe(null);
156
+
157
+ const result = await mutation.mutate({ name: "New User" });
158
+
159
+ expect(result.data).toEqual({ id: "new-id", name: "New User" });
160
+ expect(mutation.data()).toEqual({ id: "new-id", name: "New User" });
161
+ expect(mutation.loading()).toBe(false);
162
+
163
+ dispose();
164
+ resolve();
165
+ });
166
+ });
167
+ });
168
+
169
+ test("handles mutation error", async () => {
170
+ await new Promise<void>((resolve) => {
171
+ createRoot(async (dispose) => {
172
+ const mutationFn = async (_input: { name: string }): Promise<
173
+ MutationResult<{ id: string }>
174
+ > => {
175
+ throw new Error("Mutation failed");
176
+ };
177
+
178
+ const mutation = createMutation(mutationFn);
179
+
180
+ try {
181
+ await mutation.mutate({ name: "New User" });
182
+ } catch {
183
+ // Expected error
184
+ }
185
+
186
+ expect(mutation.error()?.message).toBe("Mutation failed");
187
+ expect(mutation.loading()).toBe(false);
188
+
189
+ dispose();
190
+ resolve();
191
+ });
192
+ });
193
+ });
194
+
195
+ test("reset clears mutation state", async () => {
196
+ await new Promise<void>((resolve) => {
197
+ createRoot(async (dispose) => {
198
+ const mutationFn = async (input: { name: string }): Promise<
199
+ MutationResult<{ id: string; name: string }>
200
+ > => {
201
+ return { data: { id: "new-id", name: input.name } };
202
+ };
203
+
204
+ const mutation = createMutation(mutationFn);
205
+ await mutation.mutate({ name: "New User" });
206
+
207
+ expect(mutation.data()).not.toBe(null);
208
+
209
+ mutation.reset();
210
+
211
+ expect(mutation.data()).toBe(null);
212
+ expect(mutation.error()).toBe(null);
213
+ expect(mutation.loading()).toBe(false);
214
+
215
+ dispose();
216
+ resolve();
217
+ });
218
+ });
219
+ });
220
+ });
221
+
222
+ // =============================================================================
223
+ // Tests: createLazyQuery
224
+ // =============================================================================
225
+
226
+ describe("createLazyQuery", () => {
227
+ test("does not execute query on creation", () => {
228
+ createRoot((dispose) => {
229
+ const mockQuery = createMockQueryResult<{ id: string }>({ id: "123" });
230
+ const query = createLazyQuery(() => mockQuery);
231
+
232
+ expect(query.loading()).toBe(false);
233
+ expect(query.data()).toBe(null);
234
+
235
+ dispose();
236
+ });
237
+ });
238
+
239
+ test("executes query when execute is called", async () => {
240
+ await new Promise<void>((resolve) => {
241
+ createRoot(async (dispose) => {
242
+ const mockQuery = createMockQueryResult<{ id: string; name: string }>({
243
+ id: "123",
244
+ name: "John",
245
+ });
246
+ const query = createLazyQuery(() => mockQuery);
247
+
248
+ const result = await query.execute();
249
+
250
+ expect(result).toEqual({ id: "123", name: "John" });
251
+ expect(query.data()).toEqual({ id: "123", name: "John" });
252
+
253
+ dispose();
254
+ resolve();
255
+ });
256
+ });
257
+ });
258
+
259
+ test("reset clears query state", async () => {
260
+ await new Promise<void>((resolve) => {
261
+ createRoot(async (dispose) => {
262
+ const mockQuery = createMockQueryResult<{ id: string }>({ id: "123" });
263
+ const query = createLazyQuery(() => mockQuery);
264
+
265
+ await query.execute();
266
+ expect(query.data()).not.toBe(null);
267
+
268
+ query.reset();
269
+
270
+ expect(query.data()).toBe(null);
271
+ expect(query.error()).toBe(null);
272
+ expect(query.loading()).toBe(false);
273
+
274
+ dispose();
275
+ resolve();
276
+ });
277
+ });
278
+ });
279
+ });