@izumisy-tailor/tailor-data-viewer 0.2.6 → 0.2.8

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.
@@ -1,16 +1,18 @@
1
1
  import { renderHook, act } from "@testing-library/react";
2
2
  import { describe, it, expect } from "vitest";
3
3
  import type { TableMetadataMap } from "../../generator/metadata-generator";
4
- import { useCollectionParams } from "./use-collection-params";
4
+ import { useCollection } from "./use-collection";
5
5
 
6
- describe("useCollectionParams", () => {
6
+ const FAKE_QUERY = { kind: "Document" } as const;
7
+
8
+ describe("useCollection", () => {
7
9
  // ---------------------------------------------------------------------------
8
10
  // Initial state
9
11
  // ---------------------------------------------------------------------------
10
12
  describe("initial state", () => {
11
13
  it("returns default variables with pageSize 20", () => {
12
- const { result } = renderHook(() => useCollectionParams());
13
- expect(result.current.variables).toEqual({ first: 20 });
14
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
15
+ expect(result.current.toQueryArgs().variables).toEqual({ first: 20 });
14
16
  expect(result.current.filters).toEqual([]);
15
17
  expect(result.current.sortStates).toEqual([]);
16
18
  expect(result.current.cursor).toBeNull();
@@ -19,40 +21,45 @@ describe("useCollectionParams", () => {
19
21
 
20
22
  it("uses custom pageSize", () => {
21
23
  const { result } = renderHook(() =>
22
- useCollectionParams({ pageSize: 50 }),
24
+ useCollection({ query: FAKE_QUERY, params: { pageSize: 50 } }),
23
25
  );
24
- expect(result.current.variables.first).toBe(50);
26
+ expect(result.current.toQueryArgs().variables.first).toBe(50);
25
27
  });
26
28
 
27
29
  it("applies initial sort", () => {
28
30
  const { result } = renderHook(() =>
29
- useCollectionParams({
30
- initialSort: [{ field: "createdAt", direction: "Desc" }],
31
+ useCollection({
32
+ query: FAKE_QUERY,
33
+ params: {
34
+ initialSort: [{ field: "createdAt", direction: "Desc" }],
35
+ },
31
36
  }),
32
37
  );
33
38
  expect(result.current.sortStates).toEqual([
34
39
  { field: "createdAt", direction: "Desc" },
35
40
  ]);
36
- expect(result.current.variables.order).toEqual([
41
+ expect(result.current.toQueryArgs().variables.order).toEqual([
37
42
  { field: "createdAt", direction: "Desc" },
38
43
  ]);
39
44
  });
40
45
 
41
46
  it("applies initial filters", () => {
42
47
  const { result } = renderHook(() =>
43
- useCollectionParams({
44
- initialFilters: [
45
- {
46
- field: "status",
47
- fieldType: "enum",
48
- operator: "eq",
49
- value: "ACTIVE",
50
- },
51
- ],
48
+ useCollection({
49
+ query: FAKE_QUERY,
50
+ params: {
51
+ initialFilters: [
52
+ {
53
+ field: "status",
54
+ operator: "eq",
55
+ value: "ACTIVE",
56
+ },
57
+ ],
58
+ },
52
59
  }),
53
60
  );
54
61
  expect(result.current.filters).toHaveLength(1);
55
- expect(result.current.variables.query).toEqual({
62
+ expect(result.current.toQueryArgs().variables.query).toEqual({
56
63
  status: { eq: "ACTIVE" },
57
64
  });
58
65
  });
@@ -63,7 +70,7 @@ describe("useCollectionParams", () => {
63
70
  // ---------------------------------------------------------------------------
64
71
  describe("filter operations", () => {
65
72
  it("adds a filter", () => {
66
- const { result } = renderHook(() => useCollectionParams());
73
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
67
74
 
68
75
  act(() => {
69
76
  result.current.addFilter("status", "ACTIVE", "eq");
@@ -75,13 +82,13 @@ describe("useCollectionParams", () => {
75
82
  operator: "eq",
76
83
  value: "ACTIVE",
77
84
  });
78
- expect(result.current.variables.query).toEqual({
85
+ expect(result.current.toQueryArgs().variables.query).toEqual({
79
86
  status: { eq: "ACTIVE" },
80
87
  });
81
88
  });
82
89
 
83
90
  it("replaces filter for same field", () => {
84
- const { result } = renderHook(() => useCollectionParams());
91
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
85
92
 
86
93
  act(() => {
87
94
  result.current.addFilter("status", "ACTIVE", "eq");
@@ -95,19 +102,17 @@ describe("useCollectionParams", () => {
95
102
  });
96
103
 
97
104
  it("sets filters in bulk", () => {
98
- const { result } = renderHook(() => useCollectionParams());
105
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
99
106
 
100
107
  act(() => {
101
108
  result.current.setFilters([
102
109
  {
103
110
  field: "status",
104
- fieldType: "enum",
105
111
  operator: "eq",
106
112
  value: "ACTIVE",
107
113
  },
108
114
  {
109
115
  field: "amount",
110
- fieldType: "number",
111
116
  operator: "gte",
112
117
  value: 1000,
113
118
  },
@@ -115,14 +120,14 @@ describe("useCollectionParams", () => {
115
120
  });
116
121
 
117
122
  expect(result.current.filters).toHaveLength(2);
118
- expect(result.current.variables.query).toEqual({
123
+ expect(result.current.toQueryArgs().variables.query).toEqual({
119
124
  status: { eq: "ACTIVE" },
120
125
  amount: { gte: 1000 },
121
126
  });
122
127
  });
123
128
 
124
129
  it("removes a filter", () => {
125
- const { result } = renderHook(() => useCollectionParams());
130
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
126
131
 
127
132
  act(() => {
128
133
  result.current.addFilter("status", "ACTIVE", "eq");
@@ -137,7 +142,7 @@ describe("useCollectionParams", () => {
137
142
  });
138
143
 
139
144
  it("clears all filters", () => {
140
- const { result } = renderHook(() => useCollectionParams());
145
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
141
146
 
142
147
  act(() => {
143
148
  result.current.addFilter("status", "ACTIVE", "eq");
@@ -148,11 +153,11 @@ describe("useCollectionParams", () => {
148
153
  });
149
154
 
150
155
  expect(result.current.filters).toHaveLength(0);
151
- expect(result.current.variables.query).toBeUndefined();
156
+ expect(result.current.toQueryArgs().variables.query).toBeUndefined();
152
157
  });
153
158
 
154
159
  it("resets pagination when filters change", () => {
155
- const { result } = renderHook(() => useCollectionParams());
160
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
156
161
 
157
162
  // Navigate to next page
158
163
  act(() => {
@@ -174,7 +179,7 @@ describe("useCollectionParams", () => {
174
179
  // ---------------------------------------------------------------------------
175
180
  describe("sort operations", () => {
176
181
  it("sets sort", () => {
177
- const { result } = renderHook(() => useCollectionParams());
182
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
178
183
 
179
184
  act(() => {
180
185
  result.current.setSort("createdAt", "Desc");
@@ -183,13 +188,13 @@ describe("useCollectionParams", () => {
183
188
  expect(result.current.sortStates).toEqual([
184
189
  { field: "createdAt", direction: "Desc" },
185
190
  ]);
186
- expect(result.current.variables.order).toEqual([
191
+ expect(result.current.toQueryArgs().variables.order).toEqual([
187
192
  { field: "createdAt", direction: "Desc" },
188
193
  ]);
189
194
  });
190
195
 
191
196
  it("replaces sort by default", () => {
192
- const { result } = renderHook(() => useCollectionParams());
197
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
193
198
 
194
199
  act(() => {
195
200
  result.current.setSort("createdAt", "Desc");
@@ -204,7 +209,7 @@ describe("useCollectionParams", () => {
204
209
  });
205
210
 
206
211
  it("appends sort with append=true (multi-sort)", () => {
207
- const { result } = renderHook(() => useCollectionParams());
212
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
208
213
 
209
214
  act(() => {
210
215
  result.current.setSort("createdAt", "Desc");
@@ -220,7 +225,7 @@ describe("useCollectionParams", () => {
220
225
  });
221
226
 
222
227
  it("clears sort", () => {
223
- const { result } = renderHook(() => useCollectionParams());
228
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
224
229
 
225
230
  act(() => {
226
231
  result.current.setSort("createdAt", "Desc");
@@ -230,7 +235,7 @@ describe("useCollectionParams", () => {
230
235
  });
231
236
 
232
237
  expect(result.current.sortStates).toEqual([]);
233
- expect(result.current.variables.order).toBeUndefined();
238
+ expect(result.current.toQueryArgs().variables.order).toBeUndefined();
234
239
  });
235
240
  });
236
241
 
@@ -239,7 +244,7 @@ describe("useCollectionParams", () => {
239
244
  // ---------------------------------------------------------------------------
240
245
  describe("pagination operations", () => {
241
246
  it("navigates to next page", () => {
242
- const { result } = renderHook(() => useCollectionParams());
247
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
243
248
 
244
249
  act(() => {
245
250
  result.current.nextPage("cursor1");
@@ -247,11 +252,11 @@ describe("useCollectionParams", () => {
247
252
 
248
253
  expect(result.current.cursor).toBe("cursor1");
249
254
  expect(result.current.hasPrevPage).toBe(true);
250
- expect(result.current.variables.after).toBe("cursor1");
255
+ expect(result.current.toQueryArgs().variables.after).toBe("cursor1");
251
256
  });
252
257
 
253
258
  it("navigates back to previous page", () => {
254
- const { result } = renderHook(() => useCollectionParams());
259
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
255
260
 
256
261
  act(() => {
257
262
  result.current.nextPage("cursor1");
@@ -268,7 +273,7 @@ describe("useCollectionParams", () => {
268
273
  });
269
274
 
270
275
  it("navigates back to first page", () => {
271
- const { result } = renderHook(() => useCollectionParams());
276
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
272
277
 
273
278
  act(() => {
274
279
  result.current.nextPage("cursor1");
@@ -282,7 +287,7 @@ describe("useCollectionParams", () => {
282
287
  });
283
288
 
284
289
  it("resets page", () => {
285
- const { result } = renderHook(() => useCollectionParams());
290
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
286
291
 
287
292
  act(() => {
288
293
  result.current.nextPage("cursor1");
@@ -298,22 +303,24 @@ describe("useCollectionParams", () => {
298
303
  });
299
304
 
300
305
  // ---------------------------------------------------------------------------
301
- // variables generation
306
+ // toQueryArgs
302
307
  // ---------------------------------------------------------------------------
303
- describe("variables generation", () => {
308
+ describe("toQueryArgs", () => {
304
309
  it("generates complete variables with filters, sort, and cursor", () => {
305
310
  const { result } = renderHook(() =>
306
- useCollectionParams({
307
- pageSize: 10,
308
- initialFilters: [
309
- {
310
- field: "status",
311
- fieldType: "enum",
312
- operator: "eq",
313
- value: "ACTIVE",
314
- },
315
- ],
316
- initialSort: [{ field: "createdAt", direction: "Desc" }],
311
+ useCollection({
312
+ query: FAKE_QUERY,
313
+ params: {
314
+ pageSize: 10,
315
+ initialFilters: [
316
+ {
317
+ field: "status",
318
+ operator: "eq",
319
+ value: "ACTIVE",
320
+ },
321
+ ],
322
+ initialSort: [{ field: "createdAt", direction: "Desc" }],
323
+ },
317
324
  }),
318
325
  );
319
326
 
@@ -321,21 +328,37 @@ describe("useCollectionParams", () => {
321
328
  result.current.nextPage("abc123");
322
329
  });
323
330
 
324
- expect(result.current.variables).toEqual({
325
- first: 10,
326
- query: { status: { eq: "ACTIVE" } },
327
- order: [{ field: "createdAt", direction: "Desc" }],
328
- after: "abc123",
331
+ expect(result.current.toQueryArgs()).toEqual({
332
+ query: FAKE_QUERY,
333
+ variables: {
334
+ first: 10,
335
+ query: { status: { eq: "ACTIVE" } },
336
+ order: [{ field: "createdAt", direction: "Desc" }],
337
+ after: "abc123",
338
+ },
329
339
  });
330
340
  });
331
341
 
332
342
  it("omits undefined fields from variables", () => {
333
- const { result } = renderHook(() => useCollectionParams());
334
- const vars = result.current.variables;
335
- expect(vars).toEqual({ first: 20 });
336
- expect("query" in vars).toBe(false);
337
- expect("order" in vars).toBe(false);
338
- expect("after" in vars).toBe(false);
343
+ const { result } = renderHook(() => useCollection({ query: FAKE_QUERY }));
344
+ const { variables } = result.current.toQueryArgs();
345
+ expect(variables).toEqual({ first: 20 });
346
+ expect("query" in variables).toBe(false);
347
+ expect("order" in variables).toBe(false);
348
+ expect("after" in variables).toBe(false);
349
+ });
350
+
351
+ it("includes query in toQueryArgs result", () => {
352
+ const fakeQuery = { kind: "Document" } as const;
353
+ const { result } = renderHook(() =>
354
+ useCollection({ query: fakeQuery, params: { pageSize: 10 } }),
355
+ );
356
+
357
+ const args = result.current.toQueryArgs();
358
+ expect(args).toEqual({
359
+ query: fakeQuery,
360
+ variables: { first: 10 },
361
+ });
339
362
  });
340
363
  });
341
364
 
@@ -365,96 +388,25 @@ describe("useCollectionParams", () => {
365
388
 
366
389
  it("works with metadata and tableName", () => {
367
390
  const { result } = renderHook(() =>
368
- useCollectionParams({
369
- metadata: testMetadata,
370
- tableName: "task",
371
- pageSize: 10,
372
- }),
373
- );
374
- expect(result.current.variables).toEqual({ first: 10 });
375
- });
376
-
377
- it("auto-detects fieldType from metadata for string field", () => {
378
- const { result } = renderHook(() =>
379
- useCollectionParams({
380
- metadata: testMetadata,
381
- tableName: "task",
382
- }),
383
- );
384
-
385
- act(() => {
386
- result.current.addFilter("title", "foo");
387
- });
388
-
389
- expect(result.current.filters[0].fieldType).toBe("string");
390
- });
391
-
392
- it("auto-detects fieldType from metadata for enum field", () => {
393
- const { result } = renderHook(() =>
394
- useCollectionParams({
395
- metadata: testMetadata,
396
- tableName: "task",
397
- }),
398
- );
399
-
400
- act(() => {
401
- result.current.addFilter("status", "todo");
402
- });
403
-
404
- expect(result.current.filters[0].fieldType).toBe("enum");
405
- });
406
-
407
- it("auto-detects fieldType from metadata for date field", () => {
408
- const { result } = renderHook(() =>
409
- useCollectionParams({
391
+ useCollection({
410
392
  metadata: testMetadata,
411
393
  tableName: "task",
394
+ query: FAKE_QUERY,
395
+ params: { pageSize: 10 },
412
396
  }),
413
397
  );
414
-
415
- act(() => {
416
- result.current.addFilter("dueDate", "2026-01-01");
417
- });
418
-
419
- expect(result.current.filters[0].fieldType).toBe("date");
420
- });
421
-
422
- it("auto-detects fieldType from metadata for uuid field", () => {
423
- const { result } = renderHook(() =>
424
- useCollectionParams({
425
- metadata: testMetadata,
426
- tableName: "task",
427
- }),
428
- );
429
-
430
- act(() => {
431
- result.current.addFilter("id", "some-uuid");
432
- });
433
-
434
- expect(result.current.filters[0].fieldType).toBe("uuid");
435
- });
436
-
437
- it("auto-detects fieldType from metadata for number field", () => {
438
- const { result } = renderHook(() =>
439
- useCollectionParams({
440
- metadata: testMetadata,
441
- tableName: "task",
442
- }),
443
- );
444
-
445
- act(() => {
446
- result.current.addFilter("count", 42);
447
- });
448
-
449
- expect(result.current.filters[0].fieldType).toBe("number");
398
+ expect(result.current.toQueryArgs().variables).toEqual({ first: 10 });
450
399
  });
451
400
 
452
401
  it("applies typed initialSort", () => {
453
402
  const { result } = renderHook(() =>
454
- useCollectionParams({
403
+ useCollection({
455
404
  metadata: testMetadata,
456
405
  tableName: "task",
457
- initialSort: [{ field: "dueDate", direction: "Desc" }],
406
+ query: FAKE_QUERY,
407
+ params: {
408
+ initialSort: [{ field: "dueDate", direction: "Desc" }],
409
+ },
458
410
  }),
459
411
  );
460
412
 
@@ -1,20 +1,27 @@
1
- import { useCallback, useMemo, useRef, useState } from "react";
2
- import type {
3
- FieldType,
4
- TableMetadataMap,
5
- } from "../../generator/metadata-generator";
1
+ import { useCallback, useMemo, useState } from "react";
2
+ import type { TableMetadataMap } from "../../generator/metadata-generator";
6
3
  import type {
7
4
  Filter,
8
5
  FilterOperator,
6
+ MetadataFilter,
9
7
  QueryVariables,
10
8
  SortState,
11
- UseCollectionParamsOptions,
12
- UseCollectionParamsReturn,
9
+ UseCollectionOptions,
10
+ UseCollectionReturn,
13
11
  ExtractQueryVariables,
14
12
  } from "../types";
15
- import { fieldTypeToFilterConfig } from "../types";
16
13
  import type { FieldName } from "../types";
17
14
 
15
+ /**
16
+ * Resolves query variables type: uses `ExtractQueryVariables<TQuery>` when
17
+ * the query document carries a `__variablesType` brand (e.g. gql-tada),
18
+ * otherwise falls back to `QueryVariables<TFieldName>`.
19
+ */
20
+ type ResolveVariables<TQuery, TFieldName extends string = string> =
21
+ ExtractQueryVariables<TQuery> extends never
22
+ ? QueryVariables<TFieldName>
23
+ : ExtractQueryVariables<TQuery>;
24
+
18
25
  // -----------------------------------------------------------------------------
19
26
  // Overload signatures
20
27
  // -----------------------------------------------------------------------------
@@ -23,97 +30,91 @@ import type { FieldName } from "../types";
23
30
  * Hook for managing collection query parameters (filters, sort, pagination)
24
31
  * with metadata-based field name typing and automatic `fieldType` detection.
25
32
  *
26
- * When `query` is provided, the output `variables` is typed to match
27
- * the GraphQL query's expected variables (e.g. `VariablesOf<typeof QUERY>`).
28
- * The `query` value is only used for type inference and ignored at runtime.
33
+ * `toQueryArgs()` returns `{ query, variables }` so the result can be
34
+ * spread directly into `useQuery()`.
29
35
  *
30
36
  * @example
31
37
  * ```tsx
32
38
  * import { tableMetadata } from "./generated/data-viewer-metadata.generated";
33
39
  *
34
- * // Without query — variables typed as QueryVariables<FieldName>
35
- * const params = useCollectionParams({
36
- * metadata: tableMetadata,
37
- * tableName: "task",
38
- * pageSize: 20,
39
- * });
40
- *
41
- * // With query — variables typed as VariablesOf<typeof GET_TASKS>
42
- * const params = useCollectionParams({
40
+ * const collection = useCollection({
43
41
  * metadata: tableMetadata,
44
42
  * tableName: "task",
45
43
  * query: GET_TASKS,
46
- * pageSize: 20,
44
+ * params: { pageSize: 20 },
47
45
  * });
46
+ * const [result] = useQuery({ ...collection.toQueryArgs() });
48
47
  * ```
49
48
  */
50
- export function useCollectionParams<
49
+ export function useCollection<
51
50
  const TMetadata extends TableMetadataMap,
52
51
  TTableName extends string & keyof TMetadata,
53
- TQuery = never,
52
+ TQuery,
54
53
  >(
55
- options: UseCollectionParamsOptions<FieldName<TMetadata, TTableName>> & {
54
+ options: UseCollectionOptions<
55
+ FieldName<TMetadata, TTableName>,
56
+ MetadataFilter<TMetadata, TTableName>
57
+ > & {
56
58
  metadata: TMetadata;
57
59
  tableName: TTableName;
58
- query?: TQuery;
60
+ query: TQuery;
59
61
  },
60
- ): UseCollectionParamsReturn<
62
+ ): UseCollectionReturn<
61
63
  FieldName<TMetadata, TTableName>,
62
- [TQuery] extends [never]
63
- ? QueryVariables<FieldName<TMetadata, TTableName>>
64
- : ExtractQueryVariables<TQuery>
64
+ ResolveVariables<TQuery, FieldName<TMetadata, TTableName>>,
65
+ {
66
+ query: TQuery;
67
+ variables: ResolveVariables<TQuery, FieldName<TMetadata, TTableName>>;
68
+ }
65
69
  >;
66
70
 
67
71
  /**
68
72
  * Hook for managing collection query parameters (filters, sort, pagination).
69
73
  *
70
74
  * Produces `variables` in Tailor Platform format that can be passed directly
71
- * to a GraphQL query (e.g. urql's `useQuery`).
75
+ * to a GraphQL query (e.g. urql's `useQuery`) via `toQueryArgs()`.
72
76
  *
73
- * When `query` is provided, the output `variables` is typed to match
74
- * the GraphQL query's expected variables.
77
+ * `toQueryArgs()` returns `{ query, variables }` so the result can be spread
78
+ * directly into `useQuery()`.
75
79
  *
76
80
  * @example
77
81
  * ```tsx
78
- * const params = useCollectionParams({ pageSize: 20 });
79
- * const [result] = useQuery({ query: GET_ORDERS, variables: params.variables });
80
- *
81
- * // With query — variables auto-typed
82
- * const params = useCollectionParams({ query: GET_ORDERS, pageSize: 20 });
82
+ * const collection = useCollection({ query: GET_ORDERS, params: { pageSize: 20 } });
83
+ * const [result] = useQuery({ ...collection.toQueryArgs() });
83
84
  * ```
84
85
  */
85
- export function useCollectionParams<TQuery = never>(
86
- options?: UseCollectionParamsOptions & {
87
- query?: TQuery;
86
+ export function useCollection<TQuery>(
87
+ options: UseCollectionOptions & {
88
+ query: TQuery;
88
89
  metadata?: never;
89
90
  tableName?: never;
90
91
  },
91
- ): UseCollectionParamsReturn<
92
+ ): UseCollectionReturn<
92
93
  string,
93
- [TQuery] extends [never] ? QueryVariables : ExtractQueryVariables<TQuery>
94
+ ResolveVariables<TQuery>,
95
+ { query: TQuery; variables: ResolveVariables<TQuery> }
94
96
  >;
95
97
 
96
98
  // -----------------------------------------------------------------------------
97
99
  // Implementation
98
100
  // -----------------------------------------------------------------------------
99
- export function useCollectionParams(
100
- options: UseCollectionParamsOptions & {
101
+ export function useCollection(
102
+ options: UseCollectionOptions & {
101
103
  metadata?: TableMetadataMap;
102
104
  tableName?: string;
103
- } = {},
104
- ): UseCollectionParamsReturn {
105
+ query: unknown;
106
+ },
107
+ ): UseCollectionReturn<
108
+ string,
109
+ QueryVariables,
110
+ { query: unknown; variables: QueryVariables }
111
+ > {
112
+ const { params = {}, query: queryDocument } = options;
105
113
  const {
106
114
  initialFilters = [],
107
115
  initialSort = [],
108
116
  pageSize: initialPageSize = 20,
109
- metadata,
110
- tableName,
111
- } = options;
112
-
113
- // Keep a ref to the resolved fields list so callbacks can look up fieldType.
114
- const fieldsRef = useRef(
115
- metadata && tableName ? metadata[tableName]?.fields : undefined,
116
- );
117
+ } = params;
117
118
 
118
119
  // ---------------------------------------------------------------------------
119
120
  // State
@@ -131,17 +132,8 @@ export function useCollectionParams(
131
132
  (field: string, value: unknown, operator: FilterOperator = "eq") => {
132
133
  setFiltersState((prev) => {
133
134
  const existing = prev.findIndex((f) => f.field === field);
134
- // Auto-detect fieldType from metadata when available
135
- const fieldMeta = fieldsRef.current?.find((f) => f.name === field);
136
- const detectedType: Filter["fieldType"] = fieldMeta
137
- ? (fieldTypeToFilterConfig(
138
- fieldMeta.type as FieldType,
139
- fieldMeta.enumValues as readonly string[] | undefined,
140
- )?.type ?? "string")
141
- : "string";
142
135
  const newFilter: Filter = {
143
136
  field,
144
- fieldType: detectedType,
145
137
  operator,
146
138
  value,
147
139
  };
@@ -245,11 +237,11 @@ export function useCollectionParams(
245
237
 
246
238
  // Build query (filters)
247
239
  if (filters.length > 0) {
248
- const query: Record<string, unknown> = {};
240
+ const filterQuery: Record<string, unknown> = {};
249
241
  for (const filter of filters) {
250
- query[filter.field] = { [filter.operator]: filter.value };
242
+ filterQuery[filter.field] = { [filter.operator]: filter.value };
251
243
  }
252
- vars.query = query;
244
+ vars.query = filterQuery;
253
245
  }
254
246
 
255
247
  // Build order (sort)
@@ -268,11 +260,18 @@ export function useCollectionParams(
268
260
  return vars;
269
261
  }, [filters, sortStates, pageSize, cursor]);
270
262
 
263
+ // ---------------------------------------------------------------------------
264
+ // toQueryArgs
265
+ // ---------------------------------------------------------------------------
266
+ const toQueryArgs = useCallback(() => {
267
+ return { query: queryDocument, variables };
268
+ }, [queryDocument, variables]);
269
+
271
270
  // ---------------------------------------------------------------------------
272
271
  // Return
273
272
  // ---------------------------------------------------------------------------
274
273
  return {
275
- variables,
274
+ toQueryArgs,
276
275
  filters,
277
276
  addFilter,
278
277
  setFilters,
@@ -302,7 +302,7 @@ function formatValue(value: unknown): ReactNode {
302
302
  *
303
303
  * @example
304
304
  * ```tsx
305
- * const table = useDataTable({ columns, data, loading, collectionParams: params });
305
+ * const table = useDataTable({ columns, data, loading, collection });
306
306
  *
307
307
  * <DataTable.Root {...table.rootProps}>
308
308
  * <DataTable.Headers />