@izumisy-tailor/tailor-data-viewer 0.2.15 → 0.2.16
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/README.md +2 -2
- package/package.json +1 -1
- package/src/component/collection/use-collection.test.ts +3 -5
- package/src/component/collection/use-collection.ts +14 -19
- package/src/component/field-helpers.test.ts +19 -45
- package/src/component/field-helpers.ts +13 -22
- package/src/component/index.ts +4 -1
- package/src/component/types.ts +65 -27
package/README.md
CHANGED
|
@@ -215,7 +215,7 @@ export default defineConfig({
|
|
|
215
215
|
tailor-sdk generate
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
-
### `inferColumnHelper(
|
|
218
|
+
### `inferColumnHelper(tableMetadata)`
|
|
219
219
|
|
|
220
220
|
`field()` requires manually specifying `sort`/`filter` type configs and enum `options` for every column. `inferColumnHelper()` eliminates this boilerplate by automatically deriving these from the generated table metadata. Based on each field's type (string, number, date, enum, etc.), the appropriate `SortConfig` / `FilterConfig` is set automatically, and enum fields get their options populated from the schema.
|
|
221
221
|
|
|
@@ -223,7 +223,7 @@ tailor-sdk generate
|
|
|
223
223
|
import { inferColumnHelper, display } from "@izumisy-tailor/tailor-data-viewer/component";
|
|
224
224
|
import { tableMetadata } from "./generated/data-viewer-metadata.generated";
|
|
225
225
|
|
|
226
|
-
const { column, columns } = inferColumnHelper(tableMetadata
|
|
226
|
+
const { column, columns } = inferColumnHelper(tableMetadata.task);
|
|
227
227
|
|
|
228
228
|
const taskColumns = [
|
|
229
229
|
column("title"), // sort/filter auto-configured from metadata
|
package/package.json
CHANGED
|
@@ -409,11 +409,10 @@ describe("useCollection", () => {
|
|
|
409
409
|
},
|
|
410
410
|
} as const satisfies TableMetadataMap;
|
|
411
411
|
|
|
412
|
-
it("works with
|
|
412
|
+
it("works with tableMetadata", () => {
|
|
413
413
|
const { result } = renderHook(() =>
|
|
414
414
|
useCollection({
|
|
415
|
-
|
|
416
|
-
tableName: "task",
|
|
415
|
+
tableMetadata: testMetadata.task,
|
|
417
416
|
query: FAKE_QUERY,
|
|
418
417
|
params: { pageSize: 10 },
|
|
419
418
|
}),
|
|
@@ -424,8 +423,7 @@ describe("useCollection", () => {
|
|
|
424
423
|
it("applies typed initialSort", () => {
|
|
425
424
|
const { result } = renderHook(() =>
|
|
426
425
|
useCollection({
|
|
427
|
-
|
|
428
|
-
tableName: "task",
|
|
426
|
+
tableMetadata: testMetadata.task,
|
|
429
427
|
query: FAKE_QUERY,
|
|
430
428
|
params: {
|
|
431
429
|
initialSort: [{ field: "dueDate", direction: "Desc" }],
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState } from "react";
|
|
2
|
-
import type {
|
|
2
|
+
import type { TableMetadata } from "../../generator/metadata-generator";
|
|
3
3
|
import type {
|
|
4
4
|
Filter,
|
|
5
5
|
FilterOperator,
|
|
6
|
-
|
|
6
|
+
TableMetadataFilter,
|
|
7
7
|
PageInfo,
|
|
8
8
|
QueryVariables,
|
|
9
9
|
SortState,
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
ExtractQueryVariables,
|
|
13
13
|
ValidateCollectionQuery,
|
|
14
14
|
} from "../types";
|
|
15
|
-
import type {
|
|
15
|
+
import type { TableFieldName, TableOrderableFieldName } from "../types";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Resolves the variables type for `toQueryArgs()` return value.
|
|
@@ -47,8 +47,7 @@ type ResolveVariables<TQuery> =
|
|
|
47
47
|
* import { tableMetadata } from "./generated/data-viewer-metadata.generated";
|
|
48
48
|
*
|
|
49
49
|
* const collection = useCollection({
|
|
50
|
-
*
|
|
51
|
-
* tableName: "task",
|
|
50
|
+
* tableMetadata: tableMetadata.task,
|
|
52
51
|
* query: GET_TASKS,
|
|
53
52
|
* params: { pageSize: 20 },
|
|
54
53
|
* });
|
|
@@ -56,29 +55,27 @@ type ResolveVariables<TQuery> =
|
|
|
56
55
|
* ```
|
|
57
56
|
*/
|
|
58
57
|
export function useCollection<
|
|
59
|
-
const
|
|
60
|
-
TTableName extends string & keyof TMetadata,
|
|
58
|
+
const TTable extends TableMetadata,
|
|
61
59
|
TQuery,
|
|
62
60
|
>(
|
|
63
61
|
options: UseCollectionOptions<
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
TableFieldName<TTable>,
|
|
63
|
+
TableMetadataFilter<TTable>
|
|
66
64
|
> & {
|
|
67
|
-
|
|
68
|
-
tableName: TTableName;
|
|
65
|
+
tableMetadata: TTable;
|
|
69
66
|
query: ValidateCollectionQuery<
|
|
70
67
|
TQuery,
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
TableFieldName<TTable>,
|
|
69
|
+
TableOrderableFieldName<TTable>
|
|
73
70
|
>;
|
|
74
71
|
},
|
|
75
72
|
): UseCollectionReturn<
|
|
76
|
-
|
|
73
|
+
TableFieldName<TTable>,
|
|
77
74
|
{
|
|
78
75
|
query: TQuery;
|
|
79
76
|
variables: ResolveVariables<TQuery>;
|
|
80
77
|
},
|
|
81
|
-
|
|
78
|
+
TableMetadataFilter<TTable>
|
|
82
79
|
>;
|
|
83
80
|
|
|
84
81
|
/**
|
|
@@ -99,8 +96,7 @@ export function useCollection<
|
|
|
99
96
|
export function useCollection<TQuery>(
|
|
100
97
|
options: UseCollectionOptions & {
|
|
101
98
|
query: TQuery;
|
|
102
|
-
|
|
103
|
-
tableName?: never;
|
|
99
|
+
tableMetadata?: never;
|
|
104
100
|
},
|
|
105
101
|
): UseCollectionReturn<
|
|
106
102
|
string,
|
|
@@ -112,8 +108,7 @@ export function useCollection<TQuery>(
|
|
|
112
108
|
// -----------------------------------------------------------------------------
|
|
113
109
|
export function useCollection(
|
|
114
110
|
options: UseCollectionOptions & {
|
|
115
|
-
|
|
116
|
-
tableName?: string;
|
|
111
|
+
tableMetadata?: TableMetadata;
|
|
117
112
|
query: unknown;
|
|
118
113
|
},
|
|
119
114
|
): UseCollectionReturn<string, { query: unknown; variables: QueryVariables }> {
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect, expectTypeOf } from "vitest";
|
|
|
2
2
|
import { createColumnHelper, inferColumnHelper } from "./field-helpers";
|
|
3
3
|
import type { TableMetadataMap } from "../generator/metadata-generator";
|
|
4
4
|
import { fieldTypeToSortConfig, fieldTypeToFilterConfig } from "./types";
|
|
5
|
-
import type { NodeType } from "./types";
|
|
5
|
+
import type { NodeType, TableFieldName } from "./types";
|
|
6
6
|
|
|
7
7
|
describe("NodeType", () => {
|
|
8
8
|
it("extracts node type from a collection result", () => {
|
|
@@ -167,10 +167,7 @@ describe("inferColumnHelper()", () => {
|
|
|
167
167
|
} as const satisfies TableMetadataMap;
|
|
168
168
|
|
|
169
169
|
it("creates a column with auto-detected sort/filter", () => {
|
|
170
|
-
const { column } = inferColumnHelper(
|
|
171
|
-
metadata: testMetadata,
|
|
172
|
-
tableName: "task",
|
|
173
|
-
});
|
|
170
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
174
171
|
|
|
175
172
|
const titleCol = column("title");
|
|
176
173
|
expect(titleCol.kind).toBe("field");
|
|
@@ -180,10 +177,7 @@ describe("inferColumnHelper()", () => {
|
|
|
180
177
|
});
|
|
181
178
|
|
|
182
179
|
it("auto-detects enum options", () => {
|
|
183
|
-
const { column } = inferColumnHelper(
|
|
184
|
-
metadata: testMetadata,
|
|
185
|
-
tableName: "task",
|
|
186
|
-
});
|
|
180
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
187
181
|
const statusCol = column("status");
|
|
188
182
|
expect(statusCol.filter).toEqual({
|
|
189
183
|
type: "enum",
|
|
@@ -198,60 +192,42 @@ describe("inferColumnHelper()", () => {
|
|
|
198
192
|
});
|
|
199
193
|
|
|
200
194
|
it("auto-detects date type", () => {
|
|
201
|
-
const { column } = inferColumnHelper(
|
|
202
|
-
metadata: testMetadata,
|
|
203
|
-
tableName: "task",
|
|
204
|
-
});
|
|
195
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
205
196
|
const dateCol = column("dueDate");
|
|
206
197
|
expect(dateCol.sort).toEqual({ type: "date" });
|
|
207
198
|
expect(dateCol.filter).toEqual({ type: "date" });
|
|
208
199
|
});
|
|
209
200
|
|
|
210
201
|
it("disables sort with sort: false", () => {
|
|
211
|
-
const { column } = inferColumnHelper(
|
|
212
|
-
metadata: testMetadata,
|
|
213
|
-
tableName: "task",
|
|
214
|
-
});
|
|
202
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
215
203
|
const col = column("title", { sort: false });
|
|
216
204
|
expect(col.sort).toBeUndefined();
|
|
217
205
|
expect(col.filter).toEqual({ type: "string" });
|
|
218
206
|
});
|
|
219
207
|
|
|
220
208
|
it("disables filter with filter: false", () => {
|
|
221
|
-
const { column } = inferColumnHelper(
|
|
222
|
-
metadata: testMetadata,
|
|
223
|
-
tableName: "task",
|
|
224
|
-
});
|
|
209
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
225
210
|
const col = column("title", { filter: false });
|
|
226
211
|
expect(col.sort).toEqual({ type: "string" });
|
|
227
212
|
expect(col.filter).toBeUndefined();
|
|
228
213
|
});
|
|
229
214
|
|
|
230
215
|
it("uuid has no sort, has uuid filter", () => {
|
|
231
|
-
const { column } = inferColumnHelper(
|
|
232
|
-
metadata: testMetadata,
|
|
233
|
-
tableName: "task",
|
|
234
|
-
});
|
|
216
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
235
217
|
const col = column("id");
|
|
236
218
|
expect(col.sort).toBeUndefined();
|
|
237
219
|
expect(col.filter).toEqual({ type: "uuid" });
|
|
238
220
|
});
|
|
239
221
|
|
|
240
222
|
it("array type has no sort/filter", () => {
|
|
241
|
-
const { column } = inferColumnHelper(
|
|
242
|
-
metadata: testMetadata,
|
|
243
|
-
tableName: "task",
|
|
244
|
-
});
|
|
223
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
245
224
|
const col = column("tags");
|
|
246
225
|
expect(col.sort).toBeUndefined();
|
|
247
226
|
expect(col.filter).toBeUndefined();
|
|
248
227
|
});
|
|
249
228
|
|
|
250
229
|
it("columns() creates multiple columns at once", () => {
|
|
251
|
-
const { columns } = inferColumnHelper(
|
|
252
|
-
metadata: testMetadata,
|
|
253
|
-
tableName: "task",
|
|
254
|
-
});
|
|
230
|
+
const { columns } = inferColumnHelper(testMetadata.task);
|
|
255
231
|
const cols = columns(["title", "status", "dueDate"]);
|
|
256
232
|
expect(cols).toHaveLength(3);
|
|
257
233
|
expect(cols[0].dataKey).toBe("title");
|
|
@@ -260,10 +236,7 @@ describe("inferColumnHelper()", () => {
|
|
|
260
236
|
});
|
|
261
237
|
|
|
262
238
|
it("columns() applies overrides", () => {
|
|
263
|
-
const { columns } = inferColumnHelper(
|
|
264
|
-
metadata: testMetadata,
|
|
265
|
-
tableName: "task",
|
|
266
|
-
});
|
|
239
|
+
const { columns } = inferColumnHelper(testMetadata.task);
|
|
267
240
|
const cols = columns(["title", "status"], {
|
|
268
241
|
overrides: {
|
|
269
242
|
title: { label: "Custom Title", width: 300 },
|
|
@@ -274,10 +247,7 @@ describe("inferColumnHelper()", () => {
|
|
|
274
247
|
});
|
|
275
248
|
|
|
276
249
|
it("columns() applies global sort/filter options", () => {
|
|
277
|
-
const { columns } = inferColumnHelper(
|
|
278
|
-
metadata: testMetadata,
|
|
279
|
-
tableName: "task",
|
|
280
|
-
});
|
|
250
|
+
const { columns } = inferColumnHelper(testMetadata.task);
|
|
281
251
|
const cols = columns(["title", "status"], { sort: false });
|
|
282
252
|
expect(cols[0].sort).toBeUndefined();
|
|
283
253
|
expect(cols[1].sort).toBeUndefined();
|
|
@@ -286,13 +256,17 @@ describe("inferColumnHelper()", () => {
|
|
|
286
256
|
});
|
|
287
257
|
|
|
288
258
|
it("throws for non-existent field", () => {
|
|
289
|
-
const { column } = inferColumnHelper(
|
|
290
|
-
metadata: testMetadata,
|
|
291
|
-
tableName: "task",
|
|
292
|
-
});
|
|
259
|
+
const { column } = inferColumnHelper(testMetadata.task);
|
|
293
260
|
// @ts-expect-error - intentionally testing invalid field name
|
|
294
261
|
expect(() => column("nonExistent")).toThrow(
|
|
295
262
|
'Field "nonExistent" not found in table "task" metadata',
|
|
296
263
|
);
|
|
297
264
|
});
|
|
265
|
+
|
|
266
|
+
it("infers TableFieldName type correctly", () => {
|
|
267
|
+
type TaskFieldNames = TableFieldName<(typeof testMetadata)["task"]>;
|
|
268
|
+
expectTypeOf<TaskFieldNames>().toEqualTypeOf<
|
|
269
|
+
"id" | "title" | "status" | "dueDate" | "count" | "isActive" | "tags"
|
|
270
|
+
>();
|
|
271
|
+
});
|
|
298
272
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TableMetadata } from "../generator/metadata-generator";
|
|
2
2
|
import type {
|
|
3
3
|
CellRenderer,
|
|
4
4
|
DisplayColumn,
|
|
5
5
|
DisplayColumnOptions,
|
|
6
6
|
FieldColumn,
|
|
7
7
|
FieldColumnOptions,
|
|
8
|
-
|
|
8
|
+
TableFieldName,
|
|
9
9
|
FilterConfig,
|
|
10
10
|
MetadataFieldOptions,
|
|
11
11
|
MetadataFieldsOptions,
|
|
@@ -130,16 +130,13 @@ export function createColumnHelper<TRow extends Record<string, unknown>>(): {
|
|
|
130
130
|
* Automatically infers sort/filter configuration from field types,
|
|
131
131
|
* including enum options.
|
|
132
132
|
*
|
|
133
|
-
* @param
|
|
133
|
+
* @param tableMetadata - A single table metadata object from the generated map.
|
|
134
134
|
*
|
|
135
135
|
* @example
|
|
136
136
|
* ```tsx
|
|
137
137
|
* import { tableMetadata } from "./generated/data-viewer-metadata.generated";
|
|
138
138
|
*
|
|
139
|
-
* const { column, columns } = inferColumnHelper(
|
|
140
|
-
* metadata: tableMetadata,
|
|
141
|
-
* tableName: "task",
|
|
142
|
-
* });
|
|
139
|
+
* const { column, columns } = inferColumnHelper(tableMetadata.task);
|
|
143
140
|
*
|
|
144
141
|
* const taskColumns = [
|
|
145
142
|
* column("title"), // sort/filter auto-detected
|
|
@@ -149,35 +146,29 @@ export function createColumnHelper<TRow extends Record<string, unknown>>(): {
|
|
|
149
146
|
* ];
|
|
150
147
|
* ```
|
|
151
148
|
*/
|
|
152
|
-
export function inferColumnHelper<
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
>(options: {
|
|
156
|
-
metadata: TMetadata;
|
|
157
|
-
tableName: TTableName;
|
|
158
|
-
}): {
|
|
149
|
+
export function inferColumnHelper<const TTable extends TableMetadata>(
|
|
150
|
+
tableMetadata: TTable,
|
|
151
|
+
): {
|
|
159
152
|
column: (
|
|
160
|
-
dataKey:
|
|
153
|
+
dataKey: TableFieldName<TTable>,
|
|
161
154
|
options?: MetadataFieldOptions,
|
|
162
155
|
) => FieldColumn<Record<string, unknown>>;
|
|
163
156
|
|
|
164
157
|
columns: (
|
|
165
|
-
dataKeys:
|
|
158
|
+
dataKeys: TableFieldName<TTable>[],
|
|
166
159
|
options?: MetadataFieldsOptions,
|
|
167
160
|
) => FieldColumn<Record<string, unknown>>[];
|
|
168
161
|
} {
|
|
169
|
-
const
|
|
170
|
-
const tableMeta = metadata[tableName];
|
|
171
|
-
const fields = tableMeta.fields;
|
|
162
|
+
const fields = tableMetadata.fields;
|
|
172
163
|
|
|
173
164
|
const column = (
|
|
174
|
-
dataKey:
|
|
165
|
+
dataKey: TableFieldName<TTable>,
|
|
175
166
|
columnOptions?: MetadataFieldOptions,
|
|
176
167
|
): FieldColumn<Record<string, unknown>> => {
|
|
177
168
|
const fieldMeta = fields.find((f) => f.name === dataKey);
|
|
178
169
|
if (!fieldMeta) {
|
|
179
170
|
throw new Error(
|
|
180
|
-
`Field "${String(dataKey)}" not found in table "${
|
|
171
|
+
`Field "${String(dataKey)}" not found in table "${tableMetadata.name}" metadata`,
|
|
181
172
|
);
|
|
182
173
|
}
|
|
183
174
|
|
|
@@ -213,7 +204,7 @@ export function inferColumnHelper<
|
|
|
213
204
|
};
|
|
214
205
|
|
|
215
206
|
const columnsHelper = (
|
|
216
|
-
dataKeys:
|
|
207
|
+
dataKeys: TableFieldName<TTable>[],
|
|
217
208
|
options?: MetadataFieldsOptions,
|
|
218
209
|
): FieldColumn<Record<string, unknown>>[] => {
|
|
219
210
|
return dataKeys.map((dataKey) => {
|
package/src/component/index.ts
CHANGED
|
@@ -5,7 +5,6 @@ export type {
|
|
|
5
5
|
SelectOption,
|
|
6
6
|
FilterOperator,
|
|
7
7
|
Filter,
|
|
8
|
-
MetadataFilter,
|
|
9
8
|
SortState,
|
|
10
9
|
PageInfo,
|
|
11
10
|
QueryVariables,
|
|
@@ -28,7 +27,9 @@ export type {
|
|
|
28
27
|
DataTableRowProps,
|
|
29
28
|
DataTableCellProps,
|
|
30
29
|
FieldName,
|
|
30
|
+
TableFieldName,
|
|
31
31
|
OrderableFieldName,
|
|
32
|
+
TableOrderableFieldName,
|
|
32
33
|
ExtractOrderField,
|
|
33
34
|
ExtractQueryVariables,
|
|
34
35
|
ExtractQueryInputKeys,
|
|
@@ -37,6 +38,8 @@ export type {
|
|
|
37
38
|
MatchingTableName,
|
|
38
39
|
MetadataFieldOptions,
|
|
39
40
|
MetadataFieldsOptions,
|
|
41
|
+
MetadataFilter,
|
|
42
|
+
TableMetadataFilter,
|
|
40
43
|
ColumnSelectorProps,
|
|
41
44
|
CsvButtonProps,
|
|
42
45
|
SearchFilterFormProps,
|
package/src/component/types.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type {
|
|
3
3
|
FieldType,
|
|
4
|
+
TableMetadata,
|
|
4
5
|
TableMetadataMap,
|
|
5
6
|
} from "../generator/metadata-generator";
|
|
6
7
|
|
|
@@ -144,24 +145,40 @@ export interface Filter<TFieldName extends string = string> {
|
|
|
144
145
|
* // | { field: "status"; operator: "eq" | "ne" | "in" | "notIn"; value: unknown }
|
|
145
146
|
* ```
|
|
146
147
|
*/
|
|
148
|
+
/**
|
|
149
|
+
* Metadata-aware filter type from a single table metadata object.
|
|
150
|
+
*
|
|
151
|
+
* Given table metadata, produces a discriminated union over each field
|
|
152
|
+
* where the `operator` is narrowed to only those valid for that field's type.
|
|
153
|
+
*
|
|
154
|
+
* @typeParam TTable - A single table metadata object (as const).
|
|
155
|
+
*/
|
|
156
|
+
export type TableMetadataFilter<TTable extends TableMetadata> =
|
|
157
|
+
TTable["fields"][number] extends infer F
|
|
158
|
+
? F extends { readonly name: infer N; readonly type: infer T }
|
|
159
|
+
? N extends string
|
|
160
|
+
? T extends keyof FieldTypeToFilterConfigType
|
|
161
|
+
? FieldTypeToFilterConfigType[T] extends never
|
|
162
|
+
? never
|
|
163
|
+
: {
|
|
164
|
+
field: N;
|
|
165
|
+
operator: OperatorForFilterType[FieldTypeToFilterConfigType[T]];
|
|
166
|
+
value: unknown;
|
|
167
|
+
}
|
|
168
|
+
: never
|
|
169
|
+
: never
|
|
170
|
+
: never
|
|
171
|
+
: never;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Metadata-aware filter type.
|
|
175
|
+
*
|
|
176
|
+
* @deprecated Use `TableMetadataFilter<TMetadata[TTableName]>` instead.
|
|
177
|
+
*/
|
|
147
178
|
export type MetadataFilter<
|
|
148
179
|
TMetadata extends TableMetadataMap,
|
|
149
180
|
TTableName extends string & keyof TMetadata,
|
|
150
|
-
> = TMetadata[TTableName]
|
|
151
|
-
? F extends { readonly name: infer N; readonly type: infer T }
|
|
152
|
-
? N extends string
|
|
153
|
-
? T extends keyof FieldTypeToFilterConfigType
|
|
154
|
-
? FieldTypeToFilterConfigType[T] extends never
|
|
155
|
-
? never
|
|
156
|
-
: {
|
|
157
|
-
field: N;
|
|
158
|
-
operator: OperatorForFilterType[FieldTypeToFilterConfigType[T]];
|
|
159
|
-
value: unknown;
|
|
160
|
-
}
|
|
161
|
-
: never
|
|
162
|
-
: never
|
|
163
|
-
: never
|
|
164
|
-
: never;
|
|
181
|
+
> = TableMetadataFilter<TMetadata[TTableName]>;
|
|
165
182
|
|
|
166
183
|
/**
|
|
167
184
|
* Active sort state for a single field.
|
|
@@ -599,16 +616,30 @@ export interface UseDataTableReturn<TRow extends Record<string, unknown>> {
|
|
|
599
616
|
// =============================================================================
|
|
600
617
|
|
|
601
618
|
/**
|
|
602
|
-
* Extract field names from table metadata.
|
|
619
|
+
* Extract field names from a single table metadata object.
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```ts
|
|
623
|
+
* type Names = TableFieldName<typeof tableMetadata.task>;
|
|
624
|
+
* // → "id" | "title" | "status" | "dueDate" | ...
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
export type TableFieldName<TTable extends TableMetadata> =
|
|
628
|
+
TTable["fields"][number] extends { readonly name: infer N }
|
|
629
|
+
? N extends string
|
|
630
|
+
? N
|
|
631
|
+
: never
|
|
632
|
+
: never;
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Extract field names from table metadata map + table name.
|
|
636
|
+
*
|
|
637
|
+
* @deprecated Use `TableFieldName<TMetadata[TTableName]>` instead.
|
|
603
638
|
*/
|
|
604
639
|
export type FieldName<
|
|
605
640
|
TMetadata extends TableMetadataMap,
|
|
606
641
|
TTableName extends keyof TMetadata,
|
|
607
|
-
> = TMetadata[TTableName]
|
|
608
|
-
? N extends string
|
|
609
|
-
? N
|
|
610
|
-
: never
|
|
611
|
-
: never;
|
|
642
|
+
> = TableFieldName<TMetadata[TTableName]>;
|
|
612
643
|
|
|
613
644
|
/**
|
|
614
645
|
* Field types that support ordering.
|
|
@@ -625,19 +656,16 @@ type OrderableFieldType =
|
|
|
625
656
|
| "enum";
|
|
626
657
|
|
|
627
658
|
/**
|
|
628
|
-
* Extract only orderable field names from table metadata.
|
|
659
|
+
* Extract only orderable field names from a single table metadata object.
|
|
629
660
|
*
|
|
630
661
|
* Fields whose `type` is not in `OrderableFieldType` (e.g. `uuid`, `array`,
|
|
631
662
|
* `nested`, `file`) are excluded. This allows `CheckOrderField` to compare
|
|
632
663
|
* only the fields that Tailor Platform actually exposes in the
|
|
633
664
|
* `OrderFieldEnum`, avoiding false positives for fields like `id`.
|
|
634
665
|
*/
|
|
635
|
-
export type
|
|
636
|
-
TMetadata extends TableMetadataMap,
|
|
637
|
-
TTableName extends keyof TMetadata,
|
|
638
|
-
> =
|
|
666
|
+
export type TableOrderableFieldName<TTable extends TableMetadata> =
|
|
639
667
|
Extract<
|
|
640
|
-
|
|
668
|
+
TTable["fields"][number],
|
|
641
669
|
{ readonly type: OrderableFieldType }
|
|
642
670
|
> extends { readonly name: infer N }
|
|
643
671
|
? N extends string
|
|
@@ -645,6 +673,16 @@ export type OrderableFieldName<
|
|
|
645
673
|
: never
|
|
646
674
|
: never;
|
|
647
675
|
|
|
676
|
+
/**
|
|
677
|
+
* Extract only orderable field names from table metadata map + table name.
|
|
678
|
+
*
|
|
679
|
+
* @deprecated Use `TableOrderableFieldName<TMetadata[TTableName]>` instead.
|
|
680
|
+
*/
|
|
681
|
+
export type OrderableFieldName<
|
|
682
|
+
TMetadata extends TableMetadataMap,
|
|
683
|
+
TTableName extends keyof TMetadata,
|
|
684
|
+
> = TableOrderableFieldName<TMetadata[TTableName]>;
|
|
685
|
+
|
|
648
686
|
/**
|
|
649
687
|
* Extract the `order[].field` union type from a GraphQL variables type.
|
|
650
688
|
*
|