@constructive-io/graphql-codegen 2.21.0 → 2.22.1

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.
Files changed (93) hide show
  1. package/cli/codegen/barrel.d.ts +4 -1
  2. package/cli/codegen/barrel.js +18 -12
  3. package/cli/codegen/client.js +33 -0
  4. package/cli/codegen/custom-mutations.d.ts +4 -0
  5. package/cli/codegen/custom-mutations.js +39 -13
  6. package/cli/codegen/custom-queries.d.ts +4 -0
  7. package/cli/codegen/custom-queries.js +36 -11
  8. package/cli/codegen/gql-ast.js +9 -5
  9. package/cli/codegen/index.js +35 -7
  10. package/cli/codegen/mutations.d.ts +2 -0
  11. package/cli/codegen/mutations.js +87 -23
  12. package/cli/codegen/orm/barrel.js +4 -2
  13. package/cli/codegen/orm/index.js +17 -0
  14. package/cli/codegen/orm/input-types-generator.js +83 -29
  15. package/cli/codegen/orm/model-generator.js +6 -4
  16. package/cli/codegen/queries.js +36 -27
  17. package/cli/codegen/scalars.d.ts +6 -4
  18. package/cli/codegen/scalars.js +17 -9
  19. package/cli/codegen/schema-types-generator.d.ts +26 -0
  20. package/cli/codegen/schema-types-generator.js +365 -0
  21. package/cli/codegen/ts-ast.d.ts +3 -1
  22. package/cli/codegen/ts-ast.js +2 -2
  23. package/cli/codegen/type-resolver.d.ts +52 -6
  24. package/cli/codegen/type-resolver.js +97 -19
  25. package/cli/codegen/types.d.ts +7 -4
  26. package/cli/codegen/types.js +94 -41
  27. package/cli/codegen/utils.d.ts +20 -2
  28. package/cli/codegen/utils.js +32 -7
  29. package/cli/commands/generate-orm.js +5 -5
  30. package/cli/commands/generate.d.ts +4 -1
  31. package/cli/commands/generate.js +27 -8
  32. package/cli/introspect/transform-schema.d.ts +33 -21
  33. package/cli/introspect/transform-schema.js +31 -21
  34. package/esm/cli/codegen/barrel.d.ts +4 -1
  35. package/esm/cli/codegen/barrel.js +18 -12
  36. package/esm/cli/codegen/client.js +33 -0
  37. package/esm/cli/codegen/custom-mutations.d.ts +4 -0
  38. package/esm/cli/codegen/custom-mutations.js +40 -14
  39. package/esm/cli/codegen/custom-queries.d.ts +4 -0
  40. package/esm/cli/codegen/custom-queries.js +37 -12
  41. package/esm/cli/codegen/gql-ast.js +10 -6
  42. package/esm/cli/codegen/index.js +35 -7
  43. package/esm/cli/codegen/mutations.d.ts +2 -0
  44. package/esm/cli/codegen/mutations.js +88 -24
  45. package/esm/cli/codegen/orm/barrel.js +4 -2
  46. package/esm/cli/codegen/orm/index.js +17 -0
  47. package/esm/cli/codegen/orm/input-types-generator.js +83 -29
  48. package/esm/cli/codegen/orm/model-generator.js +7 -5
  49. package/esm/cli/codegen/queries.js +37 -28
  50. package/esm/cli/codegen/scalars.d.ts +6 -4
  51. package/esm/cli/codegen/scalars.js +16 -8
  52. package/esm/cli/codegen/schema-types-generator.d.ts +26 -0
  53. package/esm/cli/codegen/schema-types-generator.js +362 -0
  54. package/esm/cli/codegen/ts-ast.d.ts +3 -1
  55. package/esm/cli/codegen/ts-ast.js +2 -2
  56. package/esm/cli/codegen/type-resolver.d.ts +52 -6
  57. package/esm/cli/codegen/type-resolver.js +97 -20
  58. package/esm/cli/codegen/types.d.ts +7 -4
  59. package/esm/cli/codegen/types.js +95 -41
  60. package/esm/cli/codegen/utils.d.ts +20 -2
  61. package/esm/cli/codegen/utils.js +31 -7
  62. package/esm/cli/commands/generate-orm.js +5 -5
  63. package/esm/cli/commands/generate.d.ts +4 -1
  64. package/esm/cli/commands/generate.js +27 -8
  65. package/esm/cli/introspect/transform-schema.d.ts +33 -21
  66. package/esm/cli/introspect/transform-schema.js +31 -21
  67. package/esm/types/schema.d.ts +2 -0
  68. package/package.json +8 -7
  69. package/types/schema.d.ts +2 -0
  70. package/__tests__/codegen/input-types-generator.test.d.ts +0 -1
  71. package/__tests__/codegen/input-types-generator.test.js +0 -635
  72. package/__tests__/codegen/react-query-optional.test.d.ts +0 -1
  73. package/__tests__/codegen/react-query-optional.test.js +0 -292
  74. package/cli/codegen/filters.d.ts +0 -27
  75. package/cli/codegen/filters.js +0 -357
  76. package/cli/codegen/orm/input-types-generator.test.d.ts +0 -1
  77. package/cli/codegen/orm/input-types-generator.test.js +0 -75
  78. package/cli/codegen/orm/select-types.test.d.ts +0 -11
  79. package/cli/codegen/orm/select-types.test.js +0 -22
  80. package/cli/introspect/transform-schema.test.d.ts +0 -1
  81. package/cli/introspect/transform-schema.test.js +0 -67
  82. package/esm/__tests__/codegen/input-types-generator.test.d.ts +0 -1
  83. package/esm/__tests__/codegen/input-types-generator.test.js +0 -633
  84. package/esm/__tests__/codegen/react-query-optional.test.d.ts +0 -1
  85. package/esm/__tests__/codegen/react-query-optional.test.js +0 -290
  86. package/esm/cli/codegen/filters.d.ts +0 -27
  87. package/esm/cli/codegen/filters.js +0 -351
  88. package/esm/cli/codegen/orm/input-types-generator.test.d.ts +0 -1
  89. package/esm/cli/codegen/orm/input-types-generator.test.js +0 -73
  90. package/esm/cli/codegen/orm/select-types.test.d.ts +0 -11
  91. package/esm/cli/codegen/orm/select-types.test.js +0 -21
  92. package/esm/cli/introspect/transform-schema.test.d.ts +0 -1
  93. package/esm/cli/introspect/transform-schema.test.js +0 -65
