@constructive-io/graphql-codegen 2.19.0 → 2.20.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 +1818 -113
- package/__tests__/codegen/input-types-generator.test.d.ts +1 -0
- package/__tests__/codegen/input-types-generator.test.js +635 -0
- package/cli/codegen/barrel.d.ts +27 -0
- package/cli/codegen/barrel.js +163 -0
- package/cli/codegen/client.d.ts +4 -0
- package/cli/codegen/client.js +170 -0
- package/cli/codegen/custom-mutations.d.ts +38 -0
- package/cli/codegen/custom-mutations.js +149 -0
- package/cli/codegen/custom-queries.d.ts +38 -0
- package/cli/codegen/custom-queries.js +358 -0
- package/cli/codegen/filters.d.ts +27 -0
- package/cli/codegen/filters.js +357 -0
- package/cli/codegen/gql-ast.d.ts +41 -0
- package/cli/codegen/gql-ast.js +329 -0
- package/cli/codegen/index.d.ts +71 -0
- package/cli/codegen/index.js +147 -0
- package/cli/codegen/mutations.d.ts +30 -0
- package/cli/codegen/mutations.js +410 -0
- package/cli/codegen/orm/barrel.d.ts +18 -0
- package/cli/codegen/orm/barrel.js +48 -0
- package/cli/codegen/orm/client-generator.d.ts +45 -0
- package/cli/codegen/orm/client-generator.js +646 -0
- package/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
- package/cli/codegen/orm/custom-ops-generator.js +350 -0
- package/cli/codegen/orm/index.d.ts +38 -0
- package/cli/codegen/orm/index.js +88 -0
- package/cli/codegen/orm/input-types-generator.d.ts +21 -0
- package/cli/codegen/orm/input-types-generator.js +705 -0
- package/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
- package/cli/codegen/orm/input-types-generator.test.js +75 -0
- package/cli/codegen/orm/model-generator.d.ts +32 -0
- package/cli/codegen/orm/model-generator.js +264 -0
- package/cli/codegen/orm/query-builder.d.ts +161 -0
- package/cli/codegen/orm/query-builder.js +366 -0
- package/cli/codegen/orm/select-types.d.ts +169 -0
- package/cli/codegen/orm/select-types.js +16 -0
- package/cli/codegen/orm/select-types.test.d.ts +11 -0
- package/cli/codegen/orm/select-types.test.js +22 -0
- package/cli/codegen/queries.d.ts +25 -0
- package/cli/codegen/queries.js +438 -0
- package/cli/codegen/scalars.d.ts +12 -0
- package/cli/codegen/scalars.js +71 -0
- package/cli/codegen/schema-gql-ast.d.ts +51 -0
- package/cli/codegen/schema-gql-ast.js +385 -0
- package/cli/codegen/ts-ast.d.ts +122 -0
- package/cli/codegen/ts-ast.js +280 -0
- package/cli/codegen/type-resolver.d.ts +96 -0
- package/cli/codegen/type-resolver.js +246 -0
- package/cli/codegen/types.d.ts +12 -0
- package/cli/codegen/types.js +69 -0
- package/cli/codegen/utils.d.ts +163 -0
- package/cli/codegen/utils.js +326 -0
- package/cli/commands/generate-orm.d.ts +37 -0
- package/cli/commands/generate-orm.js +195 -0
- package/cli/commands/generate.d.ts +39 -0
- package/cli/commands/generate.js +299 -0
- package/cli/commands/index.d.ts +7 -0
- package/cli/commands/index.js +12 -0
- package/cli/commands/init.d.ts +35 -0
- package/cli/commands/init.js +176 -0
- package/cli/index.d.ts +4 -0
- package/cli/index.js +291 -0
- package/cli/introspect/fetch-meta.d.ts +31 -0
- package/cli/introspect/fetch-meta.js +108 -0
- package/cli/introspect/fetch-schema.d.ts +21 -0
- package/cli/introspect/fetch-schema.js +86 -0
- package/cli/introspect/index.d.ts +8 -0
- package/cli/introspect/index.js +16 -0
- package/cli/introspect/meta-query.d.ts +111 -0
- package/cli/introspect/meta-query.js +191 -0
- package/cli/introspect/schema-query.d.ts +20 -0
- package/cli/introspect/schema-query.js +123 -0
- package/cli/introspect/transform-schema.d.ts +74 -0
- package/cli/introspect/transform-schema.js +269 -0
- package/cli/introspect/transform-schema.test.d.ts +1 -0
- package/cli/introspect/transform-schema.test.js +67 -0
- package/cli/introspect/transform.d.ts +21 -0
- package/cli/introspect/transform.js +216 -0
- package/cli/watch/cache.d.ts +45 -0
- package/cli/watch/cache.js +111 -0
- package/cli/watch/debounce.d.ts +19 -0
- package/cli/watch/debounce.js +89 -0
- package/cli/watch/hash.d.ts +17 -0
- package/cli/watch/hash.js +48 -0
- package/cli/watch/index.d.ts +10 -0
- package/cli/watch/index.js +22 -0
- package/cli/watch/orchestrator.d.ts +63 -0
- package/cli/watch/orchestrator.js +228 -0
- package/cli/watch/poller.d.ts +65 -0
- package/cli/watch/poller.js +203 -0
- package/cli/watch/types.d.ts +67 -0
- package/cli/watch/types.js +5 -0
- package/client/error.d.ts +95 -0
- package/client/error.js +255 -0
- package/client/execute.d.ts +57 -0
- package/client/execute.js +124 -0
- package/client/index.d.ts +6 -0
- package/client/index.js +18 -0
- package/client/typed-document.d.ts +31 -0
- package/client/typed-document.js +44 -0
- package/core/ast.d.ts +10 -0
- package/core/ast.js +593 -0
- package/core/custom-ast.d.ts +35 -0
- package/core/custom-ast.js +204 -0
- package/core/index.d.ts +8 -0
- package/core/index.js +33 -0
- package/core/meta-object/convert.d.ts +65 -0
- package/core/meta-object/convert.js +63 -0
- package/core/meta-object/format.json +93 -0
- package/core/meta-object/index.d.ts +2 -0
- package/core/meta-object/index.js +18 -0
- package/core/meta-object/validate.d.ts +9 -0
- package/core/meta-object/validate.js +34 -0
- package/core/query-builder.d.ts +46 -0
- package/core/query-builder.js +412 -0
- package/core/types.d.ts +139 -0
- package/core/types.js +28 -0
- package/esm/__tests__/codegen/input-types-generator.test.d.ts +1 -0
- package/esm/__tests__/codegen/input-types-generator.test.js +633 -0
- package/esm/cli/codegen/barrel.d.ts +27 -0
- package/esm/cli/codegen/barrel.js +156 -0
- package/esm/cli/codegen/client.d.ts +4 -0
- package/esm/cli/codegen/client.js +167 -0
- package/esm/cli/codegen/custom-mutations.d.ts +38 -0
- package/esm/cli/codegen/custom-mutations.js +145 -0
- package/esm/cli/codegen/custom-queries.d.ts +38 -0
- package/esm/cli/codegen/custom-queries.js +354 -0
- package/esm/cli/codegen/filters.d.ts +27 -0
- package/esm/cli/codegen/filters.js +351 -0
- package/esm/cli/codegen/gql-ast.d.ts +41 -0
- package/esm/cli/codegen/gql-ast.js +288 -0
- package/esm/cli/codegen/index.d.ts +71 -0
- package/esm/cli/codegen/index.js +124 -0
- package/esm/cli/codegen/mutations.d.ts +30 -0
- package/esm/cli/codegen/mutations.js +404 -0
- package/esm/cli/codegen/orm/barrel.d.ts +18 -0
- package/esm/cli/codegen/orm/barrel.js +44 -0
- package/esm/cli/codegen/orm/client-generator.d.ts +45 -0
- package/esm/cli/codegen/orm/client-generator.js +640 -0
- package/esm/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
- package/esm/cli/codegen/orm/custom-ops-generator.js +346 -0
- package/esm/cli/codegen/orm/index.d.ts +38 -0
- package/esm/cli/codegen/orm/index.js +75 -0
- package/esm/cli/codegen/orm/input-types-generator.d.ts +21 -0
- package/esm/cli/codegen/orm/input-types-generator.js +700 -0
- package/esm/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
- package/esm/cli/codegen/orm/input-types-generator.test.js +73 -0
- package/esm/cli/codegen/orm/model-generator.d.ts +32 -0
- package/esm/cli/codegen/orm/model-generator.js +260 -0
- package/esm/cli/codegen/orm/query-builder.d.ts +161 -0
- package/esm/cli/codegen/orm/query-builder.js +353 -0
- package/esm/cli/codegen/orm/select-types.d.ts +169 -0
- package/esm/cli/codegen/orm/select-types.js +15 -0
- package/esm/cli/codegen/orm/select-types.test.d.ts +11 -0
- package/esm/cli/codegen/orm/select-types.test.js +21 -0
- package/esm/cli/codegen/queries.d.ts +25 -0
- package/esm/cli/codegen/queries.js +433 -0
- package/esm/cli/codegen/scalars.d.ts +12 -0
- package/esm/cli/codegen/scalars.js +66 -0
- package/esm/cli/codegen/schema-gql-ast.d.ts +51 -0
- package/esm/cli/codegen/schema-gql-ast.js +343 -0
- package/esm/cli/codegen/ts-ast.d.ts +122 -0
- package/esm/cli/codegen/ts-ast.js +260 -0
- package/esm/cli/codegen/type-resolver.d.ts +96 -0
- package/esm/cli/codegen/type-resolver.js +224 -0
- package/esm/cli/codegen/types.d.ts +12 -0
- package/esm/cli/codegen/types.js +65 -0
- package/esm/cli/codegen/utils.d.ts +163 -0
- package/esm/cli/codegen/utils.js +288 -0
- package/esm/cli/commands/generate-orm.d.ts +37 -0
- package/esm/cli/commands/generate-orm.js +192 -0
- package/esm/cli/commands/generate.d.ts +39 -0
- package/esm/cli/commands/generate.js +262 -0
- package/esm/cli/commands/index.d.ts +7 -0
- package/esm/cli/commands/index.js +5 -0
- package/esm/cli/commands/init.d.ts +35 -0
- package/esm/cli/commands/init.js +138 -0
- package/esm/cli/index.d.ts +4 -0
- package/esm/cli/index.js +256 -0
- package/esm/cli/introspect/fetch-meta.d.ts +31 -0
- package/esm/cli/introspect/fetch-meta.js +104 -0
- package/esm/cli/introspect/fetch-schema.d.ts +21 -0
- package/esm/cli/introspect/fetch-schema.js +83 -0
- package/esm/cli/introspect/index.d.ts +8 -0
- package/esm/cli/introspect/index.js +6 -0
- package/esm/cli/introspect/meta-query.d.ts +111 -0
- package/esm/cli/introspect/meta-query.js +188 -0
- package/esm/cli/introspect/schema-query.d.ts +20 -0
- package/esm/cli/introspect/schema-query.js +120 -0
- package/esm/cli/introspect/transform-schema.d.ts +74 -0
- package/esm/cli/introspect/transform-schema.js +259 -0
- package/esm/cli/introspect/transform-schema.test.d.ts +1 -0
- package/esm/cli/introspect/transform-schema.test.js +65 -0
- package/esm/cli/introspect/transform.d.ts +21 -0
- package/esm/cli/introspect/transform.js +210 -0
- package/esm/cli/watch/cache.d.ts +45 -0
- package/esm/cli/watch/cache.js +73 -0
- package/esm/cli/watch/debounce.d.ts +19 -0
- package/esm/cli/watch/debounce.js +85 -0
- package/esm/cli/watch/hash.d.ts +17 -0
- package/esm/cli/watch/hash.js +43 -0
- package/esm/cli/watch/index.d.ts +10 -0
- package/esm/cli/watch/index.js +8 -0
- package/esm/cli/watch/orchestrator.d.ts +63 -0
- package/esm/cli/watch/orchestrator.js +223 -0
- package/esm/cli/watch/poller.d.ts +65 -0
- package/esm/cli/watch/poller.js +198 -0
- package/esm/cli/watch/types.d.ts +67 -0
- package/esm/cli/watch/types.js +4 -0
- package/esm/client/error.d.ts +95 -0
- package/esm/client/error.js +249 -0
- package/esm/client/execute.d.ts +57 -0
- package/esm/client/execute.js +120 -0
- package/esm/client/index.d.ts +6 -0
- package/esm/client/index.js +6 -0
- package/esm/client/typed-document.d.ts +31 -0
- package/esm/client/typed-document.js +40 -0
- package/esm/core/ast.d.ts +10 -0
- package/esm/core/ast.js +549 -0
- package/esm/core/custom-ast.d.ts +35 -0
- package/esm/core/custom-ast.js +161 -0
- package/esm/core/index.d.ts +8 -0
- package/esm/core/index.js +12 -0
- package/esm/core/meta-object/convert.d.ts +65 -0
- package/esm/core/meta-object/convert.js +60 -0
- package/esm/core/meta-object/format.json +93 -0
- package/esm/core/meta-object/index.d.ts +2 -0
- package/esm/core/meta-object/index.js +2 -0
- package/esm/core/meta-object/validate.d.ts +9 -0
- package/esm/core/meta-object/validate.js +28 -0
- package/esm/core/query-builder.d.ts +46 -0
- package/esm/core/query-builder.js +375 -0
- package/esm/core/types.d.ts +139 -0
- package/esm/core/types.js +24 -0
- package/esm/generators/field-selector.d.ts +30 -0
- package/esm/generators/field-selector.js +355 -0
- package/esm/generators/index.d.ts +6 -0
- package/esm/generators/index.js +9 -0
- package/esm/generators/mutations.d.ts +31 -0
- package/esm/generators/mutations.js +197 -0
- package/esm/generators/select.d.ts +50 -0
- package/esm/generators/select.js +636 -0
- package/esm/index.d.ts +12 -0
- package/esm/index.js +17 -3
- package/esm/react/index.d.ts +5 -0
- package/esm/react/index.js +6 -0
- package/esm/types/config.d.ts +199 -0
- package/esm/types/config.js +106 -0
- package/esm/types/index.d.ts +9 -0
- package/esm/types/index.js +4 -0
- package/esm/types/introspection.d.ts +121 -0
- package/esm/types/introspection.js +54 -0
- package/esm/types/mutation.d.ts +45 -0
- package/esm/types/mutation.js +4 -0
- package/esm/types/query.d.ts +82 -0
- package/esm/types/query.js +4 -0
- package/esm/types/schema.d.ts +253 -0
- package/esm/types/schema.js +5 -0
- package/esm/types/selection.d.ts +43 -0
- package/esm/types/selection.js +4 -0
- package/esm/utils/index.d.ts +4 -0
- package/esm/utils/index.js +4 -0
- package/generators/field-selector.d.ts +30 -0
- package/generators/field-selector.js +361 -0
- package/generators/index.d.ts +6 -0
- package/generators/index.js +27 -0
- package/generators/mutations.d.ts +31 -0
- package/generators/mutations.js +235 -0
- package/generators/select.d.ts +50 -0
- package/generators/select.js +679 -0
- package/index.d.ts +12 -3
- package/index.js +19 -3
- package/package.json +59 -38
- package/react/index.d.ts +5 -0
- package/react/index.js +9 -0
- package/types/config.d.ts +199 -0
- package/types/config.js +111 -0
- package/types/index.d.ts +9 -0
- package/types/index.js +10 -0
- package/types/introspection.d.ts +121 -0
- package/types/introspection.js +62 -0
- package/types/mutation.d.ts +45 -0
- package/types/mutation.js +5 -0
- package/types/query.d.ts +82 -0
- package/types/query.js +5 -0
- package/types/schema.d.ts +253 -0
- package/types/schema.js +6 -0
- package/types/selection.d.ts +43 -0
- package/types/selection.js +5 -0
- package/utils/index.d.ts +4 -0
- package/utils/index.js +7 -0
- package/codegen.d.ts +0 -13
- package/codegen.js +0 -293
- package/esm/codegen.js +0 -253
- package/esm/gql.js +0 -939
- package/esm/options.js +0 -27
- package/gql.d.ts +0 -188
- package/gql.js +0 -992
- package/options.d.ts +0 -45
- package/options.js +0 -31
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import { createProject, createSourceFile, getFormattedOutput, createFileHeader, createImport, createInterface, createConst, createTypeAlias, createUnionType, createFilterInterface, } from './ts-ast';
|
|
2
|
+
import { buildListQueryAST, buildSingleQueryAST, printGraphQL, } from './gql-ast';
|
|
3
|
+
import { getTableNames, getListQueryHookName, getSingleQueryHookName, getListQueryFileName, getSingleQueryFileName, getAllRowsQueryName, getSingleRowQueryName, getFilterTypeName, getOrderByTypeName, getScalarFields, getScalarFilterType, toScreamingSnake, ucFirst, } from './utils';
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// List query hook generator
|
|
6
|
+
// ============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Generate list query hook file content using AST
|
|
9
|
+
*/
|
|
10
|
+
export function generateListQueryHook(table) {
|
|
11
|
+
const project = createProject();
|
|
12
|
+
const { typeName, pluralName } = getTableNames(table);
|
|
13
|
+
const hookName = getListQueryHookName(table);
|
|
14
|
+
const queryName = getAllRowsQueryName(table);
|
|
15
|
+
const filterTypeName = getFilterTypeName(table);
|
|
16
|
+
const orderByTypeName = getOrderByTypeName(table);
|
|
17
|
+
const scalarFields = getScalarFields(table);
|
|
18
|
+
// Generate GraphQL document via AST
|
|
19
|
+
const queryAST = buildListQueryAST({ table });
|
|
20
|
+
const queryDocument = printGraphQL(queryAST);
|
|
21
|
+
const sourceFile = createSourceFile(project, getListQueryFileName(table));
|
|
22
|
+
// Add file header as leading comment
|
|
23
|
+
sourceFile.insertText(0, createFileHeader(`List query hook for ${typeName}`) + '\n\n');
|
|
24
|
+
// Collect all filter types used by this table's fields
|
|
25
|
+
const filterTypesUsed = new Set();
|
|
26
|
+
for (const field of scalarFields) {
|
|
27
|
+
const filterType = getScalarFilterType(field.type.gqlType);
|
|
28
|
+
if (filterType) {
|
|
29
|
+
filterTypesUsed.add(filterType);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Add imports
|
|
33
|
+
sourceFile.addImportDeclarations([
|
|
34
|
+
createImport({
|
|
35
|
+
moduleSpecifier: '@tanstack/react-query',
|
|
36
|
+
namedImports: ['useQuery'],
|
|
37
|
+
typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
|
|
38
|
+
}),
|
|
39
|
+
createImport({
|
|
40
|
+
moduleSpecifier: '../client',
|
|
41
|
+
namedImports: ['execute'],
|
|
42
|
+
typeOnlyNamedImports: ['ExecuteOptions'],
|
|
43
|
+
}),
|
|
44
|
+
createImport({
|
|
45
|
+
moduleSpecifier: '../types',
|
|
46
|
+
typeOnlyNamedImports: [typeName, ...Array.from(filterTypesUsed)],
|
|
47
|
+
}),
|
|
48
|
+
]);
|
|
49
|
+
// Re-export entity type
|
|
50
|
+
sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
|
|
51
|
+
// Add section comment
|
|
52
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
53
|
+
sourceFile.addStatements('// GraphQL Document');
|
|
54
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
55
|
+
// Add query document constant
|
|
56
|
+
sourceFile.addVariableStatement(createConst(`${queryName}QueryDocument`, '`\n' + queryDocument + '`'));
|
|
57
|
+
// Add section comment
|
|
58
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
59
|
+
sourceFile.addStatements('// Types');
|
|
60
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
61
|
+
// Generate filter interface
|
|
62
|
+
const fieldFilters = scalarFields
|
|
63
|
+
.map((field) => {
|
|
64
|
+
const filterType = getScalarFilterType(field.type.gqlType);
|
|
65
|
+
return filterType ? { fieldName: field.name, filterType } : null;
|
|
66
|
+
})
|
|
67
|
+
.filter((f) => f !== null);
|
|
68
|
+
sourceFile.addInterface(createFilterInterface(filterTypeName, fieldFilters));
|
|
69
|
+
// Generate OrderBy type
|
|
70
|
+
const orderByValues = [
|
|
71
|
+
...scalarFields.flatMap((f) => [
|
|
72
|
+
`${toScreamingSnake(f.name)}_ASC`,
|
|
73
|
+
`${toScreamingSnake(f.name)}_DESC`,
|
|
74
|
+
]),
|
|
75
|
+
'NATURAL',
|
|
76
|
+
'PRIMARY_KEY_ASC',
|
|
77
|
+
'PRIMARY_KEY_DESC',
|
|
78
|
+
];
|
|
79
|
+
sourceFile.addTypeAlias(createTypeAlias(orderByTypeName, createUnionType(orderByValues)));
|
|
80
|
+
// Variables interface
|
|
81
|
+
const variablesProps = [
|
|
82
|
+
{ name: 'first', type: 'number', optional: true },
|
|
83
|
+
{ name: 'offset', type: 'number', optional: true },
|
|
84
|
+
{ name: 'filter', type: filterTypeName, optional: true },
|
|
85
|
+
{ name: 'orderBy', type: `${orderByTypeName}[]`, optional: true },
|
|
86
|
+
];
|
|
87
|
+
sourceFile.addInterface(createInterface(`${ucFirst(pluralName)}QueryVariables`, variablesProps));
|
|
88
|
+
// Result interface
|
|
89
|
+
const resultProps = [
|
|
90
|
+
{
|
|
91
|
+
name: queryName,
|
|
92
|
+
type: `{
|
|
93
|
+
totalCount: number;
|
|
94
|
+
nodes: ${typeName}[];
|
|
95
|
+
pageInfo: {
|
|
96
|
+
hasNextPage: boolean;
|
|
97
|
+
hasPreviousPage: boolean;
|
|
98
|
+
startCursor: string | null;
|
|
99
|
+
endCursor: string | null;
|
|
100
|
+
};
|
|
101
|
+
}`,
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
sourceFile.addInterface(createInterface(`${ucFirst(pluralName)}QueryResult`, resultProps));
|
|
105
|
+
// Add section comment
|
|
106
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
107
|
+
sourceFile.addStatements('// Query Key');
|
|
108
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
109
|
+
// Query key factory
|
|
110
|
+
sourceFile.addVariableStatement(createConst(`${queryName}QueryKey`, `(variables?: ${ucFirst(pluralName)}QueryVariables) =>
|
|
111
|
+
['${typeName.toLowerCase()}', 'list', variables] as const`));
|
|
112
|
+
// Add section comment
|
|
113
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
114
|
+
sourceFile.addStatements('// Hook');
|
|
115
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
116
|
+
// Hook function
|
|
117
|
+
sourceFile.addFunction({
|
|
118
|
+
name: hookName,
|
|
119
|
+
isExported: true,
|
|
120
|
+
parameters: [
|
|
121
|
+
{
|
|
122
|
+
name: 'variables',
|
|
123
|
+
type: `${ucFirst(pluralName)}QueryVariables`,
|
|
124
|
+
hasQuestionToken: true,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: 'options',
|
|
128
|
+
type: `Omit<UseQueryOptions<${ucFirst(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
|
|
129
|
+
hasQuestionToken: true,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
statements: `return useQuery({
|
|
133
|
+
queryKey: ${queryName}QueryKey(variables),
|
|
134
|
+
queryFn: () => execute<${ucFirst(pluralName)}QueryResult, ${ucFirst(pluralName)}QueryVariables>(
|
|
135
|
+
${queryName}QueryDocument,
|
|
136
|
+
variables
|
|
137
|
+
),
|
|
138
|
+
...options,
|
|
139
|
+
});`,
|
|
140
|
+
docs: [
|
|
141
|
+
{
|
|
142
|
+
description: `Query hook for fetching ${typeName} list
|
|
143
|
+
|
|
144
|
+
@example
|
|
145
|
+
\`\`\`tsx
|
|
146
|
+
const { data, isLoading } = ${hookName}({
|
|
147
|
+
first: 10,
|
|
148
|
+
filter: { name: { equalTo: "example" } },
|
|
149
|
+
orderBy: ['CREATED_AT_DESC'],
|
|
150
|
+
});
|
|
151
|
+
\`\`\``,
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
});
|
|
155
|
+
// Add section comment for standalone functions
|
|
156
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
157
|
+
sourceFile.addStatements('// Standalone Functions (non-React)');
|
|
158
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
159
|
+
// Fetch function (standalone, no React)
|
|
160
|
+
sourceFile.addFunction({
|
|
161
|
+
name: `fetch${ucFirst(pluralName)}Query`,
|
|
162
|
+
isExported: true,
|
|
163
|
+
isAsync: true,
|
|
164
|
+
parameters: [
|
|
165
|
+
{
|
|
166
|
+
name: 'variables',
|
|
167
|
+
type: `${ucFirst(pluralName)}QueryVariables`,
|
|
168
|
+
hasQuestionToken: true,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'options',
|
|
172
|
+
type: 'ExecuteOptions',
|
|
173
|
+
hasQuestionToken: true,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
returnType: `Promise<${ucFirst(pluralName)}QueryResult>`,
|
|
177
|
+
statements: `return execute<${ucFirst(pluralName)}QueryResult, ${ucFirst(pluralName)}QueryVariables>(
|
|
178
|
+
${queryName}QueryDocument,
|
|
179
|
+
variables,
|
|
180
|
+
options
|
|
181
|
+
);`,
|
|
182
|
+
docs: [
|
|
183
|
+
{
|
|
184
|
+
description: `Fetch ${typeName} list without React hooks
|
|
185
|
+
|
|
186
|
+
@example
|
|
187
|
+
\`\`\`ts
|
|
188
|
+
// Direct fetch
|
|
189
|
+
const data = await fetch${ucFirst(pluralName)}Query({ first: 10 });
|
|
190
|
+
|
|
191
|
+
// With QueryClient
|
|
192
|
+
const data = await queryClient.fetchQuery({
|
|
193
|
+
queryKey: ${queryName}QueryKey(variables),
|
|
194
|
+
queryFn: () => fetch${ucFirst(pluralName)}Query(variables),
|
|
195
|
+
});
|
|
196
|
+
\`\`\``,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
});
|
|
200
|
+
// Prefetch function (for SSR/QueryClient)
|
|
201
|
+
sourceFile.addFunction({
|
|
202
|
+
name: `prefetch${ucFirst(pluralName)}Query`,
|
|
203
|
+
isExported: true,
|
|
204
|
+
isAsync: true,
|
|
205
|
+
parameters: [
|
|
206
|
+
{
|
|
207
|
+
name: 'queryClient',
|
|
208
|
+
type: 'QueryClient',
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
name: 'variables',
|
|
212
|
+
type: `${ucFirst(pluralName)}QueryVariables`,
|
|
213
|
+
hasQuestionToken: true,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'options',
|
|
217
|
+
type: 'ExecuteOptions',
|
|
218
|
+
hasQuestionToken: true,
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
returnType: 'Promise<void>',
|
|
222
|
+
statements: `await queryClient.prefetchQuery({
|
|
223
|
+
queryKey: ${queryName}QueryKey(variables),
|
|
224
|
+
queryFn: () => execute<${ucFirst(pluralName)}QueryResult, ${ucFirst(pluralName)}QueryVariables>(
|
|
225
|
+
${queryName}QueryDocument,
|
|
226
|
+
variables,
|
|
227
|
+
options
|
|
228
|
+
),
|
|
229
|
+
});`,
|
|
230
|
+
docs: [
|
|
231
|
+
{
|
|
232
|
+
description: `Prefetch ${typeName} list for SSR or cache warming
|
|
233
|
+
|
|
234
|
+
@example
|
|
235
|
+
\`\`\`ts
|
|
236
|
+
await prefetch${ucFirst(pluralName)}Query(queryClient, { first: 10 });
|
|
237
|
+
\`\`\``,
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
return {
|
|
242
|
+
fileName: getListQueryFileName(table),
|
|
243
|
+
content: getFormattedOutput(sourceFile),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
// ============================================================================
|
|
247
|
+
// Single item query hook generator
|
|
248
|
+
// ============================================================================
|
|
249
|
+
/**
|
|
250
|
+
* Generate single item query hook file content using AST
|
|
251
|
+
*/
|
|
252
|
+
export function generateSingleQueryHook(table) {
|
|
253
|
+
const project = createProject();
|
|
254
|
+
const { typeName, singularName } = getTableNames(table);
|
|
255
|
+
const hookName = getSingleQueryHookName(table);
|
|
256
|
+
const queryName = getSingleRowQueryName(table);
|
|
257
|
+
// Generate GraphQL document via AST
|
|
258
|
+
const queryAST = buildSingleQueryAST({ table });
|
|
259
|
+
const queryDocument = printGraphQL(queryAST);
|
|
260
|
+
const sourceFile = createSourceFile(project, getSingleQueryFileName(table));
|
|
261
|
+
// Add file header
|
|
262
|
+
sourceFile.insertText(0, createFileHeader(`Single item query hook for ${typeName}`) + '\n\n');
|
|
263
|
+
// Add imports
|
|
264
|
+
sourceFile.addImportDeclarations([
|
|
265
|
+
createImport({
|
|
266
|
+
moduleSpecifier: '@tanstack/react-query',
|
|
267
|
+
namedImports: ['useQuery'],
|
|
268
|
+
typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
|
|
269
|
+
}),
|
|
270
|
+
createImport({
|
|
271
|
+
moduleSpecifier: '../client',
|
|
272
|
+
namedImports: ['execute'],
|
|
273
|
+
typeOnlyNamedImports: ['ExecuteOptions'],
|
|
274
|
+
}),
|
|
275
|
+
createImport({
|
|
276
|
+
moduleSpecifier: '../types',
|
|
277
|
+
typeOnlyNamedImports: [typeName],
|
|
278
|
+
}),
|
|
279
|
+
]);
|
|
280
|
+
// Re-export entity type
|
|
281
|
+
sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
|
|
282
|
+
// Add section comment
|
|
283
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
284
|
+
sourceFile.addStatements('// GraphQL Document');
|
|
285
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
286
|
+
// Add query document constant
|
|
287
|
+
sourceFile.addVariableStatement(createConst(`${queryName}QueryDocument`, '`\n' + queryDocument + '`'));
|
|
288
|
+
// Add section comment
|
|
289
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
290
|
+
sourceFile.addStatements('// Types');
|
|
291
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
292
|
+
// Variables interface
|
|
293
|
+
sourceFile.addInterface(createInterface(`${ucFirst(singularName)}QueryVariables`, [
|
|
294
|
+
{ name: 'id', type: 'string' },
|
|
295
|
+
]));
|
|
296
|
+
// Result interface
|
|
297
|
+
sourceFile.addInterface(createInterface(`${ucFirst(singularName)}QueryResult`, [
|
|
298
|
+
{ name: queryName, type: `${typeName} | null` },
|
|
299
|
+
]));
|
|
300
|
+
// Add section comment
|
|
301
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
302
|
+
sourceFile.addStatements('// Query Key');
|
|
303
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
304
|
+
// Query key factory
|
|
305
|
+
sourceFile.addVariableStatement(createConst(`${queryName}QueryKey`, `(id: string) =>
|
|
306
|
+
['${typeName.toLowerCase()}', 'detail', id] as const`));
|
|
307
|
+
// Add section comment
|
|
308
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
309
|
+
sourceFile.addStatements('// Hook');
|
|
310
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
311
|
+
// Hook function
|
|
312
|
+
sourceFile.addFunction({
|
|
313
|
+
name: hookName,
|
|
314
|
+
isExported: true,
|
|
315
|
+
parameters: [
|
|
316
|
+
{ name: 'id', type: 'string' },
|
|
317
|
+
{
|
|
318
|
+
name: 'options',
|
|
319
|
+
type: `Omit<UseQueryOptions<${ucFirst(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
|
|
320
|
+
hasQuestionToken: true,
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
statements: `return useQuery({
|
|
324
|
+
queryKey: ${queryName}QueryKey(id),
|
|
325
|
+
queryFn: () => execute<${ucFirst(singularName)}QueryResult, ${ucFirst(singularName)}QueryVariables>(
|
|
326
|
+
${queryName}QueryDocument,
|
|
327
|
+
{ id }
|
|
328
|
+
),
|
|
329
|
+
enabled: !!id && (options?.enabled !== false),
|
|
330
|
+
...options,
|
|
331
|
+
});`,
|
|
332
|
+
docs: [
|
|
333
|
+
{
|
|
334
|
+
description: `Query hook for fetching a single ${typeName} by ID
|
|
335
|
+
|
|
336
|
+
@example
|
|
337
|
+
\`\`\`tsx
|
|
338
|
+
const { data, isLoading } = ${hookName}('uuid-here');
|
|
339
|
+
|
|
340
|
+
if (data?.${queryName}) {
|
|
341
|
+
console.log(data.${queryName}.id);
|
|
342
|
+
}
|
|
343
|
+
\`\`\``,
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
});
|
|
347
|
+
// Add section comment for standalone functions
|
|
348
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
349
|
+
sourceFile.addStatements('// Standalone Functions (non-React)');
|
|
350
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
351
|
+
// Fetch function (standalone, no React)
|
|
352
|
+
sourceFile.addFunction({
|
|
353
|
+
name: `fetch${ucFirst(singularName)}Query`,
|
|
354
|
+
isExported: true,
|
|
355
|
+
isAsync: true,
|
|
356
|
+
parameters: [
|
|
357
|
+
{ name: 'id', type: 'string' },
|
|
358
|
+
{
|
|
359
|
+
name: 'options',
|
|
360
|
+
type: 'ExecuteOptions',
|
|
361
|
+
hasQuestionToken: true,
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
returnType: `Promise<${ucFirst(singularName)}QueryResult>`,
|
|
365
|
+
statements: `return execute<${ucFirst(singularName)}QueryResult, ${ucFirst(singularName)}QueryVariables>(
|
|
366
|
+
${queryName}QueryDocument,
|
|
367
|
+
{ id },
|
|
368
|
+
options
|
|
369
|
+
);`,
|
|
370
|
+
docs: [
|
|
371
|
+
{
|
|
372
|
+
description: `Fetch a single ${typeName} by ID without React hooks
|
|
373
|
+
|
|
374
|
+
@example
|
|
375
|
+
\`\`\`ts
|
|
376
|
+
const data = await fetch${ucFirst(singularName)}Query('uuid-here');
|
|
377
|
+
\`\`\``,
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
});
|
|
381
|
+
// Prefetch function (for SSR/QueryClient)
|
|
382
|
+
sourceFile.addFunction({
|
|
383
|
+
name: `prefetch${ucFirst(singularName)}Query`,
|
|
384
|
+
isExported: true,
|
|
385
|
+
isAsync: true,
|
|
386
|
+
parameters: [
|
|
387
|
+
{ name: 'queryClient', type: 'QueryClient' },
|
|
388
|
+
{ name: 'id', type: 'string' },
|
|
389
|
+
{
|
|
390
|
+
name: 'options',
|
|
391
|
+
type: 'ExecuteOptions',
|
|
392
|
+
hasQuestionToken: true,
|
|
393
|
+
},
|
|
394
|
+
],
|
|
395
|
+
returnType: 'Promise<void>',
|
|
396
|
+
statements: `await queryClient.prefetchQuery({
|
|
397
|
+
queryKey: ${queryName}QueryKey(id),
|
|
398
|
+
queryFn: () => execute<${ucFirst(singularName)}QueryResult, ${ucFirst(singularName)}QueryVariables>(
|
|
399
|
+
${queryName}QueryDocument,
|
|
400
|
+
{ id },
|
|
401
|
+
options
|
|
402
|
+
),
|
|
403
|
+
});`,
|
|
404
|
+
docs: [
|
|
405
|
+
{
|
|
406
|
+
description: `Prefetch a single ${typeName} for SSR or cache warming
|
|
407
|
+
|
|
408
|
+
@example
|
|
409
|
+
\`\`\`ts
|
|
410
|
+
await prefetch${ucFirst(singularName)}Query(queryClient, 'uuid-here');
|
|
411
|
+
\`\`\``,
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
});
|
|
415
|
+
return {
|
|
416
|
+
fileName: getSingleQueryFileName(table),
|
|
417
|
+
content: getFormattedOutput(sourceFile),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
// ============================================================================
|
|
421
|
+
// Batch generator
|
|
422
|
+
// ============================================================================
|
|
423
|
+
/**
|
|
424
|
+
* Generate all query hook files for all tables
|
|
425
|
+
*/
|
|
426
|
+
export function generateAllQueryHooks(tables) {
|
|
427
|
+
const files = [];
|
|
428
|
+
for (const table of tables) {
|
|
429
|
+
files.push(generateListQueryHook(table));
|
|
430
|
+
files.push(generateSingleQueryHook(table));
|
|
431
|
+
}
|
|
432
|
+
return files;
|
|
433
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared scalar mappings for code generation
|
|
3
|
+
*/
|
|
4
|
+
export declare const SCALAR_TS_MAP: Record<string, string>;
|
|
5
|
+
export declare const SCALAR_FILTER_MAP: Record<string, string>;
|
|
6
|
+
export declare const SCALAR_NAMES: Set<string>;
|
|
7
|
+
export interface ScalarToTsOptions {
|
|
8
|
+
unknownScalar?: 'unknown' | 'name';
|
|
9
|
+
overrides?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare function scalarToTsType(scalarName: string, options?: ScalarToTsOptions): string;
|
|
12
|
+
export declare function scalarToFilterType(scalarName: string): string | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared scalar mappings for code generation
|
|
3
|
+
*/
|
|
4
|
+
export const SCALAR_TS_MAP = {
|
|
5
|
+
// Standard GraphQL scalars
|
|
6
|
+
String: 'string',
|
|
7
|
+
Int: 'number',
|
|
8
|
+
Float: 'number',
|
|
9
|
+
Boolean: 'boolean',
|
|
10
|
+
ID: 'string',
|
|
11
|
+
// PostGraphile scalars
|
|
12
|
+
UUID: 'string',
|
|
13
|
+
Cursor: 'string',
|
|
14
|
+
Datetime: 'string',
|
|
15
|
+
Date: 'string',
|
|
16
|
+
Time: 'string',
|
|
17
|
+
JSON: 'unknown',
|
|
18
|
+
BigInt: 'string',
|
|
19
|
+
BigFloat: 'string',
|
|
20
|
+
// Geometry types
|
|
21
|
+
GeoJSON: 'unknown',
|
|
22
|
+
Geometry: 'unknown',
|
|
23
|
+
Point: 'unknown',
|
|
24
|
+
// Interval
|
|
25
|
+
Interval: 'string',
|
|
26
|
+
// PostgreSQL-specific types
|
|
27
|
+
BitString: 'string',
|
|
28
|
+
FullText: 'string',
|
|
29
|
+
InternetAddress: 'string',
|
|
30
|
+
Inet: 'string',
|
|
31
|
+
Cidr: 'string',
|
|
32
|
+
MacAddr: 'string',
|
|
33
|
+
TsVector: 'string',
|
|
34
|
+
TsQuery: 'string',
|
|
35
|
+
};
|
|
36
|
+
export const SCALAR_FILTER_MAP = {
|
|
37
|
+
String: 'StringFilter',
|
|
38
|
+
Int: 'IntFilter',
|
|
39
|
+
Float: 'FloatFilter',
|
|
40
|
+
Boolean: 'BooleanFilter',
|
|
41
|
+
UUID: 'UUIDFilter',
|
|
42
|
+
ID: 'UUIDFilter',
|
|
43
|
+
Datetime: 'DatetimeFilter',
|
|
44
|
+
Date: 'DateFilter',
|
|
45
|
+
Time: 'StringFilter',
|
|
46
|
+
JSON: 'JSONFilter',
|
|
47
|
+
BigInt: 'BigIntFilter',
|
|
48
|
+
BigFloat: 'BigFloatFilter',
|
|
49
|
+
BitString: 'BitStringFilter',
|
|
50
|
+
InternetAddress: 'InternetAddressFilter',
|
|
51
|
+
FullText: 'FullTextFilter',
|
|
52
|
+
Interval: 'StringFilter',
|
|
53
|
+
};
|
|
54
|
+
export const SCALAR_NAMES = new Set(Object.keys(SCALAR_TS_MAP));
|
|
55
|
+
export function scalarToTsType(scalarName, options = {}) {
|
|
56
|
+
const override = options.overrides?.[scalarName];
|
|
57
|
+
if (override)
|
|
58
|
+
return override;
|
|
59
|
+
const mapped = SCALAR_TS_MAP[scalarName];
|
|
60
|
+
if (mapped)
|
|
61
|
+
return mapped;
|
|
62
|
+
return options.unknownScalar === 'unknown' ? 'unknown' : scalarName;
|
|
63
|
+
}
|
|
64
|
+
export function scalarToFilterType(scalarName) {
|
|
65
|
+
return SCALAR_FILTER_MAP[scalarName] ?? null;
|
|
66
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { DocumentNode, FieldNode, VariableDefinitionNode } from 'graphql';
|
|
2
|
+
import type { CleanOperation, CleanArgument, CleanTypeRef, TypeRegistry } from '../../types/schema';
|
|
3
|
+
export interface FieldSelectionConfig {
|
|
4
|
+
/** Max depth for nested object selections */
|
|
5
|
+
maxDepth: number;
|
|
6
|
+
/** Skip the 'query' field in payloads */
|
|
7
|
+
skipQueryField: boolean;
|
|
8
|
+
/** Type registry for resolving nested types */
|
|
9
|
+
typeRegistry?: TypeRegistry;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Build variable definitions from operation arguments
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildVariableDefinitions(args: CleanArgument[]): VariableDefinitionNode[];
|
|
15
|
+
/**
|
|
16
|
+
* Build field selections for an object type
|
|
17
|
+
* Recursively handles nested objects up to maxDepth
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildFieldSelections(typeRef: CleanTypeRef, config: FieldSelectionConfig, currentDepth?: number): FieldNode[];
|
|
20
|
+
export interface CustomQueryConfig {
|
|
21
|
+
operation: CleanOperation;
|
|
22
|
+
typeRegistry?: TypeRegistry;
|
|
23
|
+
maxDepth?: number;
|
|
24
|
+
skipQueryField?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a custom query AST from a CleanOperation
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildCustomQueryAST(config: CustomQueryConfig): DocumentNode;
|
|
30
|
+
export interface CustomMutationConfig {
|
|
31
|
+
operation: CleanOperation;
|
|
32
|
+
typeRegistry?: TypeRegistry;
|
|
33
|
+
maxDepth?: number;
|
|
34
|
+
skipQueryField?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build a custom mutation AST from a CleanOperation
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildCustomMutationAST(config: CustomMutationConfig): DocumentNode;
|
|
40
|
+
/**
|
|
41
|
+
* Print a document AST to GraphQL string
|
|
42
|
+
*/
|
|
43
|
+
export declare function printGraphQL(ast: DocumentNode): string;
|
|
44
|
+
/**
|
|
45
|
+
* Build and print a custom query in one call
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildCustomQueryString(config: CustomQueryConfig): string;
|
|
48
|
+
/**
|
|
49
|
+
* Build and print a custom mutation in one call
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildCustomMutationString(config: CustomMutationConfig): string;
|