@constructive-io/graphql-codegen 2.20.1 → 2.22.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 +15 -3
- package/cli/codegen/barrel.d.ts +4 -1
- package/cli/codegen/barrel.js +18 -12
- package/cli/codegen/client.js +33 -0
- package/cli/codegen/custom-mutations.d.ts +11 -1
- package/cli/codegen/custom-mutations.js +49 -15
- package/cli/codegen/custom-queries.d.ts +8 -0
- package/cli/codegen/custom-queries.js +82 -47
- package/cli/codegen/gql-ast.js +9 -5
- package/cli/codegen/index.js +39 -8
- package/cli/codegen/mutations.d.ts +14 -4
- package/cli/codegen/mutations.js +114 -28
- package/cli/codegen/orm/barrel.js +4 -2
- package/cli/codegen/orm/index.js +17 -0
- package/cli/codegen/orm/input-types-generator.js +83 -29
- package/cli/codegen/orm/model-generator.js +6 -4
- package/cli/codegen/queries.d.ts +7 -3
- package/cli/codegen/queries.js +185 -158
- package/cli/codegen/scalars.d.ts +6 -4
- package/cli/codegen/scalars.js +17 -9
- package/cli/codegen/schema-types-generator.d.ts +26 -0
- package/cli/codegen/schema-types-generator.js +365 -0
- package/cli/codegen/ts-ast.d.ts +3 -1
- package/cli/codegen/ts-ast.js +2 -2
- package/cli/codegen/type-resolver.d.ts +52 -6
- package/cli/codegen/type-resolver.js +97 -19
- package/cli/codegen/types.d.ts +7 -4
- package/cli/codegen/types.js +94 -41
- package/cli/codegen/utils.d.ts +20 -2
- package/cli/codegen/utils.js +32 -7
- package/cli/commands/generate-orm.js +5 -5
- package/cli/commands/generate.d.ts +4 -1
- package/cli/commands/generate.js +27 -8
- package/cli/introspect/transform-schema.d.ts +33 -21
- package/cli/introspect/transform-schema.js +31 -21
- package/esm/cli/codegen/barrel.d.ts +4 -1
- package/esm/cli/codegen/barrel.js +18 -12
- package/esm/cli/codegen/client.js +33 -0
- package/esm/cli/codegen/custom-mutations.d.ts +11 -1
- package/esm/cli/codegen/custom-mutations.js +50 -16
- package/esm/cli/codegen/custom-queries.d.ts +8 -0
- package/esm/cli/codegen/custom-queries.js +83 -48
- package/esm/cli/codegen/gql-ast.js +10 -6
- package/esm/cli/codegen/index.js +39 -8
- package/esm/cli/codegen/mutations.d.ts +14 -4
- package/esm/cli/codegen/mutations.js +115 -29
- package/esm/cli/codegen/orm/barrel.js +4 -2
- package/esm/cli/codegen/orm/index.js +17 -0
- package/esm/cli/codegen/orm/input-types-generator.js +83 -29
- package/esm/cli/codegen/orm/model-generator.js +7 -5
- package/esm/cli/codegen/queries.d.ts +7 -3
- package/esm/cli/codegen/queries.js +186 -159
- package/esm/cli/codegen/scalars.d.ts +6 -4
- package/esm/cli/codegen/scalars.js +16 -8
- package/esm/cli/codegen/schema-types-generator.d.ts +26 -0
- package/esm/cli/codegen/schema-types-generator.js +362 -0
- package/esm/cli/codegen/ts-ast.d.ts +3 -1
- package/esm/cli/codegen/ts-ast.js +2 -2
- package/esm/cli/codegen/type-resolver.d.ts +52 -6
- package/esm/cli/codegen/type-resolver.js +97 -20
- package/esm/cli/codegen/types.d.ts +7 -4
- package/esm/cli/codegen/types.js +95 -41
- package/esm/cli/codegen/utils.d.ts +20 -2
- package/esm/cli/codegen/utils.js +31 -7
- package/esm/cli/commands/generate-orm.js +5 -5
- package/esm/cli/commands/generate.d.ts +4 -1
- package/esm/cli/commands/generate.js +27 -8
- package/esm/cli/introspect/transform-schema.d.ts +33 -21
- package/esm/cli/introspect/transform-schema.js +31 -21
- package/esm/types/config.d.ts +16 -1
- package/esm/types/config.js +6 -0
- package/esm/types/schema.d.ts +2 -0
- package/package.json +8 -6
- package/types/config.d.ts +16 -1
- package/types/config.js +6 -0
- package/types/schema.d.ts +2 -0
- package/__tests__/codegen/input-types-generator.test.d.ts +0 -1
- package/__tests__/codegen/input-types-generator.test.js +0 -635
- package/cli/codegen/filters.d.ts +0 -27
- package/cli/codegen/filters.js +0 -357
- package/cli/codegen/orm/input-types-generator.test.d.ts +0 -1
- package/cli/codegen/orm/input-types-generator.test.js +0 -75
- package/cli/codegen/orm/select-types.test.d.ts +0 -11
- package/cli/codegen/orm/select-types.test.js +0 -22
- package/cli/introspect/transform-schema.test.d.ts +0 -1
- package/cli/introspect/transform-schema.test.js +0 -67
- package/esm/__tests__/codegen/input-types-generator.test.d.ts +0 -1
- package/esm/__tests__/codegen/input-types-generator.test.js +0 -633
- package/esm/cli/codegen/filters.d.ts +0 -27
- package/esm/cli/codegen/filters.js +0 -351
- package/esm/cli/codegen/orm/input-types-generator.test.d.ts +0 -1
- package/esm/cli/codegen/orm/input-types-generator.test.js +0 -73
- package/esm/cli/codegen/orm/select-types.test.d.ts +0 -11
- package/esm/cli/codegen/orm/select-types.test.js +0 -21
- package/esm/cli/introspect/transform-schema.test.d.ts +0 -1
- 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
|
-
});
|
package/cli/codegen/filters.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PostGraphile filter type generators
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeScript interfaces for PostGraphile filter types:
|
|
5
|
-
* - Base scalar filters (StringFilter, IntFilter, etc.)
|
|
6
|
-
* - Table-specific filters (CarFilter, UserFilter, etc.)
|
|
7
|
-
* - OrderBy enum types
|
|
8
|
-
*/
|
|
9
|
-
import type { CleanTable } from '../../types/schema';
|
|
10
|
-
/**
|
|
11
|
-
* Generate all base PostGraphile filter types
|
|
12
|
-
* These are shared across all tables
|
|
13
|
-
*/
|
|
14
|
-
export declare function generateBaseFilterTypes(): string;
|
|
15
|
-
/**
|
|
16
|
-
* Generate filter interface for a specific table
|
|
17
|
-
*/
|
|
18
|
-
export declare function generateTableFilter(table: CleanTable): string;
|
|
19
|
-
/**
|
|
20
|
-
* Generate OrderBy type for a specific table
|
|
21
|
-
*/
|
|
22
|
-
export declare function generateTableOrderBy(table: CleanTable): string;
|
|
23
|
-
/**
|
|
24
|
-
* Generate inline filter and orderBy types for a query hook file
|
|
25
|
-
* These are embedded directly in the hook file for self-containment
|
|
26
|
-
*/
|
|
27
|
-
export declare function generateInlineFilterTypes(table: CleanTable): string;
|