@@ -6,6 +6,34 @@
6
6
  */
7
7
  import type { CleanTypeRef, CleanArgument, CleanObjectField } from '../../types/schema';
8
8
  import type { InterfaceProperty } from './ts-ast';
9
+ /**
10
+ * Interface for tracking referenced types during code generation
11
+ */
12
+ export interface TypeTracker {
13
+ /** Set of type names that have been referenced */
14
+ referencedTypes: Set<string>;
15
+ /** Track a type reference */
16
+ track(typeName: string): void;
17
+ /** Get importable types from schema-types.ts (Input/Payload/Enum types) */
18
+ getImportableTypes(): string[];
19
+ /** Get importable types from types.ts (table entity types) */
20
+ getTableTypes(): string[];
21
+ /** Reset the tracker */
22
+ reset(): void;
23
+ }
24
+ /**
25
+ * Options for creating a TypeTracker
26
+ */
27
+ export interface TypeTrackerOptions {
28
+ /** Table entity type names that should be imported from types.ts */
29
+ tableTypeNames?: Set<string>;
30
+ }
31
+ /**
32
+ * Create a new TypeTracker instance
33
+ *
34
+ * @param options - Optional configuration for the tracker
35
+ */
36
+ export declare function createTypeTracker(options?: TypeTrackerOptions): TypeTracker;
9
37
  /**
10
38
  * Convert a GraphQL scalar type to TypeScript type
11
39
  */
@@ -13,13 +41,19 @@ export declare function scalarToTsType(scalarName: string): string;
13
41
  /**
14
42
  * Convert a CleanTypeRef to a TypeScript type string
15
43
  * Handles nested LIST and NON_NULL wrappers
44
+ *
45
+ * @param typeRef - The GraphQL type reference
46
+ * @param tracker - Optional TypeTracker to collect referenced types
16
47
  */
17
- export declare function typeRefToTsType(typeRef: CleanTypeRef): string;
48
+ export declare function typeRefToTsType(typeRef: CleanTypeRef, tracker?: TypeTracker): string;
18
49
  /**
19
50
  * Convert a CleanTypeRef to a nullable TypeScript type string
20
51
  * (for optional fields that can be null)
52
+ *
53
+ * @param typeRef - The GraphQL type reference
54
+ * @param tracker - Optional TypeTracker to collect referenced types
21
55
  */
22
- export declare function typeRefToNullableTsType(typeRef: CleanTypeRef): string;
56
+ export declare function typeRefToNullableTsType(typeRef: CleanTypeRef, tracker?: TypeTracker): string;
23
57
  /**
24
58
  * Check if a type reference is required (wrapped in NON_NULL)
25
59
  */
@@ -38,20 +72,32 @@ export declare function getTypeBaseName(typeRef: CleanTypeRef): string | null;
38
72
  export declare function getBaseTypeKind(typeRef: CleanTypeRef): CleanTypeRef['kind'];
39
73
  /**
40
74
  * Convert CleanArgument to InterfaceProperty for ts-morph
75
+ *
76
+ * @param arg - The GraphQL argument
77
+ * @param tracker - Optional TypeTracker to collect referenced types
41
78
  */
42
- export declare function argumentToInterfaceProperty(arg: CleanArgument): InterfaceProperty;
79
+ export declare function argumentToInterfaceProperty(arg: CleanArgument, tracker?: TypeTracker): InterfaceProperty;
43
80
  /**
44
81
  * Convert CleanObjectField to InterfaceProperty for ts-morph
82
+ *
83
+ * @param field - The GraphQL object field
84
+ * @param tracker - Optional TypeTracker to collect referenced types
45
85
  */
46
- export declare function fieldToInterfaceProperty(field: CleanObjectField): InterfaceProperty;
86
+ export declare function fieldToInterfaceProperty(field: CleanObjectField, tracker?: TypeTracker): InterfaceProperty;
47
87
  /**
48
88
  * Convert an array of CleanArguments to InterfaceProperty array
89
+ *
90
+ * @param args - The GraphQL arguments
91
+ * @param tracker - Optional TypeTracker to collect referenced types
49
92
  */
50
- export declare function argumentsToInterfaceProperties(args: CleanArgument[]): InterfaceProperty[];
93
+ export declare function argumentsToInterfaceProperties(args: CleanArgument[], tracker?: TypeTracker): InterfaceProperty[];
51
94
  /**
52
95
  * Convert an array of CleanObjectFields to InterfaceProperty array
96
+ *
97
+ * @param fields - The GraphQL object fields
98
+ * @param tracker - Optional TypeTracker to collect referenced types
53
99
  */
54
- export declare function fieldsToInterfaceProperties(fields: CleanObjectField[]): InterfaceProperty[];
100
+ export declare function fieldsToInterfaceProperties(fields: CleanObjectField[], tracker?: TypeTracker): InterfaceProperty[];
55
101
  /**
56
102
  * Check if a field should be skipped in selections
57
103
  */
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTypeTracker = createTypeTracker;
3
4
  exports.scalarToTsType = scalarToTsType;
4
5
  exports.typeRefToTsType = typeRefToTsType;
5
6
  exports.typeRefToNullableTsType = typeRefToNullableTsType;
@@ -22,6 +23,59 @@ exports.getQueryKeyName = getQueryKeyName;
22
23
  exports.getDocumentConstName = getDocumentConstName;
23
24
  const scalars_1 = require("./scalars");
24
25
  // ============================================================================
26
+ // Type Tracker for Collecting Referenced Types
27
+ // ============================================================================
28
+ /**
29
+ * Types that should not be tracked (scalars, built-ins, internal types)
30
+ */
31
+ const SKIP_TYPE_TRACKING = new Set([
32
+ ...scalars_1.SCALAR_NAMES,
33
+ // GraphQL built-ins
34
+ 'Query',
35
+ 'Mutation',
36
+ 'Subscription',
37
+ '__Schema',
38
+ '__Type',
39
+ '__Field',
40
+ '__InputValue',
41
+ '__EnumValue',
42
+ '__Directive',
43
+ // Connection types (handled separately)
44
+ 'PageInfo',
45
+ ]);
46
+ /**
47
+ * Create a new TypeTracker instance
48
+ *
49
+ * @param options - Optional configuration for the tracker
50
+ */
51
+ function createTypeTracker(options) {
52
+ const referencedTypes = new Set();
53
+ const tableTypeNames = options?.tableTypeNames ?? new Set();
54
+ return {
55
+ referencedTypes,
56
+ track(typeName) {
57
+ if (typeName && !SKIP_TYPE_TRACKING.has(typeName)) {
58
+ referencedTypes.add(typeName);
59
+ }
60
+ },
61
+ getImportableTypes() {
62
+ // Return schema types (not table entity types)
63
+ return Array.from(referencedTypes)
64
+ .filter((name) => !tableTypeNames.has(name))
65
+ .sort();
66
+ },
67
+ getTableTypes() {
68
+ // Return table entity types only
69
+ return Array.from(referencedTypes)
70
+ .filter((name) => tableTypeNames.has(name))
71
+ .sort();
72
+ },
73
+ reset() {
74
+ referencedTypes.clear();
75
+ },
76
+ };
77
+ }
78
+ // ============================================================================
25
79
  // GraphQL to TypeScript Type Mapping
26
80
  // ============================================================================
27
81
  /**
@@ -36,32 +90,41 @@ function scalarToTsType(scalarName) {
36
90
  /**
37
91
  * Convert a CleanTypeRef to a TypeScript type string
38
92
  * Handles nested LIST and NON_NULL wrappers
93
+ *
94
+ * @param typeRef - The GraphQL type reference
95
+ * @param tracker - Optional TypeTracker to collect referenced types
39
96
  */
40
- function typeRefToTsType(typeRef) {
97
+ function typeRefToTsType(typeRef, tracker) {
41
98
  switch (typeRef.kind) {
42
99
  case 'NON_NULL':
43
100
  // Non-null wrapper - unwrap and return the inner type
44
101
  if (typeRef.ofType) {
45
- return typeRefToTsType(typeRef.ofType);
102
+ return typeRefToTsType(typeRef.ofType, tracker);
46
103
  }
47
104
  return 'unknown';
48
105
  case 'LIST':
49
106
  // List wrapper - wrap inner type in array
50
107
  if (typeRef.ofType) {
51
- const innerType = typeRefToTsType(typeRef.ofType);
108
+ const innerType = typeRefToTsType(typeRef.ofType, tracker);
52
109
  return `${innerType}[]`;
53
110
  }
54
111
  return 'unknown[]';
55
112
  case 'SCALAR':
56
113
  // Scalar type - map to TS type
57
114
  return scalarToTsType(typeRef.name ?? 'unknown');
58
- case 'ENUM':
59
- // Enum type - use the GraphQL enum name
60
- return typeRef.name ?? 'string';
115
+ case 'ENUM': {
116
+ // Enum type - use the GraphQL enum name and track it
117
+ const typeName = typeRef.name ?? 'string';
118
+ tracker?.track(typeName);
119
+ return typeName;
120
+ }
61
121
  case 'OBJECT':
62
- case 'INPUT_OBJECT':
63
- // Object types - use the GraphQL type name
64
- return typeRef.name ?? 'unknown';
122
+ case 'INPUT_OBJECT': {
123
+ // Object types - use the GraphQL type name and track it
124
+ const typeName = typeRef.name ?? 'unknown';
125
+ tracker?.track(typeName);
126
+ return typeName;
127
+ }
65
128
  default:
66
129
  return 'unknown';
67
130
  }
@@ -69,9 +132,12 @@ function typeRefToTsType(typeRef) {
69
132
  /**
70
133
  * Convert a CleanTypeRef to a nullable TypeScript type string
71
134
  * (for optional fields that can be null)
135
+ *
136
+ * @param typeRef - The GraphQL type reference
137
+ * @param tracker - Optional TypeTracker to collect referenced types
72
138
  */
73
- function typeRefToNullableTsType(typeRef) {
74
- const baseType = typeRefToTsType(typeRef);
139
+ function typeRefToNullableTsType(typeRef, tracker) {
140
+ const baseType = typeRefToTsType(typeRef, tracker);
75
141
  // If the outer type is NON_NULL, it's required
76
142
  if (typeRef.kind === 'NON_NULL') {
77
143
  return baseType;
@@ -122,37 +188,49 @@ function getBaseTypeKind(typeRef) {
122
188
  // ============================================================================
123
189
  /**
124
190
  * Convert CleanArgument to InterfaceProperty for ts-morph
191
+ *
192
+ * @param arg - The GraphQL argument
193
+ * @param tracker - Optional TypeTracker to collect referenced types
125
194
  */
126
- function argumentToInterfaceProperty(arg) {
195
+ function argumentToInterfaceProperty(arg, tracker) {
127
196
  return {
128
197
  name: arg.name,
129
- type: typeRefToTsType(arg.type),
198
+ type: typeRefToTsType(arg.type, tracker),
130
199
  optional: !isTypeRequired(arg.type),
131
200
  docs: arg.description ? [arg.description] : undefined,
132
201
  };
133
202
  }
134
203
  /**
135
204
  * Convert CleanObjectField to InterfaceProperty for ts-morph
205
+ *
206
+ * @param field - The GraphQL object field
207
+ * @param tracker - Optional TypeTracker to collect referenced types
136
208
  */
137
- function fieldToInterfaceProperty(field) {
209
+ function fieldToInterfaceProperty(field, tracker) {
138
210
  return {
139
211
  name: field.name,
140
- type: typeRefToNullableTsType(field.type),
212
+ type: typeRefToNullableTsType(field.type, tracker),
141
213
  optional: false, // Fields are always present, just potentially null
142
214
  docs: field.description ? [field.description] : undefined,
143
215
  };
144
216
  }
145
217
  /**
146
218
  * Convert an array of CleanArguments to InterfaceProperty array
219
+ *
220
+ * @param args - The GraphQL arguments
221
+ * @param tracker - Optional TypeTracker to collect referenced types
147
222
  */
148
- function argumentsToInterfaceProperties(args) {
149
- return args.map(argumentToInterfaceProperty);
223
+ function argumentsToInterfaceProperties(args, tracker) {
224
+ return args.map((arg) => argumentToInterfaceProperty(arg, tracker));
150
225
  }
151
226
  /**
152
227
  * Convert an array of CleanObjectFields to InterfaceProperty array
228
+ *
229
+ * @param fields - The GraphQL object fields
230
+ * @param tracker - Optional TypeTracker to collect referenced types
153
231
  */
154
- function fieldsToInterfaceProperties(fields) {
155
- return fields.map(fieldToInterfaceProperty);
232
+ function fieldsToInterfaceProperties(fields, tracker) {
233
+ return fields.map((field) => fieldToInterfaceProperty(field, tracker));
156
234
  }
157
235
  // ============================================================================
158
236
  // Type Filtering
@@ -3,10 +3,13 @@
3
3
  */
4
4
  import type { CleanTable } from '../../types/schema';
5
5
  /**
6
- * Generate types.ts content with all entity interfaces and base filter types
6
+ * Options for generating types.ts
7
7
  */
8
- export declare function generateTypesFile(tables: CleanTable[]): string;
8
+ export interface GenerateTypesOptions {
9
+ /** Enum type names that are available from schema-types.ts */
10
+ enumsFromSchemaTypes?: string[];
11
+ }
9
12
  /**
10
- * Generate a minimal entity type (just id and display fields)
13
+ * Generate types.ts content with all entity interfaces and base filter types
11
14
  */
12
- export declare function generateMinimalEntityType(table: CleanTable): string;
15
+ export declare function generateTypesFile(tables: CleanTable[], options?: GenerateTypesOptions): string;
@@ -1,19 +1,103 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateTypesFile = generateTypesFile;
4
- exports.generateMinimalEntityType = generateMinimalEntityType;
5
4
  const ts_ast_1 = require("./ts-ast");
6
5
  const utils_1 = require("./utils");
7
- const filters_1 = require("./filters");
6
+ /** All filter type configurations - scalar and list filters */
7
+ const FILTER_CONFIGS = [
8
+ // Scalar filters
9
+ { name: 'StringFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'] },
10
+ { name: 'IntFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
11
+ { name: 'FloatFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
12
+ { name: 'BooleanFilter', tsType: 'boolean', operators: ['equality'] },
13
+ { name: 'UUIDFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray'] },
14
+ { name: 'DatetimeFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
15
+ { name: 'DateFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
16
+ { name: 'JSONFilter', tsType: 'Record<string, unknown>', operators: ['equality', 'distinct', 'json'] },
17
+ { name: 'BigIntFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
18
+ { name: 'BigFloatFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
19
+ { name: 'BitStringFilter', tsType: 'string', operators: ['equality'] },
20
+ { name: 'InternetAddressFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'] },
21
+ { name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] },
22
+ // List filters
23
+ { name: 'StringListFilter', tsType: 'string[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] },
24
+ { name: 'IntListFilter', tsType: 'number[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] },
25
+ { name: 'UUIDListFilter', tsType: 'string[]', operators: ['equality', 'distinct', 'comparison', 'listArray'] },
26
+ ];
27
+ /** Build filter properties based on operator sets */
28
+ function buildFilterProperties(tsType, operators) {
29
+ const props = [];
30
+ // Equality operators (isNull, equalTo, notEqualTo)
31
+ if (operators.includes('equality')) {
32
+ props.push({ name: 'isNull', type: 'boolean', optional: true }, { name: 'equalTo', type: tsType, optional: true }, { name: 'notEqualTo', type: tsType, optional: true });
33
+ }
34
+ // Distinct operators
35
+ if (operators.includes('distinct')) {
36
+ props.push({ name: 'distinctFrom', type: tsType, optional: true }, { name: 'notDistinctFrom', type: tsType, optional: true });
37
+ }
38
+ // In array operators
39
+ if (operators.includes('inArray')) {
40
+ props.push({ name: 'in', type: `${tsType}[]`, optional: true }, { name: 'notIn', type: `${tsType}[]`, optional: true });
41
+ }
42
+ // Comparison operators (lt, lte, gt, gte)
43
+ if (operators.includes('comparison')) {
44
+ props.push({ name: 'lessThan', type: tsType, optional: true }, { name: 'lessThanOrEqualTo', type: tsType, optional: true }, { name: 'greaterThan', type: tsType, optional: true }, { name: 'greaterThanOrEqualTo', type: tsType, optional: true });
45
+ }
46
+ // String-specific operators
47
+ if (operators.includes('string')) {
48
+ props.push({ name: 'includes', type: 'string', optional: true }, { name: 'notIncludes', type: 'string', optional: true }, { name: 'includesInsensitive', type: 'string', optional: true }, { name: 'notIncludesInsensitive', type: 'string', optional: true }, { name: 'startsWith', type: 'string', optional: true }, { name: 'notStartsWith', type: 'string', optional: true }, { name: 'startsWithInsensitive', type: 'string', optional: true }, { name: 'notStartsWithInsensitive', type: 'string', optional: true }, { name: 'endsWith', type: 'string', optional: true }, { name: 'notEndsWith', type: 'string', optional: true }, { name: 'endsWithInsensitive', type: 'string', optional: true }, { name: 'notEndsWithInsensitive', type: 'string', optional: true }, { name: 'like', type: 'string', optional: true }, { name: 'notLike', type: 'string', optional: true }, { name: 'likeInsensitive', type: 'string', optional: true }, { name: 'notLikeInsensitive', type: 'string', optional: true });
49
+ }
50
+ // JSON-specific operators
51
+ if (operators.includes('json')) {
52
+ props.push({ name: 'contains', type: 'unknown', optional: true }, { name: 'containedBy', type: 'unknown', optional: true }, { name: 'containsKey', type: 'string', optional: true }, { name: 'containsAllKeys', type: 'string[]', optional: true }, { name: 'containsAnyKeys', type: 'string[]', optional: true });
53
+ }
54
+ // Internet address operators
55
+ if (operators.includes('inet')) {
56
+ props.push({ name: 'contains', type: 'string', optional: true }, { name: 'containedBy', type: 'string', optional: true }, { name: 'containsOrContainedBy', type: 'string', optional: true });
57
+ }
58
+ // Full-text search operator
59
+ if (operators.includes('fulltext')) {
60
+ props.push({ name: 'matches', type: 'string', optional: true });
61
+ }
62
+ // List/Array operators (for StringListFilter, IntListFilter, etc.)
63
+ if (operators.includes('listArray')) {
64
+ // Extract base type from array type (e.g., 'string[]' -> 'string')
65
+ const baseType = tsType.replace('[]', '');
66
+ props.push({ name: 'contains', type: tsType, optional: true }, { name: 'containedBy', type: tsType, optional: true }, { name: 'overlaps', type: tsType, optional: true }, { name: 'anyEqualTo', type: baseType, optional: true }, { name: 'anyNotEqualTo', type: baseType, optional: true }, { name: 'anyLessThan', type: baseType, optional: true }, { name: 'anyLessThanOrEqualTo', type: baseType, optional: true }, { name: 'anyGreaterThan', type: baseType, optional: true }, { name: 'anyGreaterThanOrEqualTo', type: baseType, optional: true });
67
+ }
68
+ return props;
69
+ }
8
70
  /**
9
71
  * Generate types.ts content with all entity interfaces and base filter types
10
72
  */
11
- function generateTypesFile(tables) {
73
+ function generateTypesFile(tables, options = {}) {
74
+ const { enumsFromSchemaTypes = [] } = options;
75
+ const enumSet = new Set(enumsFromSchemaTypes);
12
76
  const project = (0, ts_ast_1.createProject)();
13
77
  const sourceFile = (0, ts_ast_1.createSourceFile)(project, 'types.ts');
14
78
  // Add file header
15
79
  sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)('Entity types and filter types') + '\n\n');
16
- // Add section comment
80
+ // Collect which enums are actually used by entity fields
81
+ const usedEnums = new Set();
82
+ for (const table of tables) {
83
+ const scalarFields = (0, utils_1.getScalarFields)(table);
84
+ for (const field of scalarFields) {
85
+ // Check if the field's gqlType matches any known enum
86
+ const cleanType = field.type.gqlType.replace(/!/g, '');
87
+ if (enumSet.has(cleanType)) {
88
+ usedEnums.add(cleanType);
89
+ }
90
+ }
91
+ }
92
+ // Add import for enum types from schema-types if any are used
93
+ if (usedEnums.size > 0) {
94
+ sourceFile.addImportDeclaration((0, ts_ast_1.createImport)({
95
+ moduleSpecifier: './schema-types',
96
+ typeOnlyNamedImports: Array.from(usedEnums).sort(),
97
+ }));
98
+ sourceFile.addStatements('');
99
+ }
100
+ // Add section comment for entity types
17
101
  sourceFile.addStatements('// ============================================================================');
18
102
  sourceFile.addStatements('// Entity types');
19
103
  sourceFile.addStatements('// ============================================================================\n');
@@ -26,44 +110,13 @@ function generateTypesFile(tables) {
26
110
  }));
27
111
  sourceFile.addInterface((0, ts_ast_1.createInterface)(table.name, properties));
28
112
  }
29
- // Add section comment for filters
113
+ // Add section comment for filter types
30
114
  sourceFile.addStatements('\n// ============================================================================');
31
- sourceFile.addStatements('// Filter types (shared)');
115
+ sourceFile.addStatements('// Filter types (shared PostGraphile filter interfaces)');
32
116
  sourceFile.addStatements('// ============================================================================\n');
33
- // Add base filter types (using string concat for complex types - acceptable for static definitions)
34
- const filterTypesContent = (0, filters_1.generateBaseFilterTypes)();
35
- // Extract just the interfaces part (skip the header)
36
- const filterInterfaces = filterTypesContent
37
- .split('\n')
38
- .slice(6) // Skip header lines
39
- .join('\n');
40
- sourceFile.addStatements(filterInterfaces);
41
- return (0, ts_ast_1.getFormattedOutput)(sourceFile);
42
- }
43
- /**
44
- * Generate a minimal entity type (just id and display fields)
45
- */
46
- function generateMinimalEntityType(table) {
47
- const project = (0, ts_ast_1.createProject)();
48
- const sourceFile = (0, ts_ast_1.createSourceFile)(project, 'minimal.ts');
49
- const scalarFields = (0, utils_1.getScalarFields)(table);
50
- // Find id and likely display fields
51
- const displayFields = scalarFields.filter((f) => {
52
- const name = f.name.toLowerCase();
53
- return (name === 'id' ||
54
- name === 'name' ||
55
- name === 'title' ||
56
- name === 'label' ||
57
- name === 'email' ||
58
- name.endsWith('name') ||
59
- name.endsWith('title'));
60
- });
61
- // If no display fields found, take first 5 scalar fields
62
- const fieldsToUse = displayFields.length > 0 ? displayFields : scalarFields.slice(0, 5);
63
- const properties = fieldsToUse.map((field) => ({
64
- name: field.name,
65
- type: `${(0, utils_1.fieldTypeToTs)(field.type)} | null`,
66
- }));
67
- sourceFile.addInterface((0, ts_ast_1.createInterface)(`${table.name}Minimal`, properties));
117
+ // Generate all filter types
118
+ for (const { name, tsType, operators } of FILTER_CONFIGS) {
119
+ sourceFile.addInterface((0, ts_ast_1.createInterface)(name, buildFilterProperties(tsType, operators)));
120
+ }
68
121
  return (0, ts_ast_1.getFormattedOutput)(sourceFile);
69
122
  }
@@ -134,8 +134,10 @@ export declare function gqlTypeToTs(gqlType: string, isArray?: boolean): string;
134
134
  export declare function fieldTypeToTs(fieldType: CleanFieldType): string;
135
135
  /**
136
136
  * Get the PostGraphile filter type for a GraphQL scalar
137
+ * @param gqlType - The GraphQL type string (e.g., "String", "UUID")
138
+ * @param isArray - Whether this is an array type
137
139
  */
138
- export declare function getScalarFilterType(gqlType: string): string | null;
140
+ export declare function getScalarFilterType(gqlType: string, isArray?: boolean): string | null;
139
141
  /**
140
142
  * Check if a field is a relation field (not a scalar)
141
143
  */
@@ -145,7 +147,23 @@ export declare function isRelationField(fieldName: string, table: CleanTable): b
145
147
  */
146
148
  export declare function getScalarFields(table: CleanTable): CleanField[];
147
149
  /**
148
- * Get primary key field names
150
+ * Primary key field information
151
+ */
152
+ export interface PrimaryKeyField {
153
+ /** Field name */
154
+ name: string;
155
+ /** GraphQL type (e.g., "UUID", "Int", "String") */
156
+ gqlType: string;
157
+ /** TypeScript type (e.g., "string", "number") */
158
+ tsType: string;
159
+ }
160
+ /**
161
+ * Get primary key field information from table constraints
162
+ * Returns array to support composite primary keys
163
+ */
164
+ export declare function getPrimaryKeyInfo(table: CleanTable): PrimaryKeyField[];
165
+ /**
166
+ * Get primary key field names (convenience wrapper)
149
167
  */
150
168
  export declare function getPrimaryKeyFields(table: CleanTable): string[];
151
169
  /**
@@ -32,6 +32,7 @@ exports.fieldTypeToTs = fieldTypeToTs;
32
32
  exports.getScalarFilterType = getScalarFilterType;
33
33
  exports.isRelationField = isRelationField;
34
34
  exports.getScalarFields = getScalarFields;
35
+ exports.getPrimaryKeyInfo = getPrimaryKeyInfo;
35
36
  exports.getPrimaryKeyFields = getPrimaryKeyFields;
36
37
  exports.getQueryKeyPrefix = getQueryKeyPrefix;
37
38
  exports.getGeneratedFileHeader = getGeneratedFileHeader;
@@ -258,10 +259,12 @@ function fieldTypeToTs(fieldType) {
258
259
  // ============================================================================
259
260
  /**
260
261
  * Get the PostGraphile filter type for a GraphQL scalar
262
+ * @param gqlType - The GraphQL type string (e.g., "String", "UUID")
263
+ * @param isArray - Whether this is an array type
261
264
  */
262
- function getScalarFilterType(gqlType) {
265
+ function getScalarFilterType(gqlType, isArray = false) {
263
266
  const cleanType = gqlType.replace(/!/g, '');
264
- return (0, scalars_1.scalarToFilterType)(cleanType);
267
+ return (0, scalars_1.scalarToFilterType)(cleanType, isArray);
265
268
  }
266
269
  // ============================================================================
267
270
  // Field filtering utilities
@@ -283,13 +286,35 @@ function getScalarFields(table) {
283
286
  return table.fields.filter((f) => !isRelationField(f.name, table));
284
287
  }
285
288
  /**
286
- * Get primary key field names
289
+ * Get primary key field information from table constraints
290
+ * Returns array to support composite primary keys
287
291
  */
288
- function getPrimaryKeyFields(table) {
292
+ function getPrimaryKeyInfo(table) {
289
293
  const pk = table.constraints?.primaryKey?.[0];
290
- if (!pk)
291
- return ['id']; // Default assumption
292
- return pk.fields.map((f) => f.name);
294
+ if (!pk || pk.fields.length === 0) {
295
+ // Fallback: try to find 'id' field in table fields
296
+ const idField = table.fields.find(f => f.name.toLowerCase() === 'id');
297
+ if (idField) {
298
+ return [{
299
+ name: idField.name,
300
+ gqlType: idField.type.gqlType,
301
+ tsType: fieldTypeToTs(idField.type),
302
+ }];
303
+ }
304
+ // Last resort: assume 'id' of type string (UUID)
305
+ return [{ name: 'id', gqlType: 'UUID', tsType: 'string' }];
306
+ }
307
+ return pk.fields.map((f) => ({
308
+ name: f.name,
309
+ gqlType: f.type.gqlType,
310
+ tsType: fieldTypeToTs(f.type),
311
+ }));
312
+ }
313
+ /**
314
+ * Get primary key field names (convenience wrapper)
315
+ */
316
+ function getPrimaryKeyFields(table) {
317
+ return getPrimaryKeyInfo(table).map((pk) => pk.name);
293
318
  }
294
319
  // ============================================================================
295
320
  // Query key generation
@@ -114,16 +114,16 @@ async function generateOrmCommand(options = {}) {
114
114
  }
115
115
  }
116
116
  // 7. Generate ORM code
117
- log('Generating ORM client...');
117
+ console.log('Generating code...');
118
118
  const { files: generatedFiles, stats } = (0, orm_1.generateOrm)({
119
119
  tables,
120
120
  customOperations: customOperationsData,
121
121
  config,
122
122
  });
123
- log(` Generated ${stats.tables} table models`);
124
- log(` Generated ${stats.customQueries} custom query operations`);
125
- log(` Generated ${stats.customMutations} custom mutation operations`);
126
- log(` Total files: ${stats.totalFiles}`);
123
+ console.log(`Generated ${stats.totalFiles} files`);
124
+ log(` ${stats.tables} table models`);
125
+ log(` ${stats.customQueries} custom query operations`);
126
+ log(` ${stats.customMutations} custom mutation operations`);
127
127
  if (options.dryRun) {
128
128
  return {
129
129
  success: true,
@@ -36,4 +36,7 @@ export interface WriteResult {
36
36
  filesWritten?: string[];
37
37
  errors?: string[];
38
38
  }
39
- export declare function writeGeneratedFiles(files: GeneratedFile[], outputDir: string, subdirs: string[]): Promise<WriteResult>;
39
+ export interface WriteOptions {
40
+ showProgress?: boolean;
41
+ }
42
+ export declare function writeGeneratedFiles(files: GeneratedFile[], outputDir: string, subdirs: string[], options?: WriteOptions): Promise<WriteResult>;