@constructive-io/graphql-codegen 2.23.3 → 2.24.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 +147 -2
- package/cli/codegen/babel-ast.d.ts +46 -0
- package/cli/codegen/babel-ast.js +145 -0
- package/cli/codegen/barrel.d.ts +7 -2
- package/cli/codegen/barrel.js +159 -97
- package/cli/codegen/client.js +61 -0
- package/cli/codegen/custom-mutations.d.ts +2 -12
- package/cli/codegen/custom-mutations.js +116 -124
- package/cli/codegen/custom-queries.d.ts +2 -10
- package/cli/codegen/custom-queries.js +246 -335
- package/cli/codegen/index.d.ts +3 -0
- package/cli/codegen/index.js +72 -3
- package/cli/codegen/invalidation.d.ts +20 -0
- package/cli/codegen/invalidation.js +327 -0
- package/cli/codegen/mutation-keys.d.ts +24 -0
- package/cli/codegen/mutation-keys.js +247 -0
- package/cli/codegen/mutations.d.ts +3 -19
- package/cli/codegen/mutations.js +372 -383
- package/cli/codegen/orm/barrel.d.ts +1 -1
- package/cli/codegen/orm/barrel.js +42 -10
- package/cli/codegen/orm/client-generator.d.ts +1 -19
- package/cli/codegen/orm/client-generator.js +108 -77
- package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
- package/cli/codegen/orm/custom-ops-generator.js +192 -235
- package/cli/codegen/orm/input-types-generator.d.ts +13 -1
- package/cli/codegen/orm/input-types-generator.js +403 -147
- package/cli/codegen/orm/model-generator.d.ts +1 -19
- package/cli/codegen/orm/model-generator.js +229 -234
- package/cli/codegen/queries.d.ts +3 -11
- package/cli/codegen/queries.js +582 -389
- package/cli/codegen/query-keys.d.ts +15 -0
- package/cli/codegen/query-keys.js +477 -0
- package/cli/codegen/scalars.js +1 -0
- package/cli/codegen/schema-types-generator.d.ts +15 -10
- package/cli/codegen/schema-types-generator.js +87 -175
- package/cli/codegen/type-resolver.d.ts +1 -30
- package/cli/codegen/type-resolver.js +0 -53
- package/cli/codegen/types.d.ts +1 -1
- package/cli/codegen/types.js +76 -21
- package/esm/cli/codegen/babel-ast.d.ts +46 -0
- package/esm/cli/codegen/babel-ast.js +97 -0
- package/esm/cli/codegen/barrel.d.ts +7 -2
- package/esm/cli/codegen/barrel.js +126 -97
- package/esm/cli/codegen/client.js +61 -0
- package/esm/cli/codegen/custom-mutations.d.ts +2 -12
- package/esm/cli/codegen/custom-mutations.js +83 -124
- package/esm/cli/codegen/custom-queries.d.ts +2 -10
- package/esm/cli/codegen/custom-queries.js +214 -336
- package/esm/cli/codegen/index.d.ts +3 -0
- package/esm/cli/codegen/index.js +68 -2
- package/esm/cli/codegen/invalidation.d.ts +20 -0
- package/esm/cli/codegen/invalidation.js +291 -0
- package/esm/cli/codegen/mutation-keys.d.ts +24 -0
- package/esm/cli/codegen/mutation-keys.js +211 -0
- package/esm/cli/codegen/mutations.d.ts +3 -19
- package/esm/cli/codegen/mutations.js +340 -384
- package/esm/cli/codegen/orm/barrel.d.ts +1 -1
- package/esm/cli/codegen/orm/barrel.js +10 -11
- package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
- package/esm/cli/codegen/orm/client-generator.js +76 -78
- package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
- package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
- package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
- package/esm/cli/codegen/orm/input-types-generator.js +371 -148
- package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
- package/esm/cli/codegen/orm/model-generator.js +197 -235
- package/esm/cli/codegen/queries.d.ts +3 -11
- package/esm/cli/codegen/queries.js +550 -390
- package/esm/cli/codegen/query-keys.d.ts +15 -0
- package/esm/cli/codegen/query-keys.js +441 -0
- package/esm/cli/codegen/scalars.js +1 -0
- package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
- package/esm/cli/codegen/schema-types-generator.js +54 -175
- package/esm/cli/codegen/type-resolver.d.ts +1 -30
- package/esm/cli/codegen/type-resolver.js +0 -49
- package/esm/cli/codegen/types.d.ts +1 -1
- package/esm/cli/codegen/types.js +44 -22
- package/esm/types/config.d.ts +75 -0
- package/esm/types/config.js +18 -0
- package/package.json +6 -4
- package/types/config.d.ts +75 -0
- package/types/config.js +19 -1
- package/cli/codegen/ts-ast.d.ts +0 -124
- package/cli/codegen/ts-ast.js +0 -280
- package/esm/cli/codegen/ts-ast.d.ts +0 -124
- package/esm/cli/codegen/ts-ast.js +0 -260
package/cli/codegen/queries.js
CHANGED
|
@@ -1,36 +1,84 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.generateListQueryHook = generateListQueryHook;
|
|
4
37
|
exports.generateSingleQueryHook = generateSingleQueryHook;
|
|
5
38
|
exports.generateAllQueryHooks = generateAllQueryHooks;
|
|
6
|
-
const
|
|
39
|
+
const t = __importStar(require("@babel/types"));
|
|
40
|
+
const babel_ast_1 = require("./babel-ast");
|
|
7
41
|
const gql_ast_1 = require("./gql-ast");
|
|
8
42
|
const utils_1 = require("./utils");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
43
|
+
function createUnionType(values) {
|
|
44
|
+
return t.tsUnionType(values.map((v) => t.tsLiteralType(t.stringLiteral(v))));
|
|
45
|
+
}
|
|
46
|
+
function createFilterInterfaceDeclaration(name, fieldFilters, isExported = true) {
|
|
47
|
+
const properties = [];
|
|
48
|
+
for (const filter of fieldFilters) {
|
|
49
|
+
const prop = t.tsPropertySignature(t.identifier(filter.fieldName), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filter.filterType))));
|
|
50
|
+
prop.optional = true;
|
|
51
|
+
properties.push(prop);
|
|
52
|
+
}
|
|
53
|
+
const andProp = t.tsPropertySignature(t.identifier('and'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(name)))));
|
|
54
|
+
andProp.optional = true;
|
|
55
|
+
properties.push(andProp);
|
|
56
|
+
const orProp = t.tsPropertySignature(t.identifier('or'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(name)))));
|
|
57
|
+
orProp.optional = true;
|
|
58
|
+
properties.push(orProp);
|
|
59
|
+
const notProp = t.tsPropertySignature(t.identifier('not'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(name))));
|
|
60
|
+
notProp.optional = true;
|
|
61
|
+
properties.push(notProp);
|
|
62
|
+
const body = t.tsInterfaceBody(properties);
|
|
63
|
+
const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(name), null, null, body);
|
|
64
|
+
if (isExported) {
|
|
65
|
+
return t.exportNamedDeclaration(interfaceDecl);
|
|
66
|
+
}
|
|
67
|
+
return interfaceDecl;
|
|
68
|
+
}
|
|
15
69
|
function generateListQueryHook(table, options = {}) {
|
|
16
|
-
const { reactQueryEnabled = true } = options;
|
|
17
|
-
const project = (0, ts_ast_1.createProject)();
|
|
70
|
+
const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, } = options;
|
|
18
71
|
const { typeName, pluralName } = (0, utils_1.getTableNames)(table);
|
|
19
72
|
const hookName = (0, utils_1.getListQueryHookName)(table);
|
|
20
73
|
const queryName = (0, utils_1.getAllRowsQueryName)(table);
|
|
21
74
|
const filterTypeName = (0, utils_1.getFilterTypeName)(table);
|
|
22
75
|
const orderByTypeName = (0, utils_1.getOrderByTypeName)(table);
|
|
23
76
|
const scalarFields = (0, utils_1.getScalarFields)(table);
|
|
24
|
-
|
|
77
|
+
const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
|
|
78
|
+
const scopeTypeName = `${typeName}Scope`;
|
|
25
79
|
const queryAST = (0, gql_ast_1.buildListQueryAST)({ table });
|
|
26
80
|
const queryDocument = (0, gql_ast_1.printGraphQL)(queryAST);
|
|
27
|
-
const
|
|
28
|
-
// Add file header as leading comment
|
|
29
|
-
const headerText = reactQueryEnabled
|
|
30
|
-
? `List query hook for ${typeName}`
|
|
31
|
-
: `List query functions for ${typeName}`;
|
|
32
|
-
sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
|
|
33
|
-
// Collect all filter types used by this table's fields
|
|
81
|
+
const statements = [];
|
|
34
82
|
const filterTypesUsed = new Set();
|
|
35
83
|
for (const field of scalarFields) {
|
|
36
84
|
const filterType = (0, utils_1.getScalarFilterType)(field.type.gqlType, field.type.isArray);
|
|
@@ -38,47 +86,56 @@ function generateListQueryHook(table, options = {}) {
|
|
|
38
86
|
filterTypesUsed.add(filterType);
|
|
39
87
|
}
|
|
40
88
|
}
|
|
41
|
-
// Add imports - conditionally include React Query imports
|
|
42
|
-
const imports = [];
|
|
43
89
|
if (reactQueryEnabled) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
90
|
+
const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], t.stringLiteral('@tanstack/react-query'));
|
|
91
|
+
statements.push(reactQueryImport);
|
|
92
|
+
const reactQueryTypeImport = t.importDeclaration([
|
|
93
|
+
t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')),
|
|
94
|
+
t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')),
|
|
95
|
+
], t.stringLiteral('@tanstack/react-query'));
|
|
96
|
+
reactQueryTypeImport.importKind = 'type';
|
|
97
|
+
statements.push(reactQueryTypeImport);
|
|
49
98
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
99
|
+
const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
|
|
100
|
+
statements.push(clientImport);
|
|
101
|
+
const clientTypeImport = t.importDeclaration([
|
|
102
|
+
t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions')),
|
|
103
|
+
], t.stringLiteral('../client'));
|
|
104
|
+
clientTypeImport.importKind = 'type';
|
|
105
|
+
statements.push(clientTypeImport);
|
|
106
|
+
const typesImport = t.importDeclaration([
|
|
107
|
+
t.importSpecifier(t.identifier(typeName), t.identifier(typeName)),
|
|
108
|
+
...Array.from(filterTypesUsed).map((ft) => t.importSpecifier(t.identifier(ft), t.identifier(ft))),
|
|
109
|
+
], t.stringLiteral('../types'));
|
|
110
|
+
typesImport.importKind = 'type';
|
|
111
|
+
statements.push(typesImport);
|
|
112
|
+
if (useCentralizedKeys) {
|
|
113
|
+
const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
|
|
114
|
+
statements.push(queryKeyImport);
|
|
115
|
+
if (hasRelationships) {
|
|
116
|
+
const scopeTypeImport = t.importDeclaration([
|
|
117
|
+
t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName)),
|
|
118
|
+
], t.stringLiteral('../query-keys'));
|
|
119
|
+
scopeTypeImport.importKind = 'type';
|
|
120
|
+
statements.push(scopeTypeImport);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const reExportDecl = t.exportNamedDeclaration(null, [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
|
|
124
|
+
reExportDecl.exportKind = 'type';
|
|
125
|
+
statements.push(reExportDecl);
|
|
126
|
+
const queryDocConst = t.variableDeclaration('const', [
|
|
127
|
+
t.variableDeclarator(t.identifier(`${queryName}QueryDocument`), t.templateLiteral([
|
|
128
|
+
t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true),
|
|
129
|
+
], [])),
|
|
130
|
+
]);
|
|
131
|
+
statements.push(t.exportNamedDeclaration(queryDocConst));
|
|
72
132
|
const fieldFilters = scalarFields
|
|
73
133
|
.map((field) => {
|
|
74
134
|
const filterType = (0, utils_1.getScalarFilterType)(field.type.gqlType, field.type.isArray);
|
|
75
135
|
return filterType ? { fieldName: field.name, filterType } : null;
|
|
76
136
|
})
|
|
77
137
|
.filter((f) => f !== null);
|
|
78
|
-
|
|
79
|
-
sourceFile.addInterface((0, ts_ast_1.createFilterInterface)(filterTypeName, fieldFilters, { isExported: false }));
|
|
80
|
-
// Generate OrderBy type
|
|
81
|
-
// Note: Not exported to avoid conflicts with schema-types
|
|
138
|
+
statements.push(createFilterInterfaceDeclaration(filterTypeName, fieldFilters, false));
|
|
82
139
|
const orderByValues = [
|
|
83
140
|
...scalarFields.flatMap((f) => [
|
|
84
141
|
`${(0, utils_1.toScreamingSnake)(f.name)}_ASC`,
|
|
@@ -88,373 +145,509 @@ function generateListQueryHook(table, options = {}) {
|
|
|
88
145
|
'PRIMARY_KEY_ASC',
|
|
89
146
|
'PRIMARY_KEY_DESC',
|
|
90
147
|
];
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
148
|
+
const orderByTypeAlias = t.tsTypeAliasDeclaration(t.identifier(orderByTypeName), null, createUnionType(orderByValues));
|
|
149
|
+
statements.push(orderByTypeAlias);
|
|
150
|
+
const variablesInterfaceBody = t.tsInterfaceBody([
|
|
151
|
+
(() => {
|
|
152
|
+
const p = t.tsPropertySignature(t.identifier('first'), t.tsTypeAnnotation(t.tsNumberKeyword()));
|
|
153
|
+
p.optional = true;
|
|
154
|
+
return p;
|
|
155
|
+
})(),
|
|
156
|
+
(() => {
|
|
157
|
+
const p = t.tsPropertySignature(t.identifier('offset'), t.tsTypeAnnotation(t.tsNumberKeyword()));
|
|
158
|
+
p.optional = true;
|
|
159
|
+
return p;
|
|
160
|
+
})(),
|
|
161
|
+
(() => {
|
|
162
|
+
const p = t.tsPropertySignature(t.identifier('filter'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterTypeName))));
|
|
163
|
+
p.optional = true;
|
|
164
|
+
return p;
|
|
165
|
+
})(),
|
|
166
|
+
(() => {
|
|
167
|
+
const p = t.tsPropertySignature(t.identifier('orderBy'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(orderByTypeName)))));
|
|
168
|
+
p.optional = true;
|
|
169
|
+
return p;
|
|
170
|
+
})(),
|
|
171
|
+
]);
|
|
172
|
+
const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`), null, null, variablesInterfaceBody);
|
|
173
|
+
statements.push(t.exportNamedDeclaration(variablesInterface));
|
|
174
|
+
const pageInfoType = t.tsTypeLiteral([
|
|
175
|
+
t.tsPropertySignature(t.identifier('hasNextPage'), t.tsTypeAnnotation(t.tsBooleanKeyword())),
|
|
176
|
+
t.tsPropertySignature(t.identifier('hasPreviousPage'), t.tsTypeAnnotation(t.tsBooleanKeyword())),
|
|
177
|
+
t.tsPropertySignature(t.identifier('startCursor'), t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()]))),
|
|
178
|
+
t.tsPropertySignature(t.identifier('endCursor'), t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()]))),
|
|
179
|
+
]);
|
|
180
|
+
const resultType = t.tsTypeLiteral([
|
|
181
|
+
t.tsPropertySignature(t.identifier('totalCount'), t.tsTypeAnnotation(t.tsNumberKeyword())),
|
|
182
|
+
t.tsPropertySignature(t.identifier('nodes'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(typeName))))),
|
|
183
|
+
t.tsPropertySignature(t.identifier('pageInfo'), t.tsTypeAnnotation(pageInfoType)),
|
|
184
|
+
]);
|
|
185
|
+
const resultInterfaceBody = t.tsInterfaceBody([
|
|
186
|
+
t.tsPropertySignature(t.identifier(queryName), t.tsTypeAnnotation(resultType)),
|
|
187
|
+
]);
|
|
188
|
+
const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`), null, null, resultInterfaceBody);
|
|
189
|
+
statements.push(t.exportNamedDeclaration(resultInterface));
|
|
190
|
+
if (useCentralizedKeys) {
|
|
191
|
+
const queryKeyConst = t.variableDeclaration('const', [
|
|
192
|
+
t.variableDeclarator(t.identifier(`${queryName}QueryKey`), t.memberExpression(t.identifier(keysName), t.identifier('list'))),
|
|
193
|
+
]);
|
|
194
|
+
const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
|
|
195
|
+
(0, babel_ast_1.addJSDocComment)(queryKeyExport, [
|
|
196
|
+
'Query key factory - re-exported from query-keys.ts',
|
|
197
|
+
]);
|
|
198
|
+
statements.push(queryKeyExport);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
const queryKeyArrow = t.arrowFunctionExpression([
|
|
202
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
|
|
203
|
+
], t.tsAsExpression(t.arrayExpression([
|
|
204
|
+
t.stringLiteral(typeName.toLowerCase()),
|
|
205
|
+
t.stringLiteral('list'),
|
|
206
|
+
t.identifier('variables'),
|
|
207
|
+
]), t.tsTypeReference(t.identifier('const'))));
|
|
208
|
+
const queryKeyConst = t.variableDeclaration('const', [
|
|
209
|
+
t.variableDeclarator(t.identifier(`${queryName}QueryKey`), queryKeyArrow),
|
|
210
|
+
]);
|
|
211
|
+
statements.push(t.exportNamedDeclaration(queryKeyConst));
|
|
212
|
+
}
|
|
125
213
|
if (reactQueryEnabled) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
214
|
+
const hookBodyStatements = [];
|
|
215
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
216
|
+
hookBodyStatements.push(t.variableDeclaration('const', [
|
|
217
|
+
t.variableDeclarator(t.objectPattern([
|
|
218
|
+
t.objectProperty(t.identifier('scope'), t.identifier('scope'), false, true),
|
|
219
|
+
t.restElement(t.identifier('queryOptions')),
|
|
220
|
+
]), t.logicalExpression('??', t.identifier('options'), t.objectExpression([]))),
|
|
221
|
+
]));
|
|
222
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
|
|
223
|
+
t.objectExpression([
|
|
224
|
+
t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables'), t.identifier('scope')])),
|
|
225
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
226
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
227
|
+
t.identifier('variables'),
|
|
228
|
+
]))),
|
|
229
|
+
t.spreadElement(t.identifier('queryOptions')),
|
|
230
|
+
]),
|
|
231
|
+
])));
|
|
232
|
+
}
|
|
233
|
+
else if (useCentralizedKeys) {
|
|
234
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
|
|
235
|
+
t.objectExpression([
|
|
236
|
+
t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables')])),
|
|
237
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
238
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
239
|
+
t.identifier('variables'),
|
|
240
|
+
]))),
|
|
241
|
+
t.spreadElement(t.identifier('options')),
|
|
242
|
+
]),
|
|
243
|
+
])));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
|
|
247
|
+
t.objectExpression([
|
|
248
|
+
t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(`${queryName}QueryKey`), [
|
|
249
|
+
t.identifier('variables'),
|
|
250
|
+
])),
|
|
251
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
252
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
253
|
+
t.identifier('variables'),
|
|
254
|
+
]))),
|
|
255
|
+
t.spreadElement(t.identifier('options')),
|
|
256
|
+
]),
|
|
257
|
+
])));
|
|
258
|
+
}
|
|
259
|
+
const hookParams = [
|
|
260
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
|
|
261
|
+
];
|
|
262
|
+
let optionsTypeStr;
|
|
263
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
264
|
+
optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`;
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`;
|
|
268
|
+
}
|
|
269
|
+
const optionsParam = t.identifier('options');
|
|
270
|
+
optionsParam.optional = true;
|
|
271
|
+
optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
|
|
272
|
+
hookParams.push(optionsParam);
|
|
273
|
+
const hookFunc = t.functionDeclaration(t.identifier(hookName), hookParams, t.blockStatement(hookBodyStatements));
|
|
274
|
+
const hookExport = t.exportNamedDeclaration(hookFunc);
|
|
275
|
+
const docLines = [
|
|
276
|
+
`Query hook for fetching ${typeName} list`,
|
|
277
|
+
'',
|
|
278
|
+
'@example',
|
|
279
|
+
'```tsx',
|
|
280
|
+
`const { data, isLoading } = ${hookName}({`,
|
|
281
|
+
' first: 10,',
|
|
282
|
+
' filter: { name: { equalTo: "example" } },',
|
|
283
|
+
" orderBy: ['CREATED_AT_DESC'],",
|
|
284
|
+
'});',
|
|
285
|
+
'```',
|
|
286
|
+
];
|
|
287
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
288
|
+
docLines.push('');
|
|
289
|
+
docLines.push('@example With scope for hierarchical cache invalidation');
|
|
290
|
+
docLines.push('```tsx');
|
|
291
|
+
docLines.push(`const { data } = ${hookName}(`);
|
|
292
|
+
docLines.push(' { first: 10 },');
|
|
293
|
+
docLines.push(" { scope: { parentId: 'parent-id' } }");
|
|
294
|
+
docLines.push(');');
|
|
295
|
+
docLines.push('```');
|
|
296
|
+
}
|
|
297
|
+
(0, babel_ast_1.addJSDocComment)(hookExport, docLines);
|
|
298
|
+
statements.push(hookExport);
|
|
168
299
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
\`\`\`ts
|
|
202
|
-
// Direct fetch
|
|
203
|
-
const data = await fetch${(0, utils_1.ucFirst)(pluralName)}Query({ first: 10 });
|
|
204
|
-
|
|
205
|
-
// With QueryClient
|
|
206
|
-
const data = await queryClient.fetchQuery({
|
|
207
|
-
queryKey: ${queryName}QueryKey(variables),
|
|
208
|
-
queryFn: () => fetch${(0, utils_1.ucFirst)(pluralName)}Query(variables),
|
|
209
|
-
});
|
|
210
|
-
\`\`\``,
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
});
|
|
214
|
-
// Prefetch function (for SSR/QueryClient) - only if React Query is enabled
|
|
300
|
+
const fetchFuncBody = t.blockStatement([
|
|
301
|
+
t.returnStatement(t.callExpression(t.identifier('execute'), [
|
|
302
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
303
|
+
t.identifier('variables'),
|
|
304
|
+
t.identifier('options'),
|
|
305
|
+
])),
|
|
306
|
+
]);
|
|
307
|
+
const fetchFunc = t.functionDeclaration(t.identifier(`fetch${(0, utils_1.ucFirst)(pluralName)}Query`), [
|
|
308
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
|
|
309
|
+
(0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true),
|
|
310
|
+
], fetchFuncBody);
|
|
311
|
+
fetchFunc.async = true;
|
|
312
|
+
fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([
|
|
313
|
+
t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
|
|
314
|
+
])));
|
|
315
|
+
const fetchExport = t.exportNamedDeclaration(fetchFunc);
|
|
316
|
+
(0, babel_ast_1.addJSDocComment)(fetchExport, [
|
|
317
|
+
`Fetch ${typeName} list without React hooks`,
|
|
318
|
+
'',
|
|
319
|
+
'@example',
|
|
320
|
+
'```ts',
|
|
321
|
+
'// Direct fetch',
|
|
322
|
+
`const data = await fetch${(0, utils_1.ucFirst)(pluralName)}Query({ first: 10 });`,
|
|
323
|
+
'',
|
|
324
|
+
'// With QueryClient',
|
|
325
|
+
'const data = await queryClient.fetchQuery({',
|
|
326
|
+
` queryKey: ${queryName}QueryKey(variables),`,
|
|
327
|
+
` queryFn: () => fetch${(0, utils_1.ucFirst)(pluralName)}Query(variables),`,
|
|
328
|
+
'});',
|
|
329
|
+
'```',
|
|
330
|
+
]);
|
|
331
|
+
statements.push(fetchExport);
|
|
215
332
|
if (reactQueryEnabled) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
333
|
+
const prefetchParams = [
|
|
334
|
+
(0, babel_ast_1.typedParam)('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
|
|
335
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
|
|
336
|
+
];
|
|
337
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
338
|
+
prefetchParams.push((0, babel_ast_1.typedParam)('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true));
|
|
339
|
+
}
|
|
340
|
+
prefetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
|
|
341
|
+
let prefetchQueryKeyExpr;
|
|
342
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
343
|
+
prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables'), t.identifier('scope')]);
|
|
344
|
+
}
|
|
345
|
+
else if (useCentralizedKeys) {
|
|
346
|
+
prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables')]);
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
prefetchQueryKeyExpr = t.callExpression(t.identifier(`${queryName}QueryKey`), [t.identifier('variables')]);
|
|
350
|
+
}
|
|
351
|
+
const prefetchFuncBody = t.blockStatement([
|
|
352
|
+
t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
|
|
353
|
+
t.objectExpression([
|
|
354
|
+
t.objectProperty(t.identifier('queryKey'), prefetchQueryKeyExpr),
|
|
355
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
356
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
357
|
+
t.identifier('variables'),
|
|
358
|
+
t.identifier('options'),
|
|
359
|
+
]))),
|
|
360
|
+
]),
|
|
361
|
+
]))),
|
|
362
|
+
]);
|
|
363
|
+
const prefetchFunc = t.functionDeclaration(t.identifier(`prefetch${(0, utils_1.ucFirst)(pluralName)}Query`), prefetchParams, prefetchFuncBody);
|
|
364
|
+
prefetchFunc.async = true;
|
|
365
|
+
prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
|
|
366
|
+
const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
|
|
367
|
+
(0, babel_ast_1.addJSDocComment)(prefetchExport, [
|
|
368
|
+
`Prefetch ${typeName} list for SSR or cache warming`,
|
|
369
|
+
'',
|
|
370
|
+
'@example',
|
|
371
|
+
'```ts',
|
|
372
|
+
`await prefetch${(0, utils_1.ucFirst)(pluralName)}Query(queryClient, { first: 10 });`,
|
|
373
|
+
'```',
|
|
374
|
+
]);
|
|
375
|
+
statements.push(prefetchExport);
|
|
256
376
|
}
|
|
377
|
+
const code = (0, babel_ast_1.generateCode)(statements);
|
|
378
|
+
const headerText = reactQueryEnabled
|
|
379
|
+
? `List query hook for ${typeName}`
|
|
380
|
+
: `List query functions for ${typeName}`;
|
|
381
|
+
const content = (0, utils_1.getGeneratedFileHeader)(headerText) + '\n\n' + code;
|
|
257
382
|
return {
|
|
258
383
|
fileName: (0, utils_1.getListQueryFileName)(table),
|
|
259
|
-
content
|
|
384
|
+
content,
|
|
260
385
|
};
|
|
261
386
|
}
|
|
262
|
-
// ============================================================================
|
|
263
|
-
// Single item query hook generator
|
|
264
|
-
// ============================================================================
|
|
265
|
-
/**
|
|
266
|
-
* Generate single item query hook file content using AST
|
|
267
|
-
*/
|
|
268
387
|
function generateSingleQueryHook(table, options = {}) {
|
|
269
|
-
const { reactQueryEnabled = true } = options;
|
|
270
|
-
const project = (0, ts_ast_1.createProject)();
|
|
388
|
+
const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, } = options;
|
|
271
389
|
const { typeName, singularName } = (0, utils_1.getTableNames)(table);
|
|
272
390
|
const hookName = (0, utils_1.getSingleQueryHookName)(table);
|
|
273
391
|
const queryName = (0, utils_1.getSingleRowQueryName)(table);
|
|
274
|
-
|
|
392
|
+
const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
|
|
393
|
+
const scopeTypeName = `${typeName}Scope`;
|
|
275
394
|
const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
|
|
276
|
-
// For simplicity, use first PK field (most common case)
|
|
277
|
-
// Composite PKs would need more complex handling
|
|
278
395
|
const pkField = pkFields[0];
|
|
279
396
|
const pkName = pkField.name;
|
|
280
397
|
const pkTsType = pkField.tsType;
|
|
281
|
-
// Generate GraphQL document via AST
|
|
282
398
|
const queryAST = (0, gql_ast_1.buildSingleQueryAST)({ table });
|
|
283
399
|
const queryDocument = (0, gql_ast_1.printGraphQL)(queryAST);
|
|
284
|
-
const
|
|
285
|
-
// Add file header
|
|
286
|
-
const headerText = reactQueryEnabled
|
|
287
|
-
? `Single item query hook for ${typeName}`
|
|
288
|
-
: `Single item query functions for ${typeName}`;
|
|
289
|
-
sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
|
|
290
|
-
// Add imports - conditionally include React Query imports
|
|
291
|
-
const imports = [];
|
|
400
|
+
const statements = [];
|
|
292
401
|
if (reactQueryEnabled) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
402
|
+
const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], t.stringLiteral('@tanstack/react-query'));
|
|
403
|
+
statements.push(reactQueryImport);
|
|
404
|
+
const reactQueryTypeImport = t.importDeclaration([
|
|
405
|
+
t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')),
|
|
406
|
+
t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')),
|
|
407
|
+
], t.stringLiteral('@tanstack/react-query'));
|
|
408
|
+
reactQueryTypeImport.importKind = 'type';
|
|
409
|
+
statements.push(reactQueryTypeImport);
|
|
410
|
+
}
|
|
411
|
+
const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
|
|
412
|
+
statements.push(clientImport);
|
|
413
|
+
const clientTypeImport = t.importDeclaration([
|
|
414
|
+
t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions')),
|
|
415
|
+
], t.stringLiteral('../client'));
|
|
416
|
+
clientTypeImport.importKind = 'type';
|
|
417
|
+
statements.push(clientTypeImport);
|
|
418
|
+
const typesImport = t.importDeclaration([t.importSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
|
|
419
|
+
typesImport.importKind = 'type';
|
|
420
|
+
statements.push(typesImport);
|
|
421
|
+
if (useCentralizedKeys) {
|
|
422
|
+
const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
|
|
423
|
+
statements.push(queryKeyImport);
|
|
424
|
+
if (hasRelationships) {
|
|
425
|
+
const scopeTypeImport = t.importDeclaration([
|
|
426
|
+
t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName)),
|
|
427
|
+
], t.stringLiteral('../query-keys'));
|
|
428
|
+
scopeTypeImport.importKind = 'type';
|
|
429
|
+
statements.push(scopeTypeImport);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const reExportDecl = t.exportNamedDeclaration(null, [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
|
|
433
|
+
reExportDecl.exportKind = 'type';
|
|
434
|
+
statements.push(reExportDecl);
|
|
435
|
+
const queryDocConst = t.variableDeclaration('const', [
|
|
436
|
+
t.variableDeclarator(t.identifier(`${queryName}QueryDocument`), t.templateLiteral([
|
|
437
|
+
t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true),
|
|
438
|
+
], [])),
|
|
439
|
+
]);
|
|
440
|
+
statements.push(t.exportNamedDeclaration(queryDocConst));
|
|
441
|
+
const pkTypeAnnotation = pkTsType === 'string'
|
|
442
|
+
? t.tsStringKeyword()
|
|
443
|
+
: pkTsType === 'number'
|
|
444
|
+
? t.tsNumberKeyword()
|
|
445
|
+
: t.tsTypeReference(t.identifier(pkTsType));
|
|
446
|
+
const variablesInterfaceBody = t.tsInterfaceBody([
|
|
447
|
+
t.tsPropertySignature(t.identifier(pkName), t.tsTypeAnnotation(pkTypeAnnotation)),
|
|
448
|
+
]);
|
|
449
|
+
const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`), null, null, variablesInterfaceBody);
|
|
450
|
+
statements.push(t.exportNamedDeclaration(variablesInterface));
|
|
451
|
+
const resultInterfaceBody = t.tsInterfaceBody([
|
|
452
|
+
t.tsPropertySignature(t.identifier(queryName), t.tsTypeAnnotation(t.tsUnionType([
|
|
453
|
+
t.tsTypeReference(t.identifier(typeName)),
|
|
454
|
+
t.tsNullKeyword(),
|
|
455
|
+
]))),
|
|
456
|
+
]);
|
|
457
|
+
const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`), null, null, resultInterfaceBody);
|
|
458
|
+
statements.push(t.exportNamedDeclaration(resultInterface));
|
|
459
|
+
if (useCentralizedKeys) {
|
|
460
|
+
const queryKeyConst = t.variableDeclaration('const', [
|
|
461
|
+
t.variableDeclarator(t.identifier(`${queryName}QueryKey`), t.memberExpression(t.identifier(keysName), t.identifier('detail'))),
|
|
462
|
+
]);
|
|
463
|
+
const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
|
|
464
|
+
(0, babel_ast_1.addJSDocComment)(queryKeyExport, [
|
|
465
|
+
'Query key factory - re-exported from query-keys.ts',
|
|
466
|
+
]);
|
|
467
|
+
statements.push(queryKeyExport);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
const queryKeyArrow = t.arrowFunctionExpression([(0, babel_ast_1.typedParam)(pkName, pkTypeAnnotation)], t.tsAsExpression(t.arrayExpression([
|
|
471
|
+
t.stringLiteral(typeName.toLowerCase()),
|
|
472
|
+
t.stringLiteral('detail'),
|
|
473
|
+
t.identifier(pkName),
|
|
474
|
+
]), t.tsTypeReference(t.identifier('const'))));
|
|
475
|
+
const queryKeyConst = t.variableDeclaration('const', [
|
|
476
|
+
t.variableDeclarator(t.identifier(`${queryName}QueryKey`), queryKeyArrow),
|
|
477
|
+
]);
|
|
478
|
+
statements.push(t.exportNamedDeclaration(queryKeyConst));
|
|
298
479
|
}
|
|
299
|
-
imports.push((0, ts_ast_1.createImport)({
|
|
300
|
-
moduleSpecifier: '../client',
|
|
301
|
-
namedImports: ['execute'],
|
|
302
|
-
typeOnlyNamedImports: ['ExecuteOptions'],
|
|
303
|
-
}), (0, ts_ast_1.createImport)({
|
|
304
|
-
moduleSpecifier: '../types',
|
|
305
|
-
typeOnlyNamedImports: [typeName],
|
|
306
|
-
}));
|
|
307
|
-
sourceFile.addImportDeclarations(imports);
|
|
308
|
-
// Re-export entity type
|
|
309
|
-
sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
|
|
310
|
-
// Add section comment
|
|
311
|
-
sourceFile.addStatements('\n// ============================================================================');
|
|
312
|
-
sourceFile.addStatements('// GraphQL Document');
|
|
313
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
314
|
-
// Add query document constant
|
|
315
|
-
sourceFile.addVariableStatement((0, ts_ast_1.createConst)(`${queryName}QueryDocument`, '`\n' + queryDocument + '`'));
|
|
316
|
-
// Add section comment
|
|
317
|
-
sourceFile.addStatements('\n// ============================================================================');
|
|
318
|
-
sourceFile.addStatements('// Types');
|
|
319
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
320
|
-
// Variables interface - use dynamic PK field name and type
|
|
321
|
-
sourceFile.addInterface((0, ts_ast_1.createInterface)(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`, [
|
|
322
|
-
{ name: pkName, type: pkTsType },
|
|
323
|
-
]));
|
|
324
|
-
// Result interface
|
|
325
|
-
sourceFile.addInterface((0, ts_ast_1.createInterface)(`${(0, utils_1.ucFirst)(singularName)}QueryResult`, [
|
|
326
|
-
{ name: queryName, type: `${typeName} | null` },
|
|
327
|
-
]));
|
|
328
|
-
// Add section comment
|
|
329
|
-
sourceFile.addStatements('\n// ============================================================================');
|
|
330
|
-
sourceFile.addStatements('// Query Key');
|
|
331
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
332
|
-
// Query key factory - use dynamic PK field name and type
|
|
333
|
-
sourceFile.addVariableStatement((0, ts_ast_1.createConst)(`${queryName}QueryKey`, `(${pkName}: ${pkTsType}) =>
|
|
334
|
-
['${typeName.toLowerCase()}', 'detail', ${pkName}] as const`));
|
|
335
|
-
// Add React Query hook section (only if enabled)
|
|
336
480
|
if (reactQueryEnabled) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
481
|
+
const hookBodyStatements = [];
|
|
482
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
483
|
+
hookBodyStatements.push(t.variableDeclaration('const', [
|
|
484
|
+
t.variableDeclarator(t.objectPattern([
|
|
485
|
+
t.objectProperty(t.identifier('scope'), t.identifier('scope'), false, true),
|
|
486
|
+
t.restElement(t.identifier('queryOptions')),
|
|
487
|
+
]), t.logicalExpression('??', t.identifier('options'), t.objectExpression([]))),
|
|
488
|
+
]));
|
|
489
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
|
|
490
|
+
t.objectExpression([
|
|
491
|
+
t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
|
|
492
|
+
t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
|
|
493
|
+
t.identifier('scope'),
|
|
494
|
+
])),
|
|
495
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
496
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
497
|
+
t.identifier('variables'),
|
|
498
|
+
]))),
|
|
499
|
+
t.spreadElement(t.identifier('queryOptions')),
|
|
500
|
+
]),
|
|
501
|
+
])));
|
|
502
|
+
}
|
|
503
|
+
else if (useCentralizedKeys) {
|
|
504
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
|
|
505
|
+
t.objectExpression([
|
|
506
|
+
t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
|
|
507
|
+
t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
|
|
508
|
+
])),
|
|
509
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
510
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
511
|
+
t.identifier('variables'),
|
|
512
|
+
]))),
|
|
513
|
+
t.spreadElement(t.identifier('options')),
|
|
514
|
+
]),
|
|
515
|
+
])));
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
|
|
519
|
+
t.objectExpression([
|
|
520
|
+
t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(`${queryName}QueryKey`), [
|
|
521
|
+
t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
|
|
522
|
+
])),
|
|
523
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
524
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
525
|
+
t.identifier('variables'),
|
|
526
|
+
]))),
|
|
527
|
+
t.spreadElement(t.identifier('options')),
|
|
528
|
+
]),
|
|
529
|
+
])));
|
|
530
|
+
}
|
|
531
|
+
const hookParams = [
|
|
532
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`))),
|
|
533
|
+
];
|
|
534
|
+
let optionsTypeStr;
|
|
535
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
536
|
+
optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`;
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`;
|
|
540
|
+
}
|
|
541
|
+
const optionsParam = t.identifier('options');
|
|
542
|
+
optionsParam.optional = true;
|
|
543
|
+
optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
|
|
544
|
+
hookParams.push(optionsParam);
|
|
545
|
+
const hookFunc = t.functionDeclaration(t.identifier(hookName), hookParams, t.blockStatement(hookBodyStatements));
|
|
546
|
+
const hookExport = t.exportNamedDeclaration(hookFunc);
|
|
547
|
+
const docLines = [
|
|
548
|
+
`Query hook for fetching a single ${typeName}`,
|
|
549
|
+
'',
|
|
550
|
+
'@example',
|
|
551
|
+
'```tsx',
|
|
552
|
+
`const { data, isLoading } = ${hookName}({ ${pkName}: 'some-id' });`,
|
|
553
|
+
'```',
|
|
554
|
+
];
|
|
555
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
556
|
+
docLines.push('');
|
|
557
|
+
docLines.push('@example With scope for hierarchical cache invalidation');
|
|
558
|
+
docLines.push('```tsx');
|
|
559
|
+
docLines.push(`const { data } = ${hookName}(`);
|
|
560
|
+
docLines.push(` { ${pkName}: 'some-id' },`);
|
|
561
|
+
docLines.push(" { scope: { parentId: 'parent-id' } }");
|
|
562
|
+
docLines.push(');');
|
|
563
|
+
docLines.push('```');
|
|
564
|
+
}
|
|
565
|
+
(0, babel_ast_1.addJSDocComment)(hookExport, docLines);
|
|
566
|
+
statements.push(hookExport);
|
|
376
567
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
description: `Fetch a single ${typeName} by primary key without React hooks
|
|
403
|
-
|
|
404
|
-
@example
|
|
405
|
-
\`\`\`ts
|
|
406
|
-
const data = await fetch${(0, utils_1.ucFirst)(singularName)}Query(${pkTsType === 'string' ? "'value-here'" : '123'});
|
|
407
|
-
\`\`\``,
|
|
408
|
-
},
|
|
409
|
-
],
|
|
410
|
-
});
|
|
411
|
-
// Prefetch function (for SSR/QueryClient) - only if React Query is enabled, use dynamic PK
|
|
568
|
+
const fetchFuncBody = t.blockStatement([
|
|
569
|
+
t.returnStatement(t.callExpression(t.identifier('execute'), [
|
|
570
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
571
|
+
t.identifier('variables'),
|
|
572
|
+
t.identifier('options'),
|
|
573
|
+
])),
|
|
574
|
+
]);
|
|
575
|
+
const fetchFunc = t.functionDeclaration(t.identifier(`fetch${(0, utils_1.ucFirst)(singularName)}Query`), [
|
|
576
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`))),
|
|
577
|
+
(0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true),
|
|
578
|
+
], fetchFuncBody);
|
|
579
|
+
fetchFunc.async = true;
|
|
580
|
+
fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([
|
|
581
|
+
t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
|
|
582
|
+
])));
|
|
583
|
+
const fetchExport = t.exportNamedDeclaration(fetchFunc);
|
|
584
|
+
(0, babel_ast_1.addJSDocComment)(fetchExport, [
|
|
585
|
+
`Fetch a single ${typeName} without React hooks`,
|
|
586
|
+
'',
|
|
587
|
+
'@example',
|
|
588
|
+
'```ts',
|
|
589
|
+
`const data = await fetch${(0, utils_1.ucFirst)(singularName)}Query({ ${pkName}: 'some-id' });`,
|
|
590
|
+
'```',
|
|
591
|
+
]);
|
|
592
|
+
statements.push(fetchExport);
|
|
412
593
|
if (reactQueryEnabled) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
],
|
|
445
|
-
|
|
594
|
+
const prefetchParams = [
|
|
595
|
+
(0, babel_ast_1.typedParam)('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
|
|
596
|
+
(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`))),
|
|
597
|
+
];
|
|
598
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
599
|
+
prefetchParams.push((0, babel_ast_1.typedParam)('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true));
|
|
600
|
+
}
|
|
601
|
+
prefetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
|
|
602
|
+
let prefetchQueryKeyExpr;
|
|
603
|
+
if (hasRelationships && useCentralizedKeys) {
|
|
604
|
+
prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
|
|
605
|
+
t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
|
|
606
|
+
t.identifier('scope'),
|
|
607
|
+
]);
|
|
608
|
+
}
|
|
609
|
+
else if (useCentralizedKeys) {
|
|
610
|
+
prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [t.memberExpression(t.identifier('variables'), t.identifier(pkName))]);
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
prefetchQueryKeyExpr = t.callExpression(t.identifier(`${queryName}QueryKey`), [t.memberExpression(t.identifier('variables'), t.identifier(pkName))]);
|
|
614
|
+
}
|
|
615
|
+
const prefetchFuncBody = t.blockStatement([
|
|
616
|
+
t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
|
|
617
|
+
t.objectExpression([
|
|
618
|
+
t.objectProperty(t.identifier('queryKey'), prefetchQueryKeyExpr),
|
|
619
|
+
t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
|
|
620
|
+
t.identifier(`${queryName}QueryDocument`),
|
|
621
|
+
t.identifier('variables'),
|
|
622
|
+
t.identifier('options'),
|
|
623
|
+
]))),
|
|
624
|
+
]),
|
|
625
|
+
]))),
|
|
626
|
+
]);
|
|
627
|
+
const prefetchFunc = t.functionDeclaration(t.identifier(`prefetch${(0, utils_1.ucFirst)(singularName)}Query`), prefetchParams, prefetchFuncBody);
|
|
628
|
+
prefetchFunc.async = true;
|
|
629
|
+
prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
|
|
630
|
+
const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
|
|
631
|
+
(0, babel_ast_1.addJSDocComment)(prefetchExport, [
|
|
632
|
+
`Prefetch a single ${typeName} for SSR or cache warming`,
|
|
633
|
+
'',
|
|
634
|
+
'@example',
|
|
635
|
+
'```ts',
|
|
636
|
+
`await prefetch${(0, utils_1.ucFirst)(singularName)}Query(queryClient, { ${pkName}: 'some-id' });`,
|
|
637
|
+
'```',
|
|
638
|
+
]);
|
|
639
|
+
statements.push(prefetchExport);
|
|
446
640
|
}
|
|
641
|
+
const code = (0, babel_ast_1.generateCode)(statements);
|
|
642
|
+
const headerText = reactQueryEnabled
|
|
643
|
+
? `Single item query hook for ${typeName}`
|
|
644
|
+
: `Single item query functions for ${typeName}`;
|
|
645
|
+
const content = (0, utils_1.getGeneratedFileHeader)(headerText) + '\n\n' + code;
|
|
447
646
|
return {
|
|
448
647
|
fileName: (0, utils_1.getSingleQueryFileName)(table),
|
|
449
|
-
content
|
|
648
|
+
content,
|
|
450
649
|
};
|
|
451
650
|
}
|
|
452
|
-
// ============================================================================
|
|
453
|
-
// Batch generator
|
|
454
|
-
// ============================================================================
|
|
455
|
-
/**
|
|
456
|
-
* Generate all query hook files for all tables
|
|
457
|
-
*/
|
|
458
651
|
function generateAllQueryHooks(tables, options = {}) {
|
|
459
652
|
const files = [];
|
|
460
653
|
for (const table of tables) {
|