@constructive-io/graphql-codegen 2.24.0 → 2.26.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 +403 -279
- package/cli/codegen/babel-ast.d.ts +7 -0
- package/cli/codegen/babel-ast.js +15 -0
- package/cli/codegen/barrel.js +43 -14
- package/cli/codegen/custom-mutations.js +4 -4
- package/cli/codegen/custom-queries.js +12 -22
- package/cli/codegen/gql-ast.js +22 -1
- package/cli/codegen/index.js +1 -0
- package/cli/codegen/mutations.d.ts +2 -0
- package/cli/codegen/mutations.js +26 -13
- package/cli/codegen/orm/client-generator.js +475 -136
- package/cli/codegen/orm/custom-ops-generator.js +8 -3
- package/cli/codegen/orm/input-types-generator.js +22 -0
- package/cli/codegen/orm/model-generator.js +18 -5
- package/cli/codegen/orm/select-types.d.ts +33 -0
- package/cli/codegen/queries.d.ts +1 -1
- package/cli/codegen/queries.js +112 -35
- package/cli/codegen/utils.d.ts +6 -0
- package/cli/codegen/utils.js +19 -0
- package/cli/commands/generate-orm.d.ts +14 -0
- package/cli/commands/generate-orm.js +160 -44
- package/cli/commands/generate.d.ts +22 -0
- package/cli/commands/generate.js +195 -55
- package/cli/commands/init.js +29 -9
- package/cli/index.js +133 -28
- package/cli/watch/orchestrator.d.ts +4 -0
- package/cli/watch/orchestrator.js +4 -0
- package/esm/cli/codegen/babel-ast.d.ts +7 -0
- package/esm/cli/codegen/babel-ast.js +14 -0
- package/esm/cli/codegen/barrel.js +44 -15
- package/esm/cli/codegen/custom-mutations.js +5 -5
- package/esm/cli/codegen/custom-queries.js +13 -23
- package/esm/cli/codegen/gql-ast.js +23 -2
- package/esm/cli/codegen/index.js +1 -0
- package/esm/cli/codegen/mutations.d.ts +2 -0
- package/esm/cli/codegen/mutations.js +27 -14
- package/esm/cli/codegen/orm/client-generator.js +475 -136
- package/esm/cli/codegen/orm/custom-ops-generator.js +8 -3
- package/esm/cli/codegen/orm/input-types-generator.js +22 -0
- package/esm/cli/codegen/orm/model-generator.js +18 -5
- package/esm/cli/codegen/orm/select-types.d.ts +33 -0
- package/esm/cli/codegen/queries.d.ts +1 -1
- package/esm/cli/codegen/queries.js +114 -37
- package/esm/cli/codegen/utils.d.ts +6 -0
- package/esm/cli/codegen/utils.js +18 -0
- package/esm/cli/commands/generate-orm.d.ts +14 -0
- package/esm/cli/commands/generate-orm.js +161 -45
- package/esm/cli/commands/generate.d.ts +22 -0
- package/esm/cli/commands/generate.js +195 -56
- package/esm/cli/commands/init.js +29 -9
- package/esm/cli/index.js +134 -29
- package/esm/cli/watch/orchestrator.d.ts +4 -0
- package/esm/cli/watch/orchestrator.js +5 -1
- package/esm/types/config.d.ts +39 -2
- package/esm/types/config.js +88 -4
- package/esm/types/index.d.ts +2 -2
- package/esm/types/index.js +1 -1
- package/package.json +10 -7
- package/types/config.d.ts +39 -2
- package/types/config.js +91 -4
- package/types/index.d.ts +2 -2
- package/types/index.js +2 -1
- package/cli/codegen/orm/query-builder.d.ts +0 -161
- package/cli/codegen/orm/query-builder.js +0 -366
- package/esm/cli/codegen/orm/query-builder.d.ts +0 -161
- package/esm/cli/codegen/orm/query-builder.js +0 -353
package/cli/index.js
CHANGED
|
@@ -42,6 +42,17 @@ const generate_1 = require("./commands/generate");
|
|
|
42
42
|
const generate_orm_1 = require("./commands/generate-orm");
|
|
43
43
|
const watch_1 = require("./watch");
|
|
44
44
|
const config_1 = require("../types/config");
|
|
45
|
+
/**
|
|
46
|
+
* Format duration in a human-readable way
|
|
47
|
+
* - Under 1 second: show milliseconds (e.g., "123ms")
|
|
48
|
+
* - Over 1 second: show seconds with 2 decimal places (e.g., "1.23s")
|
|
49
|
+
*/
|
|
50
|
+
function formatDuration(ms) {
|
|
51
|
+
if (ms < 1000) {
|
|
52
|
+
return `${Math.round(ms)}ms`;
|
|
53
|
+
}
|
|
54
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
55
|
+
}
|
|
45
56
|
const program = new commander_1.Command();
|
|
46
57
|
/**
|
|
47
58
|
* Load configuration for watch mode, merging CLI options with config file
|
|
@@ -61,23 +72,27 @@ async function loadWatchConfig(options) {
|
|
|
61
72
|
}
|
|
62
73
|
baseConfig = loadResult.config;
|
|
63
74
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
if ((0, config_1.isMultiConfig)(baseConfig)) {
|
|
76
|
+
if (!options.target) {
|
|
77
|
+
console.error('x Watch mode requires --target when using multiple targets.');
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (!baseConfig.targets[options.target]) {
|
|
81
|
+
console.error(`x Target "${options.target}" not found in config file.`);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (options.target) {
|
|
86
|
+
console.error('x Config file does not define targets. Remove --target.');
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const sourceOverrides = {};
|
|
90
|
+
if (options.endpoint) {
|
|
91
|
+
sourceOverrides.endpoint = options.endpoint;
|
|
92
|
+
sourceOverrides.schema = undefined;
|
|
93
|
+
}
|
|
94
|
+
const watchOverrides = {
|
|
78
95
|
watch: {
|
|
79
|
-
...baseConfig.watch,
|
|
80
|
-
// CLI options override config
|
|
81
96
|
...(options.pollInterval !== undefined && {
|
|
82
97
|
pollInterval: options.pollInterval,
|
|
83
98
|
}),
|
|
@@ -86,11 +101,26 @@ async function loadWatchConfig(options) {
|
|
|
86
101
|
...(options.clear !== undefined && { clearScreen: options.clear }),
|
|
87
102
|
},
|
|
88
103
|
};
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
let mergedTarget;
|
|
105
|
+
if ((0, config_1.isMultiConfig)(baseConfig)) {
|
|
106
|
+
const defaults = baseConfig.defaults ?? {};
|
|
107
|
+
const targetConfig = baseConfig.targets[options.target];
|
|
108
|
+
mergedTarget = (0, config_1.mergeConfig)(defaults, targetConfig);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
mergedTarget = baseConfig;
|
|
112
|
+
}
|
|
113
|
+
mergedTarget = (0, config_1.mergeConfig)(mergedTarget, sourceOverrides);
|
|
114
|
+
mergedTarget = (0, config_1.mergeConfig)(mergedTarget, watchOverrides);
|
|
115
|
+
if (!mergedTarget.endpoint) {
|
|
116
|
+
console.error('x No endpoint specified. Watch mode only supports live endpoints.');
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (mergedTarget.schema) {
|
|
120
|
+
console.error('x Watch mode is only supported with an endpoint, not schema.');
|
|
91
121
|
return null;
|
|
92
122
|
}
|
|
93
|
-
return (0, config_1.resolveConfig)(
|
|
123
|
+
return (0, config_1.resolveConfig)(mergedTarget);
|
|
94
124
|
}
|
|
95
125
|
program
|
|
96
126
|
.name('graphql-codegen')
|
|
@@ -105,17 +135,19 @@ program
|
|
|
105
135
|
.option('-e, --endpoint <url>', 'GraphQL endpoint URL to pre-populate')
|
|
106
136
|
.option('-o, --output <dir>', 'Output directory to pre-populate', './generated')
|
|
107
137
|
.action(async (options) => {
|
|
138
|
+
const startTime = performance.now();
|
|
108
139
|
const result = await (0, init_1.initCommand)({
|
|
109
140
|
directory: options.directory,
|
|
110
141
|
force: options.force,
|
|
111
142
|
endpoint: options.endpoint,
|
|
112
143
|
output: options.output,
|
|
113
144
|
});
|
|
145
|
+
const duration = formatDuration(performance.now() - startTime);
|
|
114
146
|
if (result.success) {
|
|
115
|
-
console.log('[ok]', result.message);
|
|
147
|
+
console.log('[ok]', result.message, `(${duration})`);
|
|
116
148
|
}
|
|
117
149
|
else {
|
|
118
|
-
console.error('x', result.message);
|
|
150
|
+
console.error('x', result.message, `(${duration})`);
|
|
119
151
|
process.exit(1);
|
|
120
152
|
}
|
|
121
153
|
});
|
|
@@ -124,6 +156,7 @@ program
|
|
|
124
156
|
.command('generate')
|
|
125
157
|
.description('Generate SDK from GraphQL endpoint or schema file')
|
|
126
158
|
.option('-c, --config <path>', 'Path to config file')
|
|
159
|
+
.option('-t, --target <name>', 'Target name in config file')
|
|
127
160
|
.option('-e, --endpoint <url>', 'GraphQL endpoint URL (overrides config)')
|
|
128
161
|
.option('-s, --schema <path>', 'Path to GraphQL schema file (.graphql)')
|
|
129
162
|
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
@@ -136,6 +169,7 @@ program
|
|
|
136
169
|
.option('--touch <file>', 'File to touch on schema change')
|
|
137
170
|
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
138
171
|
.action(async (options) => {
|
|
172
|
+
const startTime = performance.now();
|
|
139
173
|
// Validate source options
|
|
140
174
|
if (options.endpoint && options.schema) {
|
|
141
175
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
@@ -156,6 +190,8 @@ program
|
|
|
156
190
|
generatorType: 'generate',
|
|
157
191
|
verbose: options.verbose,
|
|
158
192
|
authorization: options.authorization,
|
|
193
|
+
configPath: options.config,
|
|
194
|
+
target: options.target,
|
|
159
195
|
outputDir: options.output,
|
|
160
196
|
});
|
|
161
197
|
return;
|
|
@@ -163,6 +199,7 @@ program
|
|
|
163
199
|
// Normal one-shot generation
|
|
164
200
|
const result = await (0, generate_1.generateCommand)({
|
|
165
201
|
config: options.config,
|
|
202
|
+
target: options.target,
|
|
166
203
|
endpoint: options.endpoint,
|
|
167
204
|
schema: options.schema,
|
|
168
205
|
output: options.output,
|
|
@@ -170,8 +207,34 @@ program
|
|
|
170
207
|
verbose: options.verbose,
|
|
171
208
|
dryRun: options.dryRun,
|
|
172
209
|
});
|
|
210
|
+
const duration = formatDuration(performance.now() - startTime);
|
|
211
|
+
const targetResults = result.targets ?? [];
|
|
212
|
+
const hasNamedTargets = targetResults.length > 0 &&
|
|
213
|
+
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
214
|
+
if (hasNamedTargets) {
|
|
215
|
+
console.log(result.success ? '[ok]' : 'x', result.message);
|
|
216
|
+
targetResults.forEach((target) => {
|
|
217
|
+
const status = target.success ? '[ok]' : 'x';
|
|
218
|
+
console.log(`\n${status} ${target.message}`);
|
|
219
|
+
if (target.tables && target.tables.length > 0) {
|
|
220
|
+
console.log(' Tables:');
|
|
221
|
+
target.tables.forEach((table) => console.log(` - ${table}`));
|
|
222
|
+
}
|
|
223
|
+
if (target.filesWritten && target.filesWritten.length > 0) {
|
|
224
|
+
console.log(' Files written:');
|
|
225
|
+
target.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
226
|
+
}
|
|
227
|
+
if (!target.success && target.errors) {
|
|
228
|
+
target.errors.forEach((error) => console.error(` - ${error}`));
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
if (!result.success) {
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
173
236
|
if (result.success) {
|
|
174
|
-
console.log('[ok]', result.message);
|
|
237
|
+
console.log('[ok]', result.message, `(${duration})`);
|
|
175
238
|
if (result.tables && result.tables.length > 0) {
|
|
176
239
|
console.log('\nTables:');
|
|
177
240
|
result.tables.forEach((t) => console.log(` - ${t}`));
|
|
@@ -182,7 +245,7 @@ program
|
|
|
182
245
|
}
|
|
183
246
|
}
|
|
184
247
|
else {
|
|
185
|
-
console.error('x', result.message);
|
|
248
|
+
console.error('x', result.message, `(${duration})`);
|
|
186
249
|
if (result.errors) {
|
|
187
250
|
result.errors.forEach((e) => console.error(' -', e));
|
|
188
251
|
}
|
|
@@ -194,9 +257,10 @@ program
|
|
|
194
257
|
.command('generate-orm')
|
|
195
258
|
.description('Generate Prisma-like ORM client from GraphQL endpoint or schema file')
|
|
196
259
|
.option('-c, --config <path>', 'Path to config file')
|
|
260
|
+
.option('-t, --target <name>', 'Target name in config file')
|
|
197
261
|
.option('-e, --endpoint <url>', 'GraphQL endpoint URL (overrides config)')
|
|
198
262
|
.option('-s, --schema <path>', 'Path to GraphQL schema file (.graphql)')
|
|
199
|
-
.option('-o, --output <dir>', 'Output directory (overrides config)'
|
|
263
|
+
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
200
264
|
.option('-a, --authorization <header>', 'Authorization header value')
|
|
201
265
|
.option('-v, --verbose', 'Verbose output', false)
|
|
202
266
|
.option('--dry-run', 'Dry run - show what would be generated without writing files', false)
|
|
@@ -207,6 +271,7 @@ program
|
|
|
207
271
|
.option('--touch <file>', 'File to touch on schema change')
|
|
208
272
|
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
209
273
|
.action(async (options) => {
|
|
274
|
+
const startTime = performance.now();
|
|
210
275
|
// Validate source options
|
|
211
276
|
if (options.endpoint && options.schema) {
|
|
212
277
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
@@ -227,6 +292,8 @@ program
|
|
|
227
292
|
generatorType: 'generate-orm',
|
|
228
293
|
verbose: options.verbose,
|
|
229
294
|
authorization: options.authorization,
|
|
295
|
+
configPath: options.config,
|
|
296
|
+
target: options.target,
|
|
230
297
|
outputDir: options.output,
|
|
231
298
|
skipCustomOperations: options.skipCustomOperations,
|
|
232
299
|
});
|
|
@@ -235,6 +302,7 @@ program
|
|
|
235
302
|
// Normal one-shot generation
|
|
236
303
|
const result = await (0, generate_orm_1.generateOrmCommand)({
|
|
237
304
|
config: options.config,
|
|
305
|
+
target: options.target,
|
|
238
306
|
endpoint: options.endpoint,
|
|
239
307
|
schema: options.schema,
|
|
240
308
|
output: options.output,
|
|
@@ -243,8 +311,42 @@ program
|
|
|
243
311
|
dryRun: options.dryRun,
|
|
244
312
|
skipCustomOperations: options.skipCustomOperations,
|
|
245
313
|
});
|
|
314
|
+
const duration = formatDuration(performance.now() - startTime);
|
|
315
|
+
const targetResults = result.targets ?? [];
|
|
316
|
+
const hasNamedTargets = targetResults.length > 0 &&
|
|
317
|
+
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
318
|
+
if (hasNamedTargets) {
|
|
319
|
+
console.log(result.success ? '[ok]' : 'x', result.message);
|
|
320
|
+
targetResults.forEach((target) => {
|
|
321
|
+
const status = target.success ? '[ok]' : 'x';
|
|
322
|
+
console.log(`\n${status} ${target.message}`);
|
|
323
|
+
if (target.tables && target.tables.length > 0) {
|
|
324
|
+
console.log(' Tables:');
|
|
325
|
+
target.tables.forEach((table) => console.log(` - ${table}`));
|
|
326
|
+
}
|
|
327
|
+
if (target.customQueries && target.customQueries.length > 0) {
|
|
328
|
+
console.log(' Custom Queries:');
|
|
329
|
+
target.customQueries.forEach((query) => console.log(` - ${query}`));
|
|
330
|
+
}
|
|
331
|
+
if (target.customMutations && target.customMutations.length > 0) {
|
|
332
|
+
console.log(' Custom Mutations:');
|
|
333
|
+
target.customMutations.forEach((mutation) => console.log(` - ${mutation}`));
|
|
334
|
+
}
|
|
335
|
+
if (target.filesWritten && target.filesWritten.length > 0) {
|
|
336
|
+
console.log(' Files written:');
|
|
337
|
+
target.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
338
|
+
}
|
|
339
|
+
if (!target.success && target.errors) {
|
|
340
|
+
target.errors.forEach((error) => console.error(` - ${error}`));
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
if (!result.success) {
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
246
348
|
if (result.success) {
|
|
247
|
-
console.log('[ok]', result.message);
|
|
349
|
+
console.log('[ok]', result.message, `(${duration})`);
|
|
248
350
|
if (result.tables && result.tables.length > 0) {
|
|
249
351
|
console.log('\nTables:');
|
|
250
352
|
result.tables.forEach((t) => console.log(` - ${t}`));
|
|
@@ -263,7 +365,7 @@ program
|
|
|
263
365
|
}
|
|
264
366
|
}
|
|
265
367
|
else {
|
|
266
|
-
console.error('x', result.message);
|
|
368
|
+
console.error('x', result.message, `(${duration})`);
|
|
267
369
|
if (result.errors) {
|
|
268
370
|
result.errors.forEach((e) => console.error(' -', e));
|
|
269
371
|
}
|
|
@@ -279,6 +381,7 @@ program
|
|
|
279
381
|
.option('-a, --authorization <header>', 'Authorization header value')
|
|
280
382
|
.option('--json', 'Output as JSON', false)
|
|
281
383
|
.action(async (options) => {
|
|
384
|
+
const startTime = performance.now();
|
|
282
385
|
// Validate source options
|
|
283
386
|
if (!options.endpoint && !options.schema) {
|
|
284
387
|
console.error('x Either --endpoint or --schema must be provided.');
|
|
@@ -299,11 +402,12 @@ program
|
|
|
299
402
|
console.log('Fetching schema from', source.describe(), '...');
|
|
300
403
|
const { introspection } = await source.fetch();
|
|
301
404
|
const tables = inferTablesFromIntrospection(introspection);
|
|
405
|
+
const duration = formatDuration(performance.now() - startTime);
|
|
302
406
|
if (options.json) {
|
|
303
407
|
console.log(JSON.stringify(tables, null, 2));
|
|
304
408
|
}
|
|
305
409
|
else {
|
|
306
|
-
console.log(`\n[ok] Found ${tables.length} tables:\n`);
|
|
410
|
+
console.log(`\n[ok] Found ${tables.length} tables (${duration}):\n`);
|
|
307
411
|
tables.forEach((table) => {
|
|
308
412
|
const fieldCount = table.fields.length;
|
|
309
413
|
const relationCount = table.relations.belongsTo.length +
|
|
@@ -315,7 +419,8 @@ program
|
|
|
315
419
|
}
|
|
316
420
|
}
|
|
317
421
|
catch (err) {
|
|
318
|
-
|
|
422
|
+
const duration = formatDuration(performance.now() - startTime);
|
|
423
|
+
console.error('x Failed to introspect schema:', err instanceof Error ? err.message : err, `(${duration})`);
|
|
319
424
|
process.exit(1);
|
|
320
425
|
}
|
|
321
426
|
});
|
|
@@ -10,6 +10,10 @@ export interface WatchOrchestratorOptions {
|
|
|
10
10
|
generatorType: GeneratorType;
|
|
11
11
|
verbose: boolean;
|
|
12
12
|
authorization?: string;
|
|
13
|
+
/** Config file path for regeneration */
|
|
14
|
+
configPath?: string;
|
|
15
|
+
/** Target name for multi-target configs */
|
|
16
|
+
target?: string;
|
|
13
17
|
/** Override output directory (for ORM) */
|
|
14
18
|
outputDir?: string;
|
|
15
19
|
/** Skip custom operations flag */
|
|
@@ -138,6 +138,8 @@ class WatchOrchestrator {
|
|
|
138
138
|
let result;
|
|
139
139
|
if (this.options.generatorType === 'generate') {
|
|
140
140
|
result = await (0, generate_1.generateCommand)({
|
|
141
|
+
config: this.options.configPath,
|
|
142
|
+
target: this.options.target,
|
|
141
143
|
endpoint: this.options.config.endpoint,
|
|
142
144
|
output: this.options.outputDir ?? this.options.config.output,
|
|
143
145
|
authorization: this.options.authorization,
|
|
@@ -147,6 +149,8 @@ class WatchOrchestrator {
|
|
|
147
149
|
}
|
|
148
150
|
else {
|
|
149
151
|
result = await (0, generate_orm_1.generateOrmCommand)({
|
|
152
|
+
config: this.options.configPath,
|
|
153
|
+
target: this.options.target,
|
|
150
154
|
endpoint: this.options.config.endpoint,
|
|
151
155
|
output: this.options.outputDir ?? this.options.config.orm?.output,
|
|
152
156
|
authorization: this.options.authorization,
|
|
@@ -44,3 +44,10 @@ export declare function typedParam(name: string, typeAnnotation: t.TSType, optio
|
|
|
44
44
|
* Create keyof typeof expression - complex nested type operators
|
|
45
45
|
*/
|
|
46
46
|
export declare function keyofTypeof(name: string): t.TSTypeOperator;
|
|
47
|
+
/**
|
|
48
|
+
* Create a call expression with TypeScript type parameters
|
|
49
|
+
*
|
|
50
|
+
* This is used to generate typed function calls like:
|
|
51
|
+
* execute<ResultType, VariablesType>(document, variables)
|
|
52
|
+
*/
|
|
53
|
+
export declare function createTypedCallExpression(callee: t.Expression, args: (t.Expression | t.SpreadElement)[], typeParams: t.TSType[]): t.CallExpression;
|
|
@@ -95,3 +95,17 @@ export function keyofTypeof(name) {
|
|
|
95
95
|
keyofOp.operator = 'keyof';
|
|
96
96
|
return keyofOp;
|
|
97
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Create a call expression with TypeScript type parameters
|
|
100
|
+
*
|
|
101
|
+
* This is used to generate typed function calls like:
|
|
102
|
+
* execute<ResultType, VariablesType>(document, variables)
|
|
103
|
+
*/
|
|
104
|
+
export function createTypedCallExpression(callee, args, typeParams) {
|
|
105
|
+
const call = t.callExpression(callee, args);
|
|
106
|
+
if (typeParams.length > 0) {
|
|
107
|
+
// @ts-ignore - Babel types support typeParameters on CallExpression for TS
|
|
108
|
+
call.typeParameters = t.tsTypeParameterInstantiation(typeParams);
|
|
109
|
+
}
|
|
110
|
+
return call;
|
|
111
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import { generateCode, addJSDocComment } from './babel-ast';
|
|
3
|
-
import { getListQueryHookName, getSingleQueryHookName, getCreateMutationHookName, getUpdateMutationHookName, getDeleteMutationHookName, } from './utils';
|
|
3
|
+
import { getListQueryHookName, getSingleQueryHookName, getCreateMutationHookName, getUpdateMutationHookName, getDeleteMutationHookName, hasValidPrimaryKey, } from './utils';
|
|
4
4
|
import { getOperationHookName } from './type-resolver';
|
|
5
5
|
/**
|
|
6
6
|
* Helper to create export * from './module' statement
|
|
@@ -16,9 +16,12 @@ export function generateQueriesBarrel(tables) {
|
|
|
16
16
|
// Export all query hooks
|
|
17
17
|
for (const table of tables) {
|
|
18
18
|
const listHookName = getListQueryHookName(table);
|
|
19
|
-
const singleHookName = getSingleQueryHookName(table);
|
|
20
19
|
statements.push(exportAllFrom(`./${listHookName}`));
|
|
21
|
-
|
|
20
|
+
// Only export single query hook if table has valid primary key
|
|
21
|
+
if (hasValidPrimaryKey(table)) {
|
|
22
|
+
const singleHookName = getSingleQueryHookName(table);
|
|
23
|
+
statements.push(exportAllFrom(`./${singleHookName}`));
|
|
24
|
+
}
|
|
22
25
|
}
|
|
23
26
|
// Add file header as leading comment on first statement
|
|
24
27
|
if (statements.length > 0) {
|
|
@@ -135,17 +138,30 @@ export function generateMainBarrel(tables, options = {}) {
|
|
|
135
138
|
*/
|
|
136
139
|
export function generateCustomQueriesBarrel(tables, customQueryNames) {
|
|
137
140
|
const statements = [];
|
|
141
|
+
const exportedHooks = new Set();
|
|
138
142
|
// Export all table query hooks
|
|
139
143
|
for (const table of tables) {
|
|
140
144
|
const listHookName = getListQueryHookName(table);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
if (!exportedHooks.has(listHookName)) {
|
|
146
|
+
statements.push(exportAllFrom(`./${listHookName}`));
|
|
147
|
+
exportedHooks.add(listHookName);
|
|
148
|
+
}
|
|
149
|
+
// Only export single query hook if table has valid primary key
|
|
150
|
+
if (hasValidPrimaryKey(table)) {
|
|
151
|
+
const singleHookName = getSingleQueryHookName(table);
|
|
152
|
+
if (!exportedHooks.has(singleHookName)) {
|
|
153
|
+
statements.push(exportAllFrom(`./${singleHookName}`));
|
|
154
|
+
exportedHooks.add(singleHookName);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
144
157
|
}
|
|
145
|
-
// Add custom query hooks
|
|
158
|
+
// Add custom query hooks (skip if already exported from table hooks)
|
|
146
159
|
for (const name of customQueryNames) {
|
|
147
160
|
const hookName = getOperationHookName(name, 'query');
|
|
148
|
-
|
|
161
|
+
if (!exportedHooks.has(hookName)) {
|
|
162
|
+
statements.push(exportAllFrom(`./${hookName}`));
|
|
163
|
+
exportedHooks.add(hookName);
|
|
164
|
+
}
|
|
149
165
|
}
|
|
150
166
|
// Add file header as leading comment on first statement
|
|
151
167
|
if (statements.length > 0) {
|
|
@@ -162,24 +178,37 @@ export function generateCustomQueriesBarrel(tables, customQueryNames) {
|
|
|
162
178
|
*/
|
|
163
179
|
export function generateCustomMutationsBarrel(tables, customMutationNames) {
|
|
164
180
|
const statements = [];
|
|
181
|
+
const exportedHooks = new Set();
|
|
165
182
|
// Export all table mutation hooks
|
|
166
183
|
for (const table of tables) {
|
|
167
184
|
const createHookName = getCreateMutationHookName(table);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
if (!exportedHooks.has(createHookName)) {
|
|
186
|
+
statements.push(exportAllFrom(`./${createHookName}`));
|
|
187
|
+
exportedHooks.add(createHookName);
|
|
188
|
+
}
|
|
171
189
|
// Only add update/delete if they exist
|
|
172
190
|
if (table.query?.update !== null) {
|
|
173
|
-
|
|
191
|
+
const updateHookName = getUpdateMutationHookName(table);
|
|
192
|
+
if (!exportedHooks.has(updateHookName)) {
|
|
193
|
+
statements.push(exportAllFrom(`./${updateHookName}`));
|
|
194
|
+
exportedHooks.add(updateHookName);
|
|
195
|
+
}
|
|
174
196
|
}
|
|
175
197
|
if (table.query?.delete !== null) {
|
|
176
|
-
|
|
198
|
+
const deleteHookName = getDeleteMutationHookName(table);
|
|
199
|
+
if (!exportedHooks.has(deleteHookName)) {
|
|
200
|
+
statements.push(exportAllFrom(`./${deleteHookName}`));
|
|
201
|
+
exportedHooks.add(deleteHookName);
|
|
202
|
+
}
|
|
177
203
|
}
|
|
178
204
|
}
|
|
179
|
-
// Add custom mutation hooks
|
|
205
|
+
// Add custom mutation hooks (skip if already exported from table hooks)
|
|
180
206
|
for (const name of customMutationNames) {
|
|
181
207
|
const hookName = getOperationHookName(name, 'mutation');
|
|
182
|
-
|
|
208
|
+
if (!exportedHooks.has(hookName)) {
|
|
209
|
+
statements.push(exportAllFrom(`./${hookName}`));
|
|
210
|
+
exportedHooks.add(hookName);
|
|
211
|
+
}
|
|
183
212
|
}
|
|
184
213
|
// Add file header as leading comment on first statement
|
|
185
214
|
if (statements.length > 0) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
|
-
import { generateCode, addJSDocComment, typedParam } from './babel-ast';
|
|
2
|
+
import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast';
|
|
3
3
|
import { buildCustomMutationString } from './schema-gql-ast';
|
|
4
4
|
import { typeRefToTsType, isTypeRequired, getOperationHookName, getOperationFileName, getOperationVariablesTypeName, getOperationResultTypeName, getDocumentConstName, createTypeTracker, } from './type-resolver';
|
|
5
5
|
import { getGeneratedFileHeader } from './utils';
|
|
@@ -94,13 +94,13 @@ function generateCustomMutationHookInternal(options) {
|
|
|
94
94
|
mutationOptions.push(t.objectProperty(t.identifier('mutationKey'), t.callExpression(t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), [])));
|
|
95
95
|
}
|
|
96
96
|
if (hasArgs) {
|
|
97
|
-
mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)))], t.
|
|
98
|
-
t.identifier(
|
|
99
|
-
t.identifier(
|
|
97
|
+
mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)))], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables')], [
|
|
98
|
+
t.tsTypeReference(t.identifier(resultTypeName)),
|
|
99
|
+
t.tsTypeReference(t.identifier(variablesTypeName)),
|
|
100
100
|
]))));
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
|
-
mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([],
|
|
103
|
+
mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName)], [t.tsTypeReference(t.identifier(resultTypeName))]))));
|
|
104
104
|
}
|
|
105
105
|
mutationOptions.push(t.spreadElement(t.identifier('options')));
|
|
106
106
|
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)])));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
|
-
import { generateCode, addJSDocComment, typedParam } from './babel-ast';
|
|
2
|
+
import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast';
|
|
3
3
|
import { buildCustomQueryString } from './schema-gql-ast';
|
|
4
4
|
import { typeRefToTsType, isTypeRequired, getOperationHookName, getOperationFileName, getOperationVariablesTypeName, getOperationResultTypeName, getDocumentConstName, getQueryKeyName, createTypeTracker, } from './type-resolver';
|
|
5
5
|
import { ucFirst, getGeneratedFileHeader } from './utils';
|
|
@@ -115,9 +115,9 @@ export function generateCustomQueryHook(options) {
|
|
|
115
115
|
const useQueryOptions = [];
|
|
116
116
|
if (hasArgs) {
|
|
117
117
|
useQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
|
|
118
|
-
useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.
|
|
119
|
-
t.identifier(
|
|
120
|
-
t.identifier(
|
|
118
|
+
useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables')], [
|
|
119
|
+
t.tsTypeReference(t.identifier(resultTypeName)),
|
|
120
|
+
t.tsTypeReference(t.identifier(variablesTypeName)),
|
|
121
121
|
]))));
|
|
122
122
|
if (hasRequiredArgs) {
|
|
123
123
|
useQueryOptions.push(t.objectProperty(t.identifier('enabled'), t.logicalExpression('&&', t.unaryExpression('!', t.unaryExpression('!', t.identifier('variables'))), t.binaryExpression('!==', t.optionalMemberExpression(t.identifier('options'), t.identifier('enabled'), false, true), t.booleanLiteral(false)))));
|
|
@@ -125,7 +125,7 @@ export function generateCustomQueryHook(options) {
|
|
|
125
125
|
}
|
|
126
126
|
else {
|
|
127
127
|
useQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
|
|
128
|
-
useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([],
|
|
128
|
+
useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName)], [t.tsTypeReference(t.identifier(resultTypeName))]))));
|
|
129
129
|
}
|
|
130
130
|
useQueryOptions.push(t.spreadElement(t.identifier('options')));
|
|
131
131
|
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [t.objectExpression(useQueryOptions)])));
|
|
@@ -162,18 +162,13 @@ export function generateCustomQueryHook(options) {
|
|
|
162
162
|
const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type));
|
|
163
163
|
const fetchBodyStatements = [];
|
|
164
164
|
if (hasArgs) {
|
|
165
|
-
fetchBodyStatements.push(t.returnStatement(t.
|
|
166
|
-
t.identifier(
|
|
167
|
-
t.identifier(
|
|
168
|
-
t.identifier('options'),
|
|
165
|
+
fetchBodyStatements.push(t.returnStatement(createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], [
|
|
166
|
+
t.tsTypeReference(t.identifier(resultTypeName)),
|
|
167
|
+
t.tsTypeReference(t.identifier(variablesTypeName)),
|
|
169
168
|
])));
|
|
170
169
|
}
|
|
171
170
|
else {
|
|
172
|
-
fetchBodyStatements.push(t.returnStatement(t.
|
|
173
|
-
t.identifier(documentConstName),
|
|
174
|
-
t.identifier('undefined'),
|
|
175
|
-
t.identifier('options'),
|
|
176
|
-
])));
|
|
171
|
+
fetchBodyStatements.push(t.returnStatement(createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], [t.tsTypeReference(t.identifier(resultTypeName))])));
|
|
177
172
|
}
|
|
178
173
|
const fetchParams = [];
|
|
179
174
|
if (hasArgs) {
|
|
@@ -201,19 +196,14 @@ export function generateCustomQueryHook(options) {
|
|
|
201
196
|
const prefetchQueryOptions = [];
|
|
202
197
|
if (hasArgs) {
|
|
203
198
|
prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
|
|
204
|
-
prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.
|
|
205
|
-
t.identifier(
|
|
206
|
-
t.identifier(
|
|
207
|
-
t.identifier('options'),
|
|
199
|
+
prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], [
|
|
200
|
+
t.tsTypeReference(t.identifier(resultTypeName)),
|
|
201
|
+
t.tsTypeReference(t.identifier(variablesTypeName)),
|
|
208
202
|
]))));
|
|
209
203
|
}
|
|
210
204
|
else {
|
|
211
205
|
prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
|
|
212
|
-
prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.
|
|
213
|
-
t.identifier(documentConstName),
|
|
214
|
-
t.identifier('undefined'),
|
|
215
|
-
t.identifier('options'),
|
|
216
|
-
]))));
|
|
206
|
+
prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], [t.tsTypeReference(t.identifier(resultTypeName))]))));
|
|
217
207
|
}
|
|
218
208
|
prefetchBodyStatements.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [t.objectExpression(prefetchQueryOptions)]))));
|
|
219
209
|
const prefetchParams = [
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as t from 'gql-ast';
|
|
8
8
|
import { print } from 'graphql';
|
|
9
|
-
import { getTableNames, getAllRowsQueryName, getSingleRowQueryName, getCreateMutationName, getUpdateMutationName, getDeleteMutationName, getFilterTypeName, getOrderByTypeName, getScalarFields, getPrimaryKeyInfo, ucFirst, } from './utils';
|
|
9
|
+
import { getTableNames, getAllRowsQueryName, getSingleRowQueryName, getCreateMutationName, getUpdateMutationName, getDeleteMutationName, getFilterTypeName, getConditionTypeName, getOrderByTypeName, getScalarFields, getPrimaryKeyInfo, ucFirst, } from './utils';
|
|
10
10
|
// ============================================================================
|
|
11
11
|
// Field selection builders
|
|
12
12
|
// ============================================================================
|
|
@@ -39,22 +39,39 @@ export function buildListQueryAST(config) {
|
|
|
39
39
|
const { table } = config;
|
|
40
40
|
const queryName = getAllRowsQueryName(table);
|
|
41
41
|
const filterType = getFilterTypeName(table);
|
|
42
|
+
const conditionType = getConditionTypeName(table);
|
|
42
43
|
const orderByType = getOrderByTypeName(table);
|
|
43
44
|
const scalarFields = getScalarFields(table);
|
|
44
|
-
// Variable definitions
|
|
45
|
+
// Variable definitions - all pagination arguments from PostGraphile
|
|
45
46
|
const variableDefinitions = [
|
|
46
47
|
t.variableDefinition({
|
|
47
48
|
variable: t.variable({ name: 'first' }),
|
|
48
49
|
type: t.namedType({ type: 'Int' }),
|
|
49
50
|
}),
|
|
51
|
+
t.variableDefinition({
|
|
52
|
+
variable: t.variable({ name: 'last' }),
|
|
53
|
+
type: t.namedType({ type: 'Int' }),
|
|
54
|
+
}),
|
|
50
55
|
t.variableDefinition({
|
|
51
56
|
variable: t.variable({ name: 'offset' }),
|
|
52
57
|
type: t.namedType({ type: 'Int' }),
|
|
53
58
|
}),
|
|
59
|
+
t.variableDefinition({
|
|
60
|
+
variable: t.variable({ name: 'before' }),
|
|
61
|
+
type: t.namedType({ type: 'Cursor' }),
|
|
62
|
+
}),
|
|
63
|
+
t.variableDefinition({
|
|
64
|
+
variable: t.variable({ name: 'after' }),
|
|
65
|
+
type: t.namedType({ type: 'Cursor' }),
|
|
66
|
+
}),
|
|
54
67
|
t.variableDefinition({
|
|
55
68
|
variable: t.variable({ name: 'filter' }),
|
|
56
69
|
type: t.namedType({ type: filterType }),
|
|
57
70
|
}),
|
|
71
|
+
t.variableDefinition({
|
|
72
|
+
variable: t.variable({ name: 'condition' }),
|
|
73
|
+
type: t.namedType({ type: conditionType }),
|
|
74
|
+
}),
|
|
58
75
|
t.variableDefinition({
|
|
59
76
|
variable: t.variable({ name: 'orderBy' }),
|
|
60
77
|
type: t.listType({
|
|
@@ -65,8 +82,12 @@ export function buildListQueryAST(config) {
|
|
|
65
82
|
// Query arguments
|
|
66
83
|
const args = [
|
|
67
84
|
t.argument({ name: 'first', value: t.variable({ name: 'first' }) }),
|
|
85
|
+
t.argument({ name: 'last', value: t.variable({ name: 'last' }) }),
|
|
68
86
|
t.argument({ name: 'offset', value: t.variable({ name: 'offset' }) }),
|
|
87
|
+
t.argument({ name: 'before', value: t.variable({ name: 'before' }) }),
|
|
88
|
+
t.argument({ name: 'after', value: t.variable({ name: 'after' }) }),
|
|
69
89
|
t.argument({ name: 'filter', value: t.variable({ name: 'filter' }) }),
|
|
90
|
+
t.argument({ name: 'condition', value: t.variable({ name: 'condition' }) }),
|
|
70
91
|
t.argument({ name: 'orderBy', value: t.variable({ name: 'orderBy' }) }),
|
|
71
92
|
];
|
|
72
93
|
// Field selections
|