@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
@@ -1,635 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- /**
4
- * Comprehensive tests for input-types-generator.ts
5
- *
6
- * Uses snapshot testing to validate generated TypeScript output.
7
- * These snapshots capture the current string-based output and will be
8
- * used to validate the AST-based migration produces equivalent results.
9
- */
10
- // Jest globals - no import needed
11
- const input_types_generator_1 = require("../../cli/codegen/orm/input-types-generator");
12
- // ============================================================================
13
- // Test Fixtures - Field Types
14
- // ============================================================================
15
- const fieldTypes = {
16
- uuid: { gqlType: 'UUID', isArray: false },
17
- string: { gqlType: 'String', isArray: false },
18
- int: { gqlType: 'Int', isArray: false },
19
- float: { gqlType: 'Float', isArray: false },
20
- boolean: { gqlType: 'Boolean', isArray: false },
21
- datetime: { gqlType: 'Datetime', isArray: false },
22
- date: { gqlType: 'Date', isArray: false },
23
- json: { gqlType: 'JSON', isArray: false },
24
- bigint: { gqlType: 'BigInt', isArray: false },
25
- stringArray: { gqlType: 'String', isArray: true },
26
- intArray: { gqlType: 'Int', isArray: true },
27
- };
28
- // ============================================================================
29
- // Test Fixtures - Helper Functions
30
- // ============================================================================
31
- const emptyRelations = {
32
- belongsTo: [],
33
- hasOne: [],
34
- hasMany: [],
35
- manyToMany: [],
36
- };
37
- function createTable(partial) {
38
- return {
39
- name: partial.name,
40
- fields: partial.fields ?? [],
41
- relations: partial.relations ?? emptyRelations,
42
- query: partial.query,
43
- inflection: partial.inflection,
44
- constraints: partial.constraints,
45
- };
46
- }
47
- function createTypeRegistry(types) {
48
- return new Map(Object.entries(types));
49
- }
50
- function createTypeRef(kind, name, ofType) {
51
- return { kind, name, ofType };
52
- }
53
- function createNonNull(inner) {
54
- return { kind: 'NON_NULL', name: null, ofType: inner };
55
- }
56
- function createList(inner) {
57
- return { kind: 'LIST', name: null, ofType: inner };
58
- }
59
- // ============================================================================
60
- // Test Fixtures - Sample Tables
61
- // ============================================================================
62
- /**
63
- * Simple User table with basic scalar fields
64
- */
65
- const userTable = createTable({
66
- name: 'User',
67
- fields: [
68
- { name: 'id', type: fieldTypes.uuid },
69
- { name: 'email', type: fieldTypes.string },
70
- { name: 'name', type: fieldTypes.string },
71
- { name: 'age', type: fieldTypes.int },
72
- { name: 'isActive', type: fieldTypes.boolean },
73
- { name: 'createdAt', type: fieldTypes.datetime },
74
- { name: 'metadata', type: fieldTypes.json },
75
- ],
76
- query: {
77
- all: 'users',
78
- one: 'user',
79
- create: 'createUser',
80
- update: 'updateUser',
81
- delete: 'deleteUser',
82
- },
83
- });
84
- /**
85
- * Post table with belongsTo relation to User
86
- */
87
- const postTable = createTable({
88
- name: 'Post',
89
- fields: [
90
- { name: 'id', type: fieldTypes.uuid },
91
- { name: 'title', type: fieldTypes.string },
92
- { name: 'content', type: fieldTypes.string },
93
- { name: 'authorId', type: fieldTypes.uuid },
94
- { name: 'publishedAt', type: fieldTypes.datetime },
95
- { name: 'tags', type: fieldTypes.stringArray },
96
- ],
97
- relations: {
98
- belongsTo: [
99
- {
100
- fieldName: 'author',
101
- isUnique: false,
102
- referencesTable: 'User',
103
- type: null,
104
- keys: [{ name: 'authorId', type: fieldTypes.uuid }],
105
- },
106
- ],
107
- hasOne: [],
108
- hasMany: [
109
- {
110
- fieldName: 'comments',
111
- isUnique: false,
112
- referencedByTable: 'Comment',
113
- type: null,
114
- keys: [],
115
- },
116
- ],
117
- manyToMany: [],
118
- },
119
- query: {
120
- all: 'posts',
121
- one: 'post',
122
- create: 'createPost',
123
- update: 'updatePost',
124
- delete: 'deletePost',
125
- },
126
- });
127
- /**
128
- * Comment table with relations
129
- */
130
- const commentTable = createTable({
131
- name: 'Comment',
132
- fields: [
133
- { name: 'id', type: fieldTypes.uuid },
134
- { name: 'body', type: fieldTypes.string },
135
- { name: 'postId', type: fieldTypes.uuid },
136
- { name: 'authorId', type: fieldTypes.uuid },
137
- { name: 'createdAt', type: fieldTypes.datetime },
138
- ],
139
- relations: {
140
- belongsTo: [
141
- {
142
- fieldName: 'post',
143
- isUnique: false,
144
- referencesTable: 'Post',
145
- type: null,
146
- keys: [],
147
- },
148
- {
149
- fieldName: 'author',
150
- isUnique: false,
151
- referencesTable: 'User',
152
- type: null,
153
- keys: [],
154
- },
155
- ],
156
- hasOne: [],
157
- hasMany: [],
158
- manyToMany: [],
159
- },
160
- query: {
161
- all: 'comments',
162
- one: 'comment',
163
- create: 'createComment',
164
- update: 'updateComment',
165
- delete: 'deleteComment',
166
- },
167
- });
168
- /**
169
- * User table with hasMany to posts (update to include relation)
170
- */
171
- const userTableWithRelations = createTable({
172
- ...userTable,
173
- relations: {
174
- belongsTo: [],
175
- hasOne: [],
176
- hasMany: [
177
- {
178
- fieldName: 'posts',
179
- isUnique: false,
180
- referencedByTable: 'Post',
181
- type: null,
182
- keys: [],
183
- },
184
- {
185
- fieldName: 'comments',
186
- isUnique: false,
187
- referencedByTable: 'Comment',
188
- type: null,
189
- keys: [],
190
- },
191
- ],
192
- manyToMany: [],
193
- },
194
- });
195
- /**
196
- * Category table with manyToMany relation
197
- */
198
- const categoryTable = createTable({
199
- name: 'Category',
200
- fields: [
201
- { name: 'id', type: fieldTypes.uuid },
202
- { name: 'name', type: fieldTypes.string },
203
- { name: 'slug', type: fieldTypes.string },
204
- ],
205
- relations: {
206
- belongsTo: [],
207
- hasOne: [],
208
- hasMany: [],
209
- manyToMany: [
210
- {
211
- fieldName: 'posts',
212
- rightTable: 'Post',
213
- junctionTable: 'PostCategory',
214
- type: null,
215
- },
216
- ],
217
- },
218
- query: {
219
- all: 'categories',
220
- one: 'category',
221
- create: 'createCategory',
222
- update: 'updateCategory',
223
- delete: 'deleteCategory',
224
- },
225
- });
226
- /**
227
- * Profile table with hasOne relation
228
- */
229
- const profileTable = createTable({
230
- name: 'Profile',
231
- fields: [
232
- { name: 'id', type: fieldTypes.uuid },
233
- { name: 'bio', type: fieldTypes.string },
234
- { name: 'userId', type: fieldTypes.uuid },
235
- { name: 'avatarUrl', type: fieldTypes.string },
236
- ],
237
- relations: {
238
- belongsTo: [
239
- {
240
- fieldName: 'user',
241
- isUnique: true,
242
- referencesTable: 'User',
243
- type: null,
244
- keys: [],
245
- },
246
- ],
247
- hasOne: [],
248
- hasMany: [],
249
- manyToMany: [],
250
- },
251
- query: {
252
- all: 'profiles',
253
- one: 'profile',
254
- create: 'createProfile',
255
- update: 'updateProfile',
256
- delete: 'deleteProfile',
257
- },
258
- });
259
- // User with hasOne to profile
260
- const userTableWithProfile = createTable({
261
- ...userTable,
262
- relations: {
263
- belongsTo: [],
264
- hasOne: [
265
- {
266
- fieldName: 'profile',
267
- isUnique: true,
268
- referencedByTable: 'Profile',
269
- type: null,
270
- keys: [],
271
- },
272
- ],
273
- hasMany: [
274
- {
275
- fieldName: 'posts',
276
- isUnique: false,
277
- referencedByTable: 'Post',
278
- type: null,
279
- keys: [],
280
- },
281
- ],
282
- manyToMany: [],
283
- },
284
- });
285
- // ============================================================================
286
- // Test Fixtures - Sample TypeRegistry (for custom operations)
287
- // ============================================================================
288
- const sampleTypeRegistry = createTypeRegistry({
289
- LoginInput: {
290
- kind: 'INPUT_OBJECT',
291
- name: 'LoginInput',
292
- inputFields: [
293
- { name: 'email', type: createNonNull(createTypeRef('SCALAR', 'String')) },
294
- { name: 'password', type: createNonNull(createTypeRef('SCALAR', 'String')) },
295
- { name: 'rememberMe', type: createTypeRef('SCALAR', 'Boolean') },
296
- ],
297
- },
298
- RegisterInput: {
299
- kind: 'INPUT_OBJECT',
300
- name: 'RegisterInput',
301
- inputFields: [
302
- { name: 'email', type: createNonNull(createTypeRef('SCALAR', 'String')) },
303
- { name: 'password', type: createNonNull(createTypeRef('SCALAR', 'String')) },
304
- { name: 'name', type: createTypeRef('SCALAR', 'String') },
305
- ],
306
- },
307
- UserRole: {
308
- kind: 'ENUM',
309
- name: 'UserRole',
310
- enumValues: ['ADMIN', 'USER', 'GUEST'],
311
- },
312
- LoginPayload: {
313
- kind: 'OBJECT',
314
- name: 'LoginPayload',
315
- fields: [
316
- { name: 'token', type: createTypeRef('SCALAR', 'String') },
317
- { name: 'user', type: createTypeRef('OBJECT', 'User') },
318
- { name: 'expiresAt', type: createTypeRef('SCALAR', 'Datetime') },
319
- ],
320
- },
321
- });
322
- // ============================================================================
323
- // Tests - Full File Generation
324
- // ============================================================================
325
- describe('generateInputTypesFile', () => {
326
- it('generates complete types file for single table', () => {
327
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
328
- expect(result.content).toMatchSnapshot();
329
- });
330
- it('generates complete types file for multiple tables with relations', () => {
331
- const tables = [userTableWithRelations, postTable, commentTable];
332
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), tables);
333
- expect(result.content).toMatchSnapshot();
334
- });
335
- it('generates types with hasOne relations', () => {
336
- const tables = [userTableWithProfile, profileTable];
337
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), tables);
338
- expect(result.content).toMatchSnapshot();
339
- });
340
- it('generates types with manyToMany relations', () => {
341
- const tables = [postTable, categoryTable];
342
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), tables);
343
- expect(result.content).toMatchSnapshot();
344
- });
345
- it('generates custom input types from TypeRegistry', () => {
346
- const usedInputTypes = new Set(['LoginInput', 'RegisterInput', 'UserRole']);
347
- const result = (0, input_types_generator_1.generateInputTypesFile)(sampleTypeRegistry, usedInputTypes, [userTable]);
348
- expect(result.content).toMatchSnapshot();
349
- });
350
- it('generates payload types for custom operations', () => {
351
- const usedInputTypes = new Set(['LoginInput']);
352
- const usedPayloadTypes = new Set(['LoginPayload']);
353
- const result = (0, input_types_generator_1.generateInputTypesFile)(sampleTypeRegistry, usedInputTypes, [userTable], usedPayloadTypes);
354
- expect(result.content).toMatchSnapshot();
355
- });
356
- it('handles empty tables array', () => {
357
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set());
358
- expect(result.content).toMatchSnapshot();
359
- });
360
- });
361
- // ============================================================================
362
- // Tests - Scalar Filter Types
363
- // ============================================================================
364
- describe('scalar filter types', () => {
365
- it('includes all standard scalar filter interfaces', () => {
366
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
367
- // String filters
368
- expect(result.content).toContain('export interface StringFilter {');
369
- expect(result.content).toContain('equalTo?: string;');
370
- expect(result.content).toContain('includes?: string;');
371
- expect(result.content).toContain('likeInsensitive?: string;');
372
- // Int filters
373
- expect(result.content).toContain('export interface IntFilter {');
374
- expect(result.content).toContain('lessThan?: number;');
375
- expect(result.content).toContain('greaterThanOrEqualTo?: number;');
376
- // UUID filters
377
- expect(result.content).toContain('export interface UUIDFilter {');
378
- // Datetime filters
379
- expect(result.content).toContain('export interface DatetimeFilter {');
380
- // JSON filters
381
- expect(result.content).toContain('export interface JSONFilter {');
382
- expect(result.content).toContain('containsKey?: string;');
383
- expect(result.content).toContain('containsAllKeys?: string[];');
384
- // Boolean filters
385
- expect(result.content).toContain('export interface BooleanFilter {');
386
- // BigInt filters
387
- expect(result.content).toContain('export interface BigIntFilter {');
388
- // Float filters
389
- expect(result.content).toContain('export interface FloatFilter {');
390
- });
391
- });
392
- // ============================================================================
393
- // Tests - Entity Types
394
- // ============================================================================
395
- describe('entity types', () => {
396
- it('generates entity interface with correct field types', () => {
397
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
398
- expect(result.content).toContain('export interface User {');
399
- expect(result.content).toContain('id: string;'); // UUID -> string
400
- expect(result.content).toContain('email?: string | null;');
401
- expect(result.content).toContain('age?: number | null;');
402
- expect(result.content).toContain('isActive?: boolean | null;');
403
- expect(result.content).toContain('metadata?: Record<string, unknown> | null;');
404
- });
405
- it('generates entity relations interface', () => {
406
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTableWithRelations, postTable]);
407
- expect(result.content).toContain('export interface UserRelations {');
408
- expect(result.content).toContain('posts?: ConnectionResult<Post>;');
409
- });
410
- it('generates WithRelations type alias', () => {
411
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTableWithRelations]);
412
- expect(result.content).toContain('export type UserWithRelations = User & UserRelations;');
413
- });
414
- });
415
- // ============================================================================
416
- // Tests - Select Types
417
- // ============================================================================
418
- describe('entity select types', () => {
419
- it('generates select type with scalar fields', () => {
420
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
421
- expect(result.content).toContain('export type UserSelect = {');
422
- expect(result.content).toContain('id?: boolean;');
423
- expect(result.content).toContain('email?: boolean;');
424
- expect(result.content).toContain('name?: boolean;');
425
- });
426
- it('generates select type with belongsTo relation options', () => {
427
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [postTable, userTable]);
428
- expect(result.content).toContain('export type PostSelect = {');
429
- expect(result.content).toContain('author?: boolean | { select?: UserSelect };');
430
- });
431
- it('generates select type with hasMany relation options', () => {
432
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTableWithRelations, postTable]);
433
- expect(result.content).toContain('posts?: boolean | {');
434
- expect(result.content).toContain('select?: PostSelect;');
435
- expect(result.content).toContain('first?: number;');
436
- expect(result.content).toContain('filter?: PostFilter;');
437
- expect(result.content).toContain('orderBy?: PostsOrderBy[];');
438
- });
439
- it('generates select type with manyToMany relation options', () => {
440
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [categoryTable, postTable]);
441
- expect(result.content).toContain('export type CategorySelect = {');
442
- expect(result.content).toContain('posts?: boolean | {');
443
- expect(result.content).toContain('select?: PostSelect;');
444
- });
445
- });
446
- // ============================================================================
447
- // Tests - Table Filter Types
448
- // ============================================================================
449
- describe('table filter types', () => {
450
- it('generates filter type for table', () => {
451
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
452
- expect(result.content).toContain('export interface UserFilter {');
453
- expect(result.content).toContain('id?: UUIDFilter;');
454
- expect(result.content).toContain('email?: StringFilter;');
455
- expect(result.content).toContain('age?: IntFilter;');
456
- expect(result.content).toContain('isActive?: BooleanFilter;');
457
- expect(result.content).toContain('createdAt?: DatetimeFilter;');
458
- expect(result.content).toContain('metadata?: JSONFilter;');
459
- // Logical operators
460
- expect(result.content).toContain('and?: UserFilter[];');
461
- expect(result.content).toContain('or?: UserFilter[];');
462
- expect(result.content).toContain('not?: UserFilter;');
463
- });
464
- });
465
- // ============================================================================
466
- // Tests - OrderBy Types
467
- // ============================================================================
468
- describe('orderBy types', () => {
469
- it('generates orderBy type for table', () => {
470
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
471
- expect(result.content).toContain('export type UsersOrderBy =');
472
- expect(result.content).toContain("'PRIMARY_KEY_ASC'");
473
- expect(result.content).toContain("'PRIMARY_KEY_DESC'");
474
- expect(result.content).toContain("'NATURAL'");
475
- expect(result.content).toContain("'ID_ASC'");
476
- expect(result.content).toContain("'ID_DESC'");
477
- expect(result.content).toContain("'EMAIL_ASC'");
478
- expect(result.content).toContain("'NAME_DESC'");
479
- });
480
- });
481
- // ============================================================================
482
- // Tests - CRUD Input Types
483
- // ============================================================================
484
- describe('CRUD input types', () => {
485
- it('generates create input type', () => {
486
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
487
- expect(result.content).toContain('export interface CreateUserInput {');
488
- expect(result.content).toContain('clientMutationId?: string;');
489
- expect(result.content).toContain('user: {');
490
- expect(result.content).toContain('email?: string;');
491
- expect(result.content).toContain('name?: string;');
492
- // Should not include auto-generated fields
493
- expect(result.content).not.toMatch(/user:\s*\{[^}]*\bid\b/);
494
- });
495
- it('generates update input type with patch', () => {
496
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
497
- expect(result.content).toContain('export interface UserPatch {');
498
- expect(result.content).toContain('email?: string | null;');
499
- expect(result.content).toContain('name?: string | null;');
500
- expect(result.content).toContain('export interface UpdateUserInput {');
501
- expect(result.content).toContain('id: string;');
502
- expect(result.content).toContain('patch: UserPatch;');
503
- });
504
- it('generates delete input type', () => {
505
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [userTable]);
506
- expect(result.content).toContain('export interface DeleteUserInput {');
507
- expect(result.content).toContain('clientMutationId?: string;');
508
- expect(result.content).toContain('id: string;');
509
- });
510
- });
511
- // ============================================================================
512
- // Tests - Custom Input Types (from TypeRegistry)
513
- // ============================================================================
514
- describe('custom input types', () => {
515
- it('generates input types from TypeRegistry', () => {
516
- const usedInputTypes = new Set(['LoginInput', 'RegisterInput']);
517
- const result = (0, input_types_generator_1.generateInputTypesFile)(sampleTypeRegistry, usedInputTypes, []);
518
- expect(result.content).toContain('export interface LoginInput {');
519
- expect(result.content).toContain('email: string;'); // Non-null
520
- expect(result.content).toContain('password: string;'); // Non-null
521
- expect(result.content).toContain('rememberMe?: boolean;'); // Optional
522
- });
523
- it('generates enum types from TypeRegistry', () => {
524
- const usedInputTypes = new Set(['UserRole']);
525
- const result = (0, input_types_generator_1.generateInputTypesFile)(sampleTypeRegistry, usedInputTypes, []);
526
- expect(result.content).toContain("export type UserRole = 'ADMIN' | 'USER' | 'GUEST';");
527
- });
528
- });
529
- // ============================================================================
530
- // Tests - Payload/Return Types
531
- // ============================================================================
532
- describe('payload types', () => {
533
- it('generates payload types for custom operations', () => {
534
- const usedInputTypes = new Set();
535
- const usedPayloadTypes = new Set(['LoginPayload']);
536
- const result = (0, input_types_generator_1.generateInputTypesFile)(sampleTypeRegistry, usedInputTypes, [], usedPayloadTypes);
537
- expect(result.content).toContain('export interface LoginPayload {');
538
- expect(result.content).toContain('token?: string | null;');
539
- expect(result.content).toContain('expiresAt?: string | null;');
540
- });
541
- it('generates Select types for payload types', () => {
542
- const usedInputTypes = new Set();
543
- const usedPayloadTypes = new Set(['LoginPayload']);
544
- const result = (0, input_types_generator_1.generateInputTypesFile)(sampleTypeRegistry, usedInputTypes, [], usedPayloadTypes);
545
- expect(result.content).toContain('export type LoginPayloadSelect = {');
546
- expect(result.content).toContain('token?: boolean;');
547
- expect(result.content).toContain('expiresAt?: boolean;');
548
- });
549
- });
550
- // ============================================================================
551
- // Tests - Helper Functions
552
- // ============================================================================
553
- describe('collectInputTypeNames', () => {
554
- it('collects Input type names from operations', () => {
555
- const operations = [
556
- {
557
- args: [
558
- { name: 'input', type: createNonNull(createTypeRef('INPUT_OBJECT', 'LoginInput')) },
559
- ],
560
- },
561
- {
562
- args: [
563
- { name: 'data', type: createTypeRef('INPUT_OBJECT', 'RegisterInput') },
564
- ],
565
- },
566
- ];
567
- const result = (0, input_types_generator_1.collectInputTypeNames)(operations);
568
- expect(result.has('LoginInput')).toBe(true);
569
- expect(result.has('RegisterInput')).toBe(true);
570
- });
571
- it('collects Filter type names', () => {
572
- const operations = [
573
- {
574
- args: [
575
- { name: 'filter', type: createTypeRef('INPUT_OBJECT', 'UserFilter') },
576
- ],
577
- },
578
- ];
579
- const result = (0, input_types_generator_1.collectInputTypeNames)(operations);
580
- expect(result.has('UserFilter')).toBe(true);
581
- });
582
- });
583
- describe('collectPayloadTypeNames', () => {
584
- it('collects Payload type names from operations', () => {
585
- const operations = [
586
- { returnType: createTypeRef('OBJECT', 'LoginPayload') },
587
- { returnType: createTypeRef('OBJECT', 'RegisterPayload') },
588
- ];
589
- const result = (0, input_types_generator_1.collectPayloadTypeNames)(operations);
590
- expect(result.has('LoginPayload')).toBe(true);
591
- expect(result.has('RegisterPayload')).toBe(true);
592
- });
593
- it('excludes Connection types', () => {
594
- const operations = [
595
- { returnType: createTypeRef('OBJECT', 'UsersConnection') },
596
- ];
597
- const result = (0, input_types_generator_1.collectPayloadTypeNames)(operations);
598
- expect(result.has('UsersConnection')).toBe(false);
599
- });
600
- });
601
- // ============================================================================
602
- // Tests - Edge Cases
603
- // ============================================================================
604
- describe('edge cases', () => {
605
- it('handles table with no fields', () => {
606
- const emptyTable = createTable({ name: 'Empty', fields: [] });
607
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [emptyTable]);
608
- expect(result.content).toContain('export interface Empty {');
609
- expect(result.content).toContain('export interface EmptyFilter {');
610
- });
611
- it('handles table with only id field', () => {
612
- const minimalTable = createTable({
613
- name: 'Minimal',
614
- fields: [{ name: 'id', type: fieldTypes.uuid }],
615
- });
616
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), [minimalTable]);
617
- expect(result.content).toContain('export interface Minimal {');
618
- expect(result.content).toContain('id: string;');
619
- });
620
- it('handles circular relations gracefully', () => {
621
- // User has posts, Post has author (User)
622
- const tables = [userTableWithRelations, postTable];
623
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), new Set(), tables);
624
- // Should not cause infinite loops or errors
625
- expect(result.content).toContain('export type UserSelect = {');
626
- expect(result.content).toContain('export type PostSelect = {');
627
- });
628
- it('handles unknown input type gracefully', () => {
629
- const usedInputTypes = new Set(['UnknownType']);
630
- const result = (0, input_types_generator_1.generateInputTypesFile)(new Map(), usedInputTypes, []);
631
- // Should generate a fallback type
632
- expect(result.content).toContain("// Type 'UnknownType' not found in schema");
633
- expect(result.content).toContain('export type UnknownType = Record<string, unknown>;');
634
- });
635
- });
@@ -1 +0,0 @@
1
- export {};