@constructive-io/graphql-codegen 4.14.0 → 4.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/codegen/cli/table-command-generator.d.ts +0 -14
- package/core/codegen/cli/table-command-generator.js +11 -52
- package/core/codegen/utils.d.ts +26 -1
- package/core/codegen/utils.js +51 -0
- package/esm/core/codegen/cli/table-command-generator.d.ts +0 -14
- package/esm/core/codegen/cli/table-command-generator.js +10 -50
- package/esm/core/codegen/utils.d.ts +26 -1
- package/esm/core/codegen/utils.js +48 -0
- package/package.json +2 -2
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import type { CleanTable, TypeRegistry } from '../../../types/schema';
|
|
2
2
|
import type { GeneratedFile } from './executor-generator';
|
|
3
|
-
/**
|
|
4
|
-
* Get the set of field names that have defaults in the create input type.
|
|
5
|
-
* Looks up the CreateXInput -> inner input type (e.g. DatabaseInput) in the
|
|
6
|
-
* TypeRegistry and checks each field's defaultValue from introspection.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Resolve the inner input type from a CreateXInput or UpdateXInput type.
|
|
10
|
-
* The CreateXInput has an inner field (e.g. "database" of type DatabaseInput)
|
|
11
|
-
* that contains the actual field definitions.
|
|
12
|
-
*/
|
|
13
|
-
export declare function resolveInnerInputType(inputTypeName: string, typeRegistry: TypeRegistry): {
|
|
14
|
-
name: string;
|
|
15
|
-
fields: Set<string>;
|
|
16
|
-
} | null;
|
|
17
3
|
export declare function getFieldsWithDefaults(table: CleanTable, typeRegistry?: TypeRegistry): Set<string>;
|
|
18
4
|
export interface TableCommandOptions {
|
|
19
5
|
targetName?: string;
|
|
@@ -33,7 +33,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.resolveInnerInputType = resolveInnerInputType;
|
|
37
36
|
exports.getFieldsWithDefaults = getFieldsWithDefaults;
|
|
38
37
|
exports.generateTableCommand = generateTableCommand;
|
|
39
38
|
const t = __importStar(require("@babel/types"));
|
|
@@ -150,8 +149,8 @@ function buildFieldSchemaObject(table) {
|
|
|
150
149
|
return t.objectProperty(t.identifier(f.name), t.stringLiteral(schemaType));
|
|
151
150
|
}));
|
|
152
151
|
}
|
|
153
|
-
function buildSelectObject(table) {
|
|
154
|
-
const fields = (0, utils_1.
|
|
152
|
+
function buildSelectObject(table, typeRegistry) {
|
|
153
|
+
const fields = (0, utils_1.getSelectableScalarFields)(table, typeRegistry);
|
|
155
154
|
return t.objectExpression(fields.map((f) => t.objectProperty(t.identifier(f.name), t.booleanLiteral(true))));
|
|
156
155
|
}
|
|
157
156
|
function buildJsonLog(expr) {
|
|
@@ -202,9 +201,9 @@ function buildSubcommandSwitch(subcommands, handlerPrefix, usageVarName) {
|
|
|
202
201
|
]));
|
|
203
202
|
return t.switchStatement(t.identifier('subcommand'), cases);
|
|
204
203
|
}
|
|
205
|
-
function buildListHandler(table, targetName) {
|
|
204
|
+
function buildListHandler(table, targetName, typeRegistry) {
|
|
206
205
|
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
207
|
-
const selectObj = buildSelectObject(table);
|
|
206
|
+
const selectObj = buildSelectObject(table, typeRegistry);
|
|
208
207
|
const tryBody = [
|
|
209
208
|
buildGetClientStatement(targetName),
|
|
210
209
|
t.variableDeclaration('const', [
|
|
@@ -222,11 +221,11 @@ function buildListHandler(table, targetName) {
|
|
|
222
221
|
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Failed to list records.')),
|
|
223
222
|
]), false, true);
|
|
224
223
|
}
|
|
225
|
-
function buildGetHandler(table, targetName) {
|
|
224
|
+
function buildGetHandler(table, targetName, typeRegistry) {
|
|
226
225
|
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
227
226
|
const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
|
|
228
227
|
const pk = pkFields[0];
|
|
229
|
-
const selectObj = buildSelectObject(table);
|
|
228
|
+
const selectObj = buildSelectObject(table, typeRegistry);
|
|
230
229
|
const promptQuestion = t.objectExpression([
|
|
231
230
|
t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
|
|
232
231
|
t.objectProperty(t.identifier('name'), t.stringLiteral(pk.name)),
|
|
@@ -258,40 +257,12 @@ function buildGetHandler(table, targetName) {
|
|
|
258
257
|
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Record not found.')),
|
|
259
258
|
]), false, true);
|
|
260
259
|
}
|
|
261
|
-
/**
|
|
262
|
-
* Get the set of field names that have defaults in the create input type.
|
|
263
|
-
* Looks up the CreateXInput -> inner input type (e.g. DatabaseInput) in the
|
|
264
|
-
* TypeRegistry and checks each field's defaultValue from introspection.
|
|
265
|
-
*/
|
|
266
|
-
/**
|
|
267
|
-
* Resolve the inner input type from a CreateXInput or UpdateXInput type.
|
|
268
|
-
* The CreateXInput has an inner field (e.g. "database" of type DatabaseInput)
|
|
269
|
-
* that contains the actual field definitions.
|
|
270
|
-
*/
|
|
271
|
-
function resolveInnerInputType(inputTypeName, typeRegistry) {
|
|
272
|
-
const inputType = typeRegistry.get(inputTypeName);
|
|
273
|
-
if (!inputType?.inputFields)
|
|
274
|
-
return null;
|
|
275
|
-
for (const inputField of inputType.inputFields) {
|
|
276
|
-
const innerTypeName = inputField.type.name
|
|
277
|
-
|| inputField.type.ofType?.name
|
|
278
|
-
|| inputField.type.ofType?.ofType?.name;
|
|
279
|
-
if (!innerTypeName)
|
|
280
|
-
continue;
|
|
281
|
-
const innerType = typeRegistry.get(innerTypeName);
|
|
282
|
-
if (!innerType?.inputFields)
|
|
283
|
-
continue;
|
|
284
|
-
const fields = new Set(innerType.inputFields.map((f) => f.name));
|
|
285
|
-
return { name: innerTypeName, fields };
|
|
286
|
-
}
|
|
287
|
-
return null;
|
|
288
|
-
}
|
|
289
260
|
function getFieldsWithDefaults(table, typeRegistry) {
|
|
290
261
|
const fieldsWithDefaults = new Set();
|
|
291
262
|
if (!typeRegistry)
|
|
292
263
|
return fieldsWithDefaults;
|
|
293
264
|
const createInputTypeName = (0, utils_1.getCreateInputTypeName)(table);
|
|
294
|
-
const resolved = resolveInnerInputType(createInputTypeName, typeRegistry);
|
|
265
|
+
const resolved = (0, utils_1.resolveInnerInputType)(createInputTypeName, typeRegistry);
|
|
295
266
|
if (!resolved)
|
|
296
267
|
return fieldsWithDefaults;
|
|
297
268
|
const innerType = typeRegistry.get(resolved.name);
|
|
@@ -307,18 +278,6 @@ function getFieldsWithDefaults(table, typeRegistry) {
|
|
|
307
278
|
}
|
|
308
279
|
return fieldsWithDefaults;
|
|
309
280
|
}
|
|
310
|
-
/**
|
|
311
|
-
* Get the set of field names that actually exist in the create/update input type.
|
|
312
|
-
* Fields not in this set (e.g. computed fields like searchTsvRank, hashUuid)
|
|
313
|
-
* should be excluded from the data object in create/update handlers.
|
|
314
|
-
*/
|
|
315
|
-
function getWritableFieldNames(table, typeRegistry) {
|
|
316
|
-
if (!typeRegistry)
|
|
317
|
-
return null;
|
|
318
|
-
const createInputTypeName = (0, utils_1.getCreateInputTypeName)(table);
|
|
319
|
-
const resolved = resolveInnerInputType(createInputTypeName, typeRegistry);
|
|
320
|
-
return resolved?.fields ?? null;
|
|
321
|
-
}
|
|
322
281
|
function buildMutationHandler(table, operation, targetName, typeRegistry, ormTypes) {
|
|
323
282
|
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
324
283
|
const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
|
|
@@ -326,7 +285,7 @@ function buildMutationHandler(table, operation, targetName, typeRegistry, ormTyp
|
|
|
326
285
|
// Get the set of writable field names from the type registry
|
|
327
286
|
// This filters out computed fields (e.g. searchTsvRank, hashUuid) that exist
|
|
328
287
|
// on the entity type but not on the create/update input type.
|
|
329
|
-
const writableFields = getWritableFieldNames(table, typeRegistry);
|
|
288
|
+
const writableFields = (0, utils_1.getWritableFieldNames)(table, typeRegistry);
|
|
330
289
|
// Get fields that have defaults from introspection (for create operations)
|
|
331
290
|
const fieldsWithDefaults = getFieldsWithDefaults(table, typeRegistry);
|
|
332
291
|
// For create: include fields that are in the create input type.
|
|
@@ -379,7 +338,7 @@ function buildMutationHandler(table, operation, targetName, typeRegistry, ormTyp
|
|
|
379
338
|
? t.objectExpression([
|
|
380
339
|
t.objectProperty(t.identifier(pk.name), t.booleanLiteral(true)),
|
|
381
340
|
])
|
|
382
|
-
: buildSelectObject(table);
|
|
341
|
+
: buildSelectObject(table, typeRegistry);
|
|
383
342
|
let ormArgs;
|
|
384
343
|
// Build data properties without individual type assertions.
|
|
385
344
|
// Instead, we build a plain object from cleanedData and cast the entire
|
|
@@ -587,9 +546,9 @@ function generateTableCommand(table, options) {
|
|
|
587
546
|
]), false, true));
|
|
588
547
|
const tn = options?.targetName;
|
|
589
548
|
const ormTypes = { createInputTypeName, patchTypeName, innerFieldName };
|
|
590
|
-
statements.push(buildListHandler(table, tn));
|
|
549
|
+
statements.push(buildListHandler(table, tn, options?.typeRegistry));
|
|
591
550
|
if (hasGet)
|
|
592
|
-
statements.push(buildGetHandler(table, tn));
|
|
551
|
+
statements.push(buildGetHandler(table, tn, options?.typeRegistry));
|
|
593
552
|
statements.push(buildMutationHandler(table, 'create', tn, options?.typeRegistry, ormTypes));
|
|
594
553
|
if (hasUpdate)
|
|
595
554
|
statements.push(buildMutationHandler(table, 'update', tn, options?.typeRegistry, ormTypes));
|
package/core/codegen/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CleanField, CleanFieldType, CleanTable } from '../../types/schema';
|
|
1
|
+
import type { CleanField, CleanFieldType, CleanTable, TypeRegistry } from '../../types/schema';
|
|
2
2
|
/** Lowercase first character */
|
|
3
3
|
export declare function lcFirst(str: string): string;
|
|
4
4
|
/** Uppercase first character */
|
|
@@ -148,6 +148,31 @@ export declare function isRelationField(fieldName: string, table: CleanTable): b
|
|
|
148
148
|
* Get only scalar fields (non-relation fields)
|
|
149
149
|
*/
|
|
150
150
|
export declare function getScalarFields(table: CleanTable): CleanField[];
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the inner input type from a CreateXInput.
|
|
153
|
+
* PostGraphile create inputs wrap the actual field definitions in an inner type
|
|
154
|
+
* (e.g. CreateUserInput -> { user: UserInput }) — this resolves that inner type
|
|
155
|
+
* and returns the set of field names it contains.
|
|
156
|
+
*/
|
|
157
|
+
export declare function resolveInnerInputType(inputTypeName: string, typeRegistry: TypeRegistry): {
|
|
158
|
+
name: string;
|
|
159
|
+
fields: Set<string>;
|
|
160
|
+
} | null;
|
|
161
|
+
/**
|
|
162
|
+
* Get the set of field names that actually exist in the create input type.
|
|
163
|
+
* Fields not in this set (e.g. computed fields like searchTsvRank, hashUuid)
|
|
164
|
+
* are plugin-added computed fields that don't correspond to real database columns.
|
|
165
|
+
* Returns null when no typeRegistry is provided (caller should treat as "no filtering").
|
|
166
|
+
*/
|
|
167
|
+
export declare function getWritableFieldNames(table: CleanTable, typeRegistry?: TypeRegistry): Set<string> | null;
|
|
168
|
+
/**
|
|
169
|
+
* Get scalar fields that represent actual database columns (not computed/plugin-added).
|
|
170
|
+
* When a TypeRegistry is provided, filters out fields that don't exist in the
|
|
171
|
+
* create input type — these are computed fields added by plugins (e.g. search scores,
|
|
172
|
+
* hash UUIDs) that aren't real columns and shouldn't appear in default selections.
|
|
173
|
+
* Without a TypeRegistry, falls back to all scalar fields.
|
|
174
|
+
*/
|
|
175
|
+
export declare function getSelectableScalarFields(table: CleanTable, typeRegistry?: TypeRegistry): CleanField[];
|
|
151
176
|
/**
|
|
152
177
|
* Primary key field information
|
|
153
178
|
*/
|
package/core/codegen/utils.js
CHANGED
|
@@ -33,6 +33,9 @@ exports.fieldTypeToTs = fieldTypeToTs;
|
|
|
33
33
|
exports.getScalarFilterType = getScalarFilterType;
|
|
34
34
|
exports.isRelationField = isRelationField;
|
|
35
35
|
exports.getScalarFields = getScalarFields;
|
|
36
|
+
exports.resolveInnerInputType = resolveInnerInputType;
|
|
37
|
+
exports.getWritableFieldNames = getWritableFieldNames;
|
|
38
|
+
exports.getSelectableScalarFields = getSelectableScalarFields;
|
|
36
39
|
exports.getPrimaryKeyInfo = getPrimaryKeyInfo;
|
|
37
40
|
exports.getPrimaryKeyFields = getPrimaryKeyFields;
|
|
38
41
|
exports.hasValidPrimaryKey = hasValidPrimaryKey;
|
|
@@ -303,6 +306,54 @@ function isRelationField(fieldName, table) {
|
|
|
303
306
|
function getScalarFields(table) {
|
|
304
307
|
return table.fields.filter((f) => !isRelationField(f.name, table));
|
|
305
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Resolve the inner input type from a CreateXInput.
|
|
311
|
+
* PostGraphile create inputs wrap the actual field definitions in an inner type
|
|
312
|
+
* (e.g. CreateUserInput -> { user: UserInput }) — this resolves that inner type
|
|
313
|
+
* and returns the set of field names it contains.
|
|
314
|
+
*/
|
|
315
|
+
function resolveInnerInputType(inputTypeName, typeRegistry) {
|
|
316
|
+
const inputType = typeRegistry.get(inputTypeName);
|
|
317
|
+
if (!inputType?.inputFields)
|
|
318
|
+
return null;
|
|
319
|
+
for (const inputField of inputType.inputFields) {
|
|
320
|
+
const innerTypeName = inputField.type.name
|
|
321
|
+
|| inputField.type.ofType?.name
|
|
322
|
+
|| inputField.type.ofType?.ofType?.name;
|
|
323
|
+
if (!innerTypeName)
|
|
324
|
+
continue;
|
|
325
|
+
const innerType = typeRegistry.get(innerTypeName);
|
|
326
|
+
if (!innerType?.inputFields)
|
|
327
|
+
continue;
|
|
328
|
+
const fields = new Set(innerType.inputFields.map((f) => f.name));
|
|
329
|
+
return { name: innerTypeName, fields };
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get the set of field names that actually exist in the create input type.
|
|
335
|
+
* Fields not in this set (e.g. computed fields like searchTsvRank, hashUuid)
|
|
336
|
+
* are plugin-added computed fields that don't correspond to real database columns.
|
|
337
|
+
* Returns null when no typeRegistry is provided (caller should treat as "no filtering").
|
|
338
|
+
*/
|
|
339
|
+
function getWritableFieldNames(table, typeRegistry) {
|
|
340
|
+
if (!typeRegistry)
|
|
341
|
+
return null;
|
|
342
|
+
const createInputTypeName = getCreateInputTypeName(table);
|
|
343
|
+
const resolved = resolveInnerInputType(createInputTypeName, typeRegistry);
|
|
344
|
+
return resolved?.fields ?? null;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Get scalar fields that represent actual database columns (not computed/plugin-added).
|
|
348
|
+
* When a TypeRegistry is provided, filters out fields that don't exist in the
|
|
349
|
+
* create input type — these are computed fields added by plugins (e.g. search scores,
|
|
350
|
+
* hash UUIDs) that aren't real columns and shouldn't appear in default selections.
|
|
351
|
+
* Without a TypeRegistry, falls back to all scalar fields.
|
|
352
|
+
*/
|
|
353
|
+
function getSelectableScalarFields(table, typeRegistry) {
|
|
354
|
+
const writableFields = getWritableFieldNames(table, typeRegistry);
|
|
355
|
+
return getScalarFields(table).filter((f) => writableFields === null || writableFields.has(f.name));
|
|
356
|
+
}
|
|
306
357
|
/**
|
|
307
358
|
* Get primary key field information from table constraints
|
|
308
359
|
* Returns array to support composite primary keys
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import type { CleanTable, TypeRegistry } from '../../../types/schema';
|
|
2
2
|
import type { GeneratedFile } from './executor-generator';
|
|
3
|
-
/**
|
|
4
|
-
* Get the set of field names that have defaults in the create input type.
|
|
5
|
-
* Looks up the CreateXInput -> inner input type (e.g. DatabaseInput) in the
|
|
6
|
-
* TypeRegistry and checks each field's defaultValue from introspection.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Resolve the inner input type from a CreateXInput or UpdateXInput type.
|
|
10
|
-
* The CreateXInput has an inner field (e.g. "database" of type DatabaseInput)
|
|
11
|
-
* that contains the actual field definitions.
|
|
12
|
-
*/
|
|
13
|
-
export declare function resolveInnerInputType(inputTypeName: string, typeRegistry: TypeRegistry): {
|
|
14
|
-
name: string;
|
|
15
|
-
fields: Set<string>;
|
|
16
|
-
} | null;
|
|
17
3
|
export declare function getFieldsWithDefaults(table: CleanTable, typeRegistry?: TypeRegistry): Set<string>;
|
|
18
4
|
export interface TableCommandOptions {
|
|
19
5
|
targetName?: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import { toKebabCase } from 'komoji';
|
|
3
3
|
import { generateCode } from '../babel-ast';
|
|
4
|
-
import { getGeneratedFileHeader, getPrimaryKeyInfo, getScalarFields, getTableNames, ucFirst, lcFirst, getCreateInputTypeName, getPatchTypeName, } from '../utils';
|
|
4
|
+
import { getGeneratedFileHeader, getPrimaryKeyInfo, getScalarFields, getSelectableScalarFields, getTableNames, getWritableFieldNames, resolveInnerInputType, ucFirst, lcFirst, getCreateInputTypeName, getPatchTypeName, } from '../utils';
|
|
5
5
|
function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
|
|
6
6
|
const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
|
|
7
7
|
const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
|
|
@@ -112,8 +112,8 @@ function buildFieldSchemaObject(table) {
|
|
|
112
112
|
return t.objectProperty(t.identifier(f.name), t.stringLiteral(schemaType));
|
|
113
113
|
}));
|
|
114
114
|
}
|
|
115
|
-
function buildSelectObject(table) {
|
|
116
|
-
const fields =
|
|
115
|
+
function buildSelectObject(table, typeRegistry) {
|
|
116
|
+
const fields = getSelectableScalarFields(table, typeRegistry);
|
|
117
117
|
return t.objectExpression(fields.map((f) => t.objectProperty(t.identifier(f.name), t.booleanLiteral(true))));
|
|
118
118
|
}
|
|
119
119
|
function buildJsonLog(expr) {
|
|
@@ -164,9 +164,9 @@ function buildSubcommandSwitch(subcommands, handlerPrefix, usageVarName) {
|
|
|
164
164
|
]));
|
|
165
165
|
return t.switchStatement(t.identifier('subcommand'), cases);
|
|
166
166
|
}
|
|
167
|
-
function buildListHandler(table, targetName) {
|
|
167
|
+
function buildListHandler(table, targetName, typeRegistry) {
|
|
168
168
|
const { singularName } = getTableNames(table);
|
|
169
|
-
const selectObj = buildSelectObject(table);
|
|
169
|
+
const selectObj = buildSelectObject(table, typeRegistry);
|
|
170
170
|
const tryBody = [
|
|
171
171
|
buildGetClientStatement(targetName),
|
|
172
172
|
t.variableDeclaration('const', [
|
|
@@ -184,11 +184,11 @@ function buildListHandler(table, targetName) {
|
|
|
184
184
|
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Failed to list records.')),
|
|
185
185
|
]), false, true);
|
|
186
186
|
}
|
|
187
|
-
function buildGetHandler(table, targetName) {
|
|
187
|
+
function buildGetHandler(table, targetName, typeRegistry) {
|
|
188
188
|
const { singularName } = getTableNames(table);
|
|
189
189
|
const pkFields = getPrimaryKeyInfo(table);
|
|
190
190
|
const pk = pkFields[0];
|
|
191
|
-
const selectObj = buildSelectObject(table);
|
|
191
|
+
const selectObj = buildSelectObject(table, typeRegistry);
|
|
192
192
|
const promptQuestion = t.objectExpression([
|
|
193
193
|
t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
|
|
194
194
|
t.objectProperty(t.identifier('name'), t.stringLiteral(pk.name)),
|
|
@@ -220,34 +220,6 @@ function buildGetHandler(table, targetName) {
|
|
|
220
220
|
t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Record not found.')),
|
|
221
221
|
]), false, true);
|
|
222
222
|
}
|
|
223
|
-
/**
|
|
224
|
-
* Get the set of field names that have defaults in the create input type.
|
|
225
|
-
* Looks up the CreateXInput -> inner input type (e.g. DatabaseInput) in the
|
|
226
|
-
* TypeRegistry and checks each field's defaultValue from introspection.
|
|
227
|
-
*/
|
|
228
|
-
/**
|
|
229
|
-
* Resolve the inner input type from a CreateXInput or UpdateXInput type.
|
|
230
|
-
* The CreateXInput has an inner field (e.g. "database" of type DatabaseInput)
|
|
231
|
-
* that contains the actual field definitions.
|
|
232
|
-
*/
|
|
233
|
-
export function resolveInnerInputType(inputTypeName, typeRegistry) {
|
|
234
|
-
const inputType = typeRegistry.get(inputTypeName);
|
|
235
|
-
if (!inputType?.inputFields)
|
|
236
|
-
return null;
|
|
237
|
-
for (const inputField of inputType.inputFields) {
|
|
238
|
-
const innerTypeName = inputField.type.name
|
|
239
|
-
|| inputField.type.ofType?.name
|
|
240
|
-
|| inputField.type.ofType?.ofType?.name;
|
|
241
|
-
if (!innerTypeName)
|
|
242
|
-
continue;
|
|
243
|
-
const innerType = typeRegistry.get(innerTypeName);
|
|
244
|
-
if (!innerType?.inputFields)
|
|
245
|
-
continue;
|
|
246
|
-
const fields = new Set(innerType.inputFields.map((f) => f.name));
|
|
247
|
-
return { name: innerTypeName, fields };
|
|
248
|
-
}
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
223
|
export function getFieldsWithDefaults(table, typeRegistry) {
|
|
252
224
|
const fieldsWithDefaults = new Set();
|
|
253
225
|
if (!typeRegistry)
|
|
@@ -269,18 +241,6 @@ export function getFieldsWithDefaults(table, typeRegistry) {
|
|
|
269
241
|
}
|
|
270
242
|
return fieldsWithDefaults;
|
|
271
243
|
}
|
|
272
|
-
/**
|
|
273
|
-
* Get the set of field names that actually exist in the create/update input type.
|
|
274
|
-
* Fields not in this set (e.g. computed fields like searchTsvRank, hashUuid)
|
|
275
|
-
* should be excluded from the data object in create/update handlers.
|
|
276
|
-
*/
|
|
277
|
-
function getWritableFieldNames(table, typeRegistry) {
|
|
278
|
-
if (!typeRegistry)
|
|
279
|
-
return null;
|
|
280
|
-
const createInputTypeName = getCreateInputTypeName(table);
|
|
281
|
-
const resolved = resolveInnerInputType(createInputTypeName, typeRegistry);
|
|
282
|
-
return resolved?.fields ?? null;
|
|
283
|
-
}
|
|
284
244
|
function buildMutationHandler(table, operation, targetName, typeRegistry, ormTypes) {
|
|
285
245
|
const { singularName } = getTableNames(table);
|
|
286
246
|
const pkFields = getPrimaryKeyInfo(table);
|
|
@@ -341,7 +301,7 @@ function buildMutationHandler(table, operation, targetName, typeRegistry, ormTyp
|
|
|
341
301
|
? t.objectExpression([
|
|
342
302
|
t.objectProperty(t.identifier(pk.name), t.booleanLiteral(true)),
|
|
343
303
|
])
|
|
344
|
-
: buildSelectObject(table);
|
|
304
|
+
: buildSelectObject(table, typeRegistry);
|
|
345
305
|
let ormArgs;
|
|
346
306
|
// Build data properties without individual type assertions.
|
|
347
307
|
// Instead, we build a plain object from cleanedData and cast the entire
|
|
@@ -549,9 +509,9 @@ export function generateTableCommand(table, options) {
|
|
|
549
509
|
]), false, true));
|
|
550
510
|
const tn = options?.targetName;
|
|
551
511
|
const ormTypes = { createInputTypeName, patchTypeName, innerFieldName };
|
|
552
|
-
statements.push(buildListHandler(table, tn));
|
|
512
|
+
statements.push(buildListHandler(table, tn, options?.typeRegistry));
|
|
553
513
|
if (hasGet)
|
|
554
|
-
statements.push(buildGetHandler(table, tn));
|
|
514
|
+
statements.push(buildGetHandler(table, tn, options?.typeRegistry));
|
|
555
515
|
statements.push(buildMutationHandler(table, 'create', tn, options?.typeRegistry, ormTypes));
|
|
556
516
|
if (hasUpdate)
|
|
557
517
|
statements.push(buildMutationHandler(table, 'update', tn, options?.typeRegistry, ormTypes));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CleanField, CleanFieldType, CleanTable } from '../../types/schema';
|
|
1
|
+
import type { CleanField, CleanFieldType, CleanTable, TypeRegistry } from '../../types/schema';
|
|
2
2
|
/** Lowercase first character */
|
|
3
3
|
export declare function lcFirst(str: string): string;
|
|
4
4
|
/** Uppercase first character */
|
|
@@ -148,6 +148,31 @@ export declare function isRelationField(fieldName: string, table: CleanTable): b
|
|
|
148
148
|
* Get only scalar fields (non-relation fields)
|
|
149
149
|
*/
|
|
150
150
|
export declare function getScalarFields(table: CleanTable): CleanField[];
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the inner input type from a CreateXInput.
|
|
153
|
+
* PostGraphile create inputs wrap the actual field definitions in an inner type
|
|
154
|
+
* (e.g. CreateUserInput -> { user: UserInput }) — this resolves that inner type
|
|
155
|
+
* and returns the set of field names it contains.
|
|
156
|
+
*/
|
|
157
|
+
export declare function resolveInnerInputType(inputTypeName: string, typeRegistry: TypeRegistry): {
|
|
158
|
+
name: string;
|
|
159
|
+
fields: Set<string>;
|
|
160
|
+
} | null;
|
|
161
|
+
/**
|
|
162
|
+
* Get the set of field names that actually exist in the create input type.
|
|
163
|
+
* Fields not in this set (e.g. computed fields like searchTsvRank, hashUuid)
|
|
164
|
+
* are plugin-added computed fields that don't correspond to real database columns.
|
|
165
|
+
* Returns null when no typeRegistry is provided (caller should treat as "no filtering").
|
|
166
|
+
*/
|
|
167
|
+
export declare function getWritableFieldNames(table: CleanTable, typeRegistry?: TypeRegistry): Set<string> | null;
|
|
168
|
+
/**
|
|
169
|
+
* Get scalar fields that represent actual database columns (not computed/plugin-added).
|
|
170
|
+
* When a TypeRegistry is provided, filters out fields that don't exist in the
|
|
171
|
+
* create input type — these are computed fields added by plugins (e.g. search scores,
|
|
172
|
+
* hash UUIDs) that aren't real columns and shouldn't appear in default selections.
|
|
173
|
+
* Without a TypeRegistry, falls back to all scalar fields.
|
|
174
|
+
*/
|
|
175
|
+
export declare function getSelectableScalarFields(table: CleanTable, typeRegistry?: TypeRegistry): CleanField[];
|
|
151
176
|
/**
|
|
152
177
|
* Primary key field information
|
|
153
178
|
*/
|
|
@@ -261,6 +261,54 @@ export function isRelationField(fieldName, table) {
|
|
|
261
261
|
export function getScalarFields(table) {
|
|
262
262
|
return table.fields.filter((f) => !isRelationField(f.name, table));
|
|
263
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Resolve the inner input type from a CreateXInput.
|
|
266
|
+
* PostGraphile create inputs wrap the actual field definitions in an inner type
|
|
267
|
+
* (e.g. CreateUserInput -> { user: UserInput }) — this resolves that inner type
|
|
268
|
+
* and returns the set of field names it contains.
|
|
269
|
+
*/
|
|
270
|
+
export function resolveInnerInputType(inputTypeName, typeRegistry) {
|
|
271
|
+
const inputType = typeRegistry.get(inputTypeName);
|
|
272
|
+
if (!inputType?.inputFields)
|
|
273
|
+
return null;
|
|
274
|
+
for (const inputField of inputType.inputFields) {
|
|
275
|
+
const innerTypeName = inputField.type.name
|
|
276
|
+
|| inputField.type.ofType?.name
|
|
277
|
+
|| inputField.type.ofType?.ofType?.name;
|
|
278
|
+
if (!innerTypeName)
|
|
279
|
+
continue;
|
|
280
|
+
const innerType = typeRegistry.get(innerTypeName);
|
|
281
|
+
if (!innerType?.inputFields)
|
|
282
|
+
continue;
|
|
283
|
+
const fields = new Set(innerType.inputFields.map((f) => f.name));
|
|
284
|
+
return { name: innerTypeName, fields };
|
|
285
|
+
}
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get the set of field names that actually exist in the create input type.
|
|
290
|
+
* Fields not in this set (e.g. computed fields like searchTsvRank, hashUuid)
|
|
291
|
+
* are plugin-added computed fields that don't correspond to real database columns.
|
|
292
|
+
* Returns null when no typeRegistry is provided (caller should treat as "no filtering").
|
|
293
|
+
*/
|
|
294
|
+
export function getWritableFieldNames(table, typeRegistry) {
|
|
295
|
+
if (!typeRegistry)
|
|
296
|
+
return null;
|
|
297
|
+
const createInputTypeName = getCreateInputTypeName(table);
|
|
298
|
+
const resolved = resolveInnerInputType(createInputTypeName, typeRegistry);
|
|
299
|
+
return resolved?.fields ?? null;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get scalar fields that represent actual database columns (not computed/plugin-added).
|
|
303
|
+
* When a TypeRegistry is provided, filters out fields that don't exist in the
|
|
304
|
+
* create input type — these are computed fields added by plugins (e.g. search scores,
|
|
305
|
+
* hash UUIDs) that aren't real columns and shouldn't appear in default selections.
|
|
306
|
+
* Without a TypeRegistry, falls back to all scalar fields.
|
|
307
|
+
*/
|
|
308
|
+
export function getSelectableScalarFields(table, typeRegistry) {
|
|
309
|
+
const writableFields = getWritableFieldNames(table, typeRegistry);
|
|
310
|
+
return getScalarFields(table).filter((f) => writableFields === null || writableFields.has(f.name));
|
|
311
|
+
}
|
|
264
312
|
/**
|
|
265
313
|
* Get primary key field information from table constraints
|
|
266
314
|
* Returns array to support composite primary keys
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/graphql-codegen",
|
|
3
|
-
"version": "4.14.
|
|
3
|
+
"version": "4.14.1",
|
|
4
4
|
"description": "GraphQL SDK generator for Constructive databases with React Query hooks",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphql",
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
"tsx": "^4.21.0",
|
|
102
102
|
"typescript": "^5.9.3"
|
|
103
103
|
},
|
|
104
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "64ef59e5114d52bc897c7e9ef92d35ca6525f12f"
|
|
105
105
|
}
|