@izumisy-tailor/tailor-data-viewer 0.2.33 → 0.3.0
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 +31 -18
- package/package.json +1 -1
- package/src/component/collection/collection-provider.tsx +16 -30
- package/src/component/collection/use-collection.test.ts +65 -76
- package/src/component/collection/use-collection.ts +67 -89
- package/src/component/collection/use-collection.typetest.ts +157 -293
- package/src/component/data-table/data-table.tsx +8 -6
- package/src/component/data-table/i18n.ts +12 -6
- package/src/component/data-table/pagination.tsx +3 -3
- package/src/component/data-table/search-filter-form.tsx +3 -3
- package/src/component/data-table/use-data-table.ts +6 -2
- package/src/component/index.ts +6 -9
- package/src/component/types.ts +145 -276
- package/src/tests/helpers.tsx +9 -5
package/src/component/types.ts
CHANGED
|
@@ -53,12 +53,23 @@ export type FilterConfig =
|
|
|
53
53
|
* are derived from it, eliminating duplication.
|
|
54
54
|
*/
|
|
55
55
|
export const OPERATORS_BY_FILTER_TYPE = {
|
|
56
|
-
string: [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
string: [
|
|
57
|
+
"eq",
|
|
58
|
+
"ne",
|
|
59
|
+
"contains",
|
|
60
|
+
"notContains",
|
|
61
|
+
"hasPrefix",
|
|
62
|
+
"hasSuffix",
|
|
63
|
+
"notHasPrefix",
|
|
64
|
+
"notHasSuffix",
|
|
65
|
+
"in",
|
|
66
|
+
"nin",
|
|
67
|
+
],
|
|
68
|
+
number: ["eq", "ne", "gt", "gte", "lt", "lte", "between", "in", "nin"],
|
|
69
|
+
date: ["eq", "ne", "gt", "gte", "lt", "lte", "between", "in", "nin"],
|
|
70
|
+
enum: ["eq", "ne", "in", "nin"],
|
|
60
71
|
boolean: ["eq", "ne"],
|
|
61
|
-
uuid: ["eq", "ne", "in", "
|
|
72
|
+
uuid: ["eq", "ne", "in", "nin"],
|
|
62
73
|
} as const satisfies Record<FilterConfig["type"], readonly string[]>;
|
|
63
74
|
|
|
64
75
|
/**
|
|
@@ -144,7 +155,7 @@ export interface Filter<TFieldName extends string = string> {
|
|
|
144
155
|
* type F = MetadataFilter<typeof tableMetadata, "task">;
|
|
145
156
|
* // | { field: "name"; operator: "eq" | "ne" | "contains" | ...; value: unknown }
|
|
146
157
|
* // | { field: "priority"; operator: "eq" | "ne" | "gt" | ...; value: unknown }
|
|
147
|
-
* // | { field: "status"; operator: "eq" | "ne" | "in" | "
|
|
158
|
+
* // | { field: "status"; operator: "eq" | "ne" | "in" | "nin"; value: unknown }
|
|
148
159
|
* ```
|
|
149
160
|
*/
|
|
150
161
|
/**
|
|
@@ -208,29 +219,13 @@ export interface PageInfo {
|
|
|
208
219
|
* GraphQL query variables in Tailor Platform format.
|
|
209
220
|
*
|
|
210
221
|
* Field-level type safety for `query` and `order` is not enforced here.
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* for orderable fields) when `useCollection` is called with metadata.
|
|
222
|
+
* When `useCollectionVariables` is called with metadata, `BuildQueryVariables`
|
|
223
|
+
* produces precise per-field filter types at compile time.
|
|
214
224
|
*/
|
|
215
225
|
export interface QueryVariables {
|
|
216
|
-
/**
|
|
217
|
-
* Filter object built at runtime by `useCollection`.
|
|
218
|
-
*
|
|
219
|
-
* Typed as `Record<string, unknown>` because the concrete shape depends on
|
|
220
|
-
* which filters the user applies at runtime (e.g. `{ name: { eq: "foo" } }`).
|
|
221
|
-
*
|
|
222
|
-
* Compile-time safety for field names is enforced separately by
|
|
223
|
-
* `ValidateCollectionQuery` (specifically `CheckQueryInput`), which verifies
|
|
224
|
-
* that metadata field names are a subset of the GraphQL `QueryInput` type's keys.
|
|
225
|
-
*/
|
|
226
|
+
/** Filter object built at runtime by `useCollectionVariables`. */
|
|
226
227
|
query?: Record<string, unknown>;
|
|
227
|
-
/**
|
|
228
|
-
* Sort order built at runtime by `useCollection`.
|
|
229
|
-
*
|
|
230
|
-
* `field` is typed as `string` here. Compile-time validation that
|
|
231
|
-
* field names are assignable to the GraphQL `OrderInput` enum is
|
|
232
|
-
* performed by `ValidateCollectionQuery` (specifically `CheckOrderField`).
|
|
233
|
-
*/
|
|
228
|
+
/** Sort order built at runtime by `useCollectionVariables`. */
|
|
234
229
|
order?: { field: string; direction: "Asc" | "Desc" }[];
|
|
235
230
|
/** Forward pagination: number of items to fetch */
|
|
236
231
|
first?: number | null;
|
|
@@ -242,6 +237,111 @@ export interface QueryVariables {
|
|
|
242
237
|
before?: string | null;
|
|
243
238
|
}
|
|
244
239
|
|
|
240
|
+
// =============================================================================
|
|
241
|
+
// Collection Variables (split into explicit sub-properties)
|
|
242
|
+
// =============================================================================
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Pagination variables for cursor-based pagination (Tailor Platform format).
|
|
246
|
+
*/
|
|
247
|
+
export interface PaginationVariables {
|
|
248
|
+
/** Forward pagination: number of items to fetch */
|
|
249
|
+
first?: number;
|
|
250
|
+
/** Forward pagination: cursor to start after */
|
|
251
|
+
after?: string | null;
|
|
252
|
+
/** Backward pagination: number of items to fetch from the end */
|
|
253
|
+
last?: number;
|
|
254
|
+
/** Backward pagination: cursor to fetch before */
|
|
255
|
+
before?: string | null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// Metadata-aware filter variable types
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Maps `FieldType` (from metadata) to the TypeScript value type
|
|
264
|
+
* used in filter variable construction.
|
|
265
|
+
*/
|
|
266
|
+
type FieldTypeToTSType = {
|
|
267
|
+
string: string;
|
|
268
|
+
number: number;
|
|
269
|
+
boolean: boolean;
|
|
270
|
+
uuid: string;
|
|
271
|
+
datetime: string;
|
|
272
|
+
date: string;
|
|
273
|
+
time: string;
|
|
274
|
+
enum: string;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Resolves the value type for a filter operator.
|
|
279
|
+
* `in`/`nin` operators accept arrays, `between` accepts `{ min, max }`,
|
|
280
|
+
* all other operators accept a scalar value.
|
|
281
|
+
*/
|
|
282
|
+
type OperatorValueType<TOp extends string, TValue> = TOp extends "in" | "nin"
|
|
283
|
+
? TValue[]
|
|
284
|
+
: TOp extends "between"
|
|
285
|
+
? { min: TValue; max: TValue }
|
|
286
|
+
: TValue;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Builds a filter input type for a specific filter config type and value type.
|
|
290
|
+
* Each operator key is optional, with the appropriate value type.
|
|
291
|
+
*/
|
|
292
|
+
type FilterInputForFieldType<
|
|
293
|
+
TFilterConfigType extends FilterConfig["type"],
|
|
294
|
+
TValue,
|
|
295
|
+
> = {
|
|
296
|
+
[Op in OperatorForFilterType[TFilterConfigType]]?: OperatorValueType<
|
|
297
|
+
Op,
|
|
298
|
+
TValue
|
|
299
|
+
>;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Builds a Tailor Platform QueryInput-compatible type from table metadata.
|
|
304
|
+
*
|
|
305
|
+
* Each filterable field becomes an optional key with its filter input type.
|
|
306
|
+
* Non-filterable fields (array, nested, file) are excluded.
|
|
307
|
+
*
|
|
308
|
+
* The resulting type is structurally assignable to the corresponding
|
|
309
|
+
* GraphQL QueryInput type generated by gql-tada.
|
|
310
|
+
*/
|
|
311
|
+
export type BuildQueryVariables<TTable extends TableMetadata> = {
|
|
312
|
+
[F in TTable["fields"][number] as F extends {
|
|
313
|
+
readonly name: infer N extends string;
|
|
314
|
+
readonly type: infer T;
|
|
315
|
+
}
|
|
316
|
+
? T extends keyof FieldTypeToFilterConfigType
|
|
317
|
+
? FieldTypeToFilterConfigType[T] extends never
|
|
318
|
+
? never
|
|
319
|
+
: N
|
|
320
|
+
: never
|
|
321
|
+
: never]?: F extends {
|
|
322
|
+
readonly type: infer T extends keyof FieldTypeToFilterConfigType &
|
|
323
|
+
keyof FieldTypeToTSType;
|
|
324
|
+
}
|
|
325
|
+
? FieldTypeToFilterConfigType[T] extends infer FCT extends
|
|
326
|
+
FilterConfig["type"]
|
|
327
|
+
? FilterInputForFieldType<FCT, FieldTypeToTSType[T]>
|
|
328
|
+
: never
|
|
329
|
+
: never;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Collection variables split into explicit sub-properties.
|
|
334
|
+
* Each sub-property maps to a specific part of the GraphQL query variables.
|
|
335
|
+
*/
|
|
336
|
+
export interface CollectionVariables {
|
|
337
|
+
/** Filter variables (Tailor Platform QueryInput format) */
|
|
338
|
+
query: Record<string, Record<string, unknown>> | undefined;
|
|
339
|
+
/** Sort order variables (Tailor Platform OrderInput format) */
|
|
340
|
+
order: { field: string; direction: "Asc" | "Desc" }[] | undefined;
|
|
341
|
+
/** Cursor-based pagination variables */
|
|
342
|
+
pagination: PaginationVariables;
|
|
343
|
+
}
|
|
344
|
+
|
|
245
345
|
// =============================================================================
|
|
246
346
|
// Collection Result (Tailor Platform standard)
|
|
247
347
|
// =============================================================================
|
|
@@ -325,11 +425,11 @@ export type ColumnDefinition<TRow extends Record<string, unknown>> =
|
|
|
325
425
|
Column<TRow>;
|
|
326
426
|
|
|
327
427
|
// =============================================================================
|
|
328
|
-
//
|
|
428
|
+
// useCollectionVariables Types
|
|
329
429
|
// =============================================================================
|
|
330
430
|
|
|
331
431
|
/**
|
|
332
|
-
* Options for `
|
|
432
|
+
* Options for `useCollectionVariables` hook.
|
|
333
433
|
*
|
|
334
434
|
* @typeParam TFieldName - Union of allowed field name strings (default: `string`).
|
|
335
435
|
*/
|
|
@@ -349,7 +449,7 @@ export interface UseCollectionOptions<
|
|
|
349
449
|
}
|
|
350
450
|
|
|
351
451
|
/**
|
|
352
|
-
* Return type of `
|
|
452
|
+
* Return type of `useCollectionVariables` hook.
|
|
353
453
|
*
|
|
354
454
|
* Methods that accept a field name are typed with `TFieldName` so that
|
|
355
455
|
* auto-completion works when a concrete union is supplied.
|
|
@@ -361,25 +461,27 @@ export interface UseCollectionOptions<
|
|
|
361
461
|
* can be safely destructured without triggering `unbound-method` lint rules.
|
|
362
462
|
*
|
|
363
463
|
* @typeParam TFieldName - Union of allowed field name strings (default: `string`).
|
|
364
|
-
* @typeParam
|
|
365
|
-
* `query` and `variables`.
|
|
464
|
+
* @typeParam TVariables - Type of `variables` property.
|
|
366
465
|
*/
|
|
367
466
|
export interface UseCollectionReturn<
|
|
368
467
|
TFieldName extends string = string,
|
|
369
|
-
|
|
468
|
+
TVariables = CollectionVariables,
|
|
370
469
|
TFilter = Filter<TFieldName>,
|
|
371
470
|
> {
|
|
372
471
|
/**
|
|
373
|
-
*
|
|
374
|
-
*
|
|
472
|
+
* Collection variables split into explicit sub-properties
|
|
473
|
+
* for direct mapping to GraphQL query variables.
|
|
375
474
|
*
|
|
376
475
|
* @example
|
|
377
476
|
* ```tsx
|
|
378
|
-
* const
|
|
379
|
-
* const [result] = useQuery({
|
|
477
|
+
* const { query, order, pagination } = collection.variables;
|
|
478
|
+
* const [result] = useQuery({
|
|
479
|
+
* query: GET_TASKS,
|
|
480
|
+
* variables: { ...pagination, query, order },
|
|
481
|
+
* });
|
|
380
482
|
* ```
|
|
381
483
|
*/
|
|
382
|
-
|
|
484
|
+
variables: TVariables;
|
|
383
485
|
|
|
384
486
|
// Filter operations
|
|
385
487
|
/** Current active filters */
|
|
@@ -647,242 +749,6 @@ export type OrderableFieldName<
|
|
|
647
749
|
TTableName extends keyof TMetadata,
|
|
648
750
|
> = TableOrderableFieldName<TMetadata[TTableName]>;
|
|
649
751
|
|
|
650
|
-
/**
|
|
651
|
-
* Extract the `order[].field` union type from a GraphQL variables type.
|
|
652
|
-
*
|
|
653
|
-
* For gql-tada's `VariablesOf<typeof QUERY>`, this extracts the allowed
|
|
654
|
-
* field names from the `order` parameter.
|
|
655
|
-
*
|
|
656
|
-
* @example
|
|
657
|
-
* ```ts
|
|
658
|
-
* type Fields = ExtractOrderField<VariablesOf<typeof GET_ORDERS>>;
|
|
659
|
-
* // → "name" | "amount" | "status" | "createdAt"
|
|
660
|
-
* ```
|
|
661
|
-
*/
|
|
662
|
-
export type ExtractOrderField<T> = T extends {
|
|
663
|
-
order?: readonly (infer O | null | undefined)[] | null | undefined;
|
|
664
|
-
}
|
|
665
|
-
? O extends { field?: infer F | null }
|
|
666
|
-
? NonNullable<F> & string
|
|
667
|
-
: string
|
|
668
|
-
: string;
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* Extract the variables type from a gql.tada `DocumentDecoration`.
|
|
672
|
-
*
|
|
673
|
-
* gql.tada stores variables via `__apiType?: (variables: V) => R`.
|
|
674
|
-
*
|
|
675
|
-
* @example
|
|
676
|
-
* ```ts
|
|
677
|
-
* const GET_ORDERS = graphql(`query Orders($first: Int, ...) { ... }`);
|
|
678
|
-
* type Vars = ExtractQueryVariables<typeof GET_ORDERS>;
|
|
679
|
-
* // → { first?: number | null; order?: OrderInput[] | null; ... }
|
|
680
|
-
* ```
|
|
681
|
-
*/
|
|
682
|
-
export type ExtractQueryVariables<T> = T extends {
|
|
683
|
-
__apiType?: (variables: infer V) => unknown;
|
|
684
|
-
}
|
|
685
|
-
? NonNullable<V>
|
|
686
|
-
: never;
|
|
687
|
-
|
|
688
|
-
// =============================================================================
|
|
689
|
-
// Collection Query Validation (compile-time safety)
|
|
690
|
-
// =============================================================================
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* Extract the key names of the `query` (filter) input type from GraphQL variables.
|
|
694
|
-
*
|
|
695
|
-
* For gql-tada's `VariablesOf<typeof QUERY>`, this extracts the allowed
|
|
696
|
-
* field names from the `query` (QueryInput) parameter.
|
|
697
|
-
*
|
|
698
|
-
* @example
|
|
699
|
-
* ```ts
|
|
700
|
-
* // query: BuyerContactQueryInput has keys: name, email, phone, ...
|
|
701
|
-
* type Keys = ExtractQueryInputKeys<typeof GET_BUYER_CONTACTS>;
|
|
702
|
-
* // → "name" | "email" | "phone" | ...
|
|
703
|
-
* ```
|
|
704
|
-
*/
|
|
705
|
-
export type ExtractQueryInputKeys<T> =
|
|
706
|
-
ExtractQueryVariables<T> extends {
|
|
707
|
-
query?: infer Q | null;
|
|
708
|
-
}
|
|
709
|
-
? keyof NonNullable<Q> & string
|
|
710
|
-
: string;
|
|
711
|
-
|
|
712
|
-
// ---------------------------------------------------------------------------
|
|
713
|
-
// Individual collection query validation rules
|
|
714
|
-
// ---------------------------------------------------------------------------
|
|
715
|
-
// Each rule resolves to `Pass` when the check passes (or is not applicable),
|
|
716
|
-
// or `{ __xxxError: "…" }` when it fails. The rules are independent, so
|
|
717
|
-
// adding a new one is just defining a new `Check*` type and appending it to
|
|
718
|
-
// the intersection inside `ValidateCollectionQuery`.
|
|
719
|
-
// ---------------------------------------------------------------------------
|
|
720
|
-
|
|
721
|
-
/**
|
|
722
|
-
* Identity type for intersection: `T & Pass` ≡ `T`.
|
|
723
|
-
* Used as the "pass" branch of each validation rule.
|
|
724
|
-
*/
|
|
725
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
726
|
-
type Pass = {};
|
|
727
|
-
|
|
728
|
-
/**
|
|
729
|
-
* Rule 1 — The query must declare `$first` as a variable.
|
|
730
|
-
*/
|
|
731
|
-
type CheckFirstVariable<TQuery> =
|
|
732
|
-
"first" extends keyof ExtractQueryVariables<TQuery>
|
|
733
|
-
? Pass
|
|
734
|
-
: {
|
|
735
|
-
__firstVariableError: `Query must declare a $first variable (e.g. $first: Int).`;
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* Rule 2 — The query must declare `$after` as a variable.
|
|
740
|
-
*/
|
|
741
|
-
type CheckAfterVariable<TQuery> =
|
|
742
|
-
"after" extends keyof ExtractQueryVariables<TQuery>
|
|
743
|
-
? Pass
|
|
744
|
-
: {
|
|
745
|
-
__afterVariableError: `Query must declare an $after variable (e.g. $after: String).`;
|
|
746
|
-
};
|
|
747
|
-
|
|
748
|
-
/**
|
|
749
|
-
* Rule 3 — The query must declare `$last` as a variable.
|
|
750
|
-
*/
|
|
751
|
-
type CheckLastVariable<TQuery> =
|
|
752
|
-
"last" extends keyof ExtractQueryVariables<TQuery>
|
|
753
|
-
? Pass
|
|
754
|
-
: {
|
|
755
|
-
__lastVariableError: `Query must declare a $last variable (e.g. $last: Int).`;
|
|
756
|
-
};
|
|
757
|
-
|
|
758
|
-
/**
|
|
759
|
-
* Rule 4 — The query must declare `$before` as a variable.
|
|
760
|
-
*/
|
|
761
|
-
type CheckBeforeVariable<TQuery> =
|
|
762
|
-
"before" extends keyof ExtractQueryVariables<TQuery>
|
|
763
|
-
? Pass
|
|
764
|
-
: {
|
|
765
|
-
__beforeVariableError: `Query must declare a $before variable (e.g. $before: String).`;
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* Rule 5 — The query must declare `$query` as a variable.
|
|
770
|
-
*/
|
|
771
|
-
type CheckQueryVariable<TQuery> =
|
|
772
|
-
"query" extends keyof ExtractQueryVariables<TQuery>
|
|
773
|
-
? Pass
|
|
774
|
-
: {
|
|
775
|
-
__queryVariableError: `Query must declare a $query variable (e.g. $query: XxxQueryInput!).`;
|
|
776
|
-
};
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
* Rule 6 — The query must declare `$order` as a variable.
|
|
780
|
-
*/
|
|
781
|
-
type CheckOrderVariable<TQuery> =
|
|
782
|
-
"order" extends keyof ExtractQueryVariables<TQuery>
|
|
783
|
-
? Pass
|
|
784
|
-
: {
|
|
785
|
-
__orderVariableError: `Query must declare an $order variable (e.g. $order: [XxxOrderInput]).`;
|
|
786
|
-
};
|
|
787
|
-
|
|
788
|
-
/**
|
|
789
|
-
* Rule 7 — When metadata is provided, metadata field names must be
|
|
790
|
-
* assignable to the `field` enum inside the `OrderInput` type.
|
|
791
|
-
*/
|
|
792
|
-
type CheckOrderField<
|
|
793
|
-
TQuery,
|
|
794
|
-
TFieldName extends string,
|
|
795
|
-
> = "order" extends keyof ExtractQueryVariables<TQuery>
|
|
796
|
-
? [TFieldName] extends [ExtractOrderField<ExtractQueryVariables<TQuery>>]
|
|
797
|
-
? Pass
|
|
798
|
-
: {
|
|
799
|
-
__orderFieldError: `Some metadata field names are not assignable to OrderInput field enum. Check that the order variable's field type includes all metadata fields.`;
|
|
800
|
-
}
|
|
801
|
-
: Pass;
|
|
802
|
-
|
|
803
|
-
/**
|
|
804
|
-
* Rule 8 — When metadata is provided, metadata field names must be a
|
|
805
|
-
* subset of the `QueryInput` type's keys.
|
|
806
|
-
*/
|
|
807
|
-
type CheckQueryInput<
|
|
808
|
-
TQuery,
|
|
809
|
-
TFieldName extends string,
|
|
810
|
-
> = "query" extends keyof ExtractQueryVariables<TQuery>
|
|
811
|
-
? [Exclude<TFieldName, ExtractQueryInputKeys<TQuery>>] extends [never]
|
|
812
|
-
? Pass
|
|
813
|
-
: {
|
|
814
|
-
__queryInputError: `Some metadata field names are not present in QueryInput keys. Missing: ${Exclude<TFieldName, ExtractQueryInputKeys<TQuery>> & string}`;
|
|
815
|
-
}
|
|
816
|
-
: Pass;
|
|
817
|
-
|
|
818
|
-
/**
|
|
819
|
-
* Validate that a query document is compatible with `useCollection`.
|
|
820
|
-
*
|
|
821
|
-
* When gql-tada type information is available (i.e. `ExtractQueryVariables`
|
|
822
|
-
* does not resolve to `never`), this type performs compile-time checks by
|
|
823
|
-
* intersecting independent rule types:
|
|
824
|
-
*
|
|
825
|
-
* 1. **`CheckFirstVariable`** — `$first` must exist.
|
|
826
|
-
* 2. **`CheckAfterVariable`** — `$after` must exist.
|
|
827
|
-
* 3. **`CheckLastVariable`** — `$last` must exist.
|
|
828
|
-
* 4. **`CheckBeforeVariable`** — `$before` must exist.
|
|
829
|
-
* 5. **`CheckQueryVariable`** — `$query` must exist.
|
|
830
|
-
* 6. **`CheckOrderVariable`** — `$order` must exist.
|
|
831
|
-
* 7. **`CheckOrderField`** — OrderInput field compatibility (metadata-aware).
|
|
832
|
-
* 8. **`CheckQueryInput`** — QueryInput key compatibility (metadata-aware).
|
|
833
|
-
*
|
|
834
|
-
* Each rule resolves to `{}` on pass or `{ __xxxError: "…" }` on fail.
|
|
835
|
-
* A failing rule adds a phantom error property that makes `TQuery`
|
|
836
|
-
* incompatible with the actual value, producing a compile error.
|
|
837
|
-
*
|
|
838
|
-
* When gql-tada is not used (plain `DocumentNode`), all checks are skipped.
|
|
839
|
-
*
|
|
840
|
-
* @typeParam TQuery - The query document type (e.g. `typeof GET_ORDERS`).
|
|
841
|
-
* @typeParam TFieldName - Union of metadata field names (default: `string`,
|
|
842
|
-
* which disables metadata-aware checks).
|
|
843
|
-
*/
|
|
844
|
-
export type ValidateCollectionQuery<
|
|
845
|
-
TQuery,
|
|
846
|
-
TFieldName extends string = string,
|
|
847
|
-
TOrderableFieldName extends string = TFieldName,
|
|
848
|
-
> =
|
|
849
|
-
ExtractQueryVariables<TQuery> extends never
|
|
850
|
-
? TQuery // No gql-tada type info → skip validation
|
|
851
|
-
: string extends TFieldName
|
|
852
|
-
? TQuery &
|
|
853
|
-
CheckFirstVariable<TQuery> &
|
|
854
|
-
CheckAfterVariable<TQuery> &
|
|
855
|
-
CheckLastVariable<TQuery> &
|
|
856
|
-
CheckBeforeVariable<TQuery> &
|
|
857
|
-
CheckQueryVariable<TQuery> &
|
|
858
|
-
CheckOrderVariable<TQuery>
|
|
859
|
-
: TQuery &
|
|
860
|
-
CheckFirstVariable<TQuery> &
|
|
861
|
-
CheckAfterVariable<TQuery> &
|
|
862
|
-
CheckLastVariable<TQuery> &
|
|
863
|
-
CheckBeforeVariable<TQuery> &
|
|
864
|
-
CheckQueryVariable<TQuery> &
|
|
865
|
-
CheckOrderVariable<TQuery> &
|
|
866
|
-
CheckOrderField<TQuery, TOrderableFieldName> &
|
|
867
|
-
CheckQueryInput<TQuery, TFieldName>;
|
|
868
|
-
|
|
869
|
-
/**
|
|
870
|
-
* Helper to check whether a `ValidateCollectionQuery` result contains any
|
|
871
|
-
* validation error. Use this in type-level assertions instead of checking
|
|
872
|
-
* individual error keys.
|
|
873
|
-
*/
|
|
874
|
-
export type HasCollectionQueryError<T> = T extends
|
|
875
|
-
| { __firstVariableError: string }
|
|
876
|
-
| { __afterVariableError: string }
|
|
877
|
-
| { __lastVariableError: string }
|
|
878
|
-
| { __beforeVariableError: string }
|
|
879
|
-
| { __queryVariableError: string }
|
|
880
|
-
| { __orderVariableError: string }
|
|
881
|
-
| { __orderFieldError: string }
|
|
882
|
-
| { __queryInputError: string }
|
|
883
|
-
? true
|
|
884
|
-
: false;
|
|
885
|
-
|
|
886
752
|
/**
|
|
887
753
|
* Find table names in metadata whose fields are a superset of `TFieldName`.
|
|
888
754
|
*
|
|
@@ -977,15 +843,18 @@ export const DEFAULT_OPERATOR_LABELS: Record<FilterOperator, string> = {
|
|
|
977
843
|
eq: "=",
|
|
978
844
|
ne: "≠",
|
|
979
845
|
contains: "contains",
|
|
980
|
-
|
|
981
|
-
|
|
846
|
+
notContains: "not contains",
|
|
847
|
+
hasPrefix: "starts with",
|
|
848
|
+
hasSuffix: "ends with",
|
|
849
|
+
notHasPrefix: "not starts with",
|
|
850
|
+
notHasSuffix: "not ends with",
|
|
982
851
|
gt: ">",
|
|
983
852
|
gte: "≥",
|
|
984
853
|
lt: "<",
|
|
985
854
|
lte: "≤",
|
|
986
855
|
between: "between",
|
|
987
856
|
in: "in",
|
|
988
|
-
|
|
857
|
+
nin: "not in",
|
|
989
858
|
};
|
|
990
859
|
|
|
991
860
|
/**
|
package/src/tests/helpers.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import { vi } from "vitest";
|
|
|
3
3
|
import type { Column, UseCollectionReturn } from "../component/types";
|
|
4
4
|
import { DataTableContext } from "../component/data-table/data-table-context";
|
|
5
5
|
import type { DataTableContextValue } from "../component/data-table/data-table-context";
|
|
6
|
-
import {
|
|
6
|
+
import { CollectionVariablesProvider } from "../component/collection/collection-provider";
|
|
7
7
|
|
|
8
8
|
// =============================================================================
|
|
9
9
|
// Mock factory: DataTableContext
|
|
@@ -43,14 +43,18 @@ export function createMockDataTableContext<T extends Record<string, unknown>>(
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// =============================================================================
|
|
46
|
-
// Mock factory:
|
|
46
|
+
// Mock factory: CollectionVariablesContext
|
|
47
47
|
// =============================================================================
|
|
48
48
|
|
|
49
49
|
export function createMockCollectionContext(
|
|
50
50
|
overrides?: Partial<UseCollectionReturn<string, unknown>>,
|
|
51
51
|
): UseCollectionReturn<string, unknown> {
|
|
52
52
|
return {
|
|
53
|
-
|
|
53
|
+
variables: {
|
|
54
|
+
query: undefined,
|
|
55
|
+
order: undefined,
|
|
56
|
+
pagination: { first: 20 },
|
|
57
|
+
},
|
|
54
58
|
filters: [],
|
|
55
59
|
addFilter: vi.fn(),
|
|
56
60
|
setFilters: vi.fn(),
|
|
@@ -118,7 +122,7 @@ export function createTestProviders<
|
|
|
118
122
|
collection?: Partial<UseCollectionReturn<string, unknown>>;
|
|
119
123
|
}) {
|
|
120
124
|
return (
|
|
121
|
-
<
|
|
125
|
+
<CollectionVariablesProvider
|
|
122
126
|
value={createMockCollectionContext({
|
|
123
127
|
...defaults.collectionDefaults,
|
|
124
128
|
...collection,
|
|
@@ -132,7 +136,7 @@ export function createTestProviders<
|
|
|
132
136
|
>
|
|
133
137
|
{children}
|
|
134
138
|
</DataTableContext.Provider>
|
|
135
|
-
</
|
|
139
|
+
</CollectionVariablesProvider>
|
|
136
140
|
);
|
|
137
141
|
};
|
|
138
142
|
}
|