diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap index 52c49afd7..33cf64782 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/cli-generator.test.ts.snap @@ -281,10 +281,10 @@ CRUD operations for Car records via myapp CLI \`\`\`bash myapp car list -myapp car get --id -myapp car create --make --model --year --isElectric -myapp car update --id [--make ] [--model ] [--year ] [--isElectric ] -myapp car delete --id +myapp car get --id +myapp car create --make --model --year --isElectric +myapp car update --id [--make ] [--model ] [--year ] [--isElectric ] +myapp car delete --id \`\`\` ## Examples @@ -298,7 +298,7 @@ myapp car list ### Create a car \`\`\`bash -myapp car create --make --model --year --isElectric +myapp car create --make --model --year --isElectric \`\`\` ### Get a car by id @@ -320,10 +320,10 @@ CRUD operations for Driver records via myapp CLI \`\`\`bash myapp driver list -myapp driver get --id -myapp driver create --name --licenseNumber -myapp driver update --id [--name ] [--licenseNumber ] -myapp driver delete --id +myapp driver get --id +myapp driver create --name --licenseNumber +myapp driver update --id [--name ] [--licenseNumber ] +myapp driver delete --id \`\`\` ## Examples @@ -337,7 +337,7 @@ myapp driver list ### Create a driver \`\`\`bash -myapp driver create --name --licenseNumber +myapp driver create --name --licenseNumber \`\`\` ### Get a driver by id @@ -381,7 +381,7 @@ Authenticate a user ## Usage \`\`\`bash -myapp login --email --password +myapp login --email --password \`\`\` ## Examples @@ -389,7 +389,7 @@ myapp login --email --password ### Run login \`\`\`bash -myapp login --email --password +myapp login --email --password \`\`\` " `; @@ -1409,7 +1409,7 @@ const { data, isLoading } = useCarsQuery({ // Get one car const { data: item } = useCarQuery({ - id: '', + id: '', selection: { fields: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } }, }); @@ -1417,7 +1417,7 @@ const { data: item } = useCarQuery({ const { mutate: create } = useCreateCarMutation({ selection: { fields: { id: true } }, }); -create({ make: '', model: '', year: '', isElectric: '' }); +create({ make: '', model: '', year: '', isElectric: '' }); \`\`\` ### Driver @@ -1430,7 +1430,7 @@ const { data, isLoading } = useDriversQuery({ // Get one driver const { data: item } = useDriverQuery({ - id: '', + id: '', selection: { fields: { id: true, name: true, licenseNumber: true } }, }); @@ -1438,7 +1438,7 @@ const { data: item } = useDriverQuery({ const { mutate: create } = useCreateDriverMutation({ selection: { fields: { id: true } }, }); -create({ name: '', licenseNumber: '' }); +create({ name: '', licenseNumber: '' }); \`\`\` ## Custom Operation Hooks @@ -1485,7 +1485,7 @@ React Query hooks for Car data operations \`\`\`typescript useCarsQuery({ selection: { fields: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } } }) -useCarQuery({ id: '', selection: { fields: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } } }) +useCarQuery({ id: '', selection: { fields: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } } }) useCreateCarMutation({ selection: { fields: { id: true } } }) useUpdateCarMutation({ selection: { fields: { id: true } } }) useDeleteCarMutation({}) @@ -1507,7 +1507,7 @@ const { data, isLoading } = useCarsQuery({ const { mutate } = useCreateCarMutation({ selection: { fields: { id: true } }, }); -mutate({ make: '', model: '', year: '', isElectric: '' }); +mutate({ make: '', model: '', year: '', isElectric: '' }); \`\`\` " `; @@ -1523,7 +1523,7 @@ React Query hooks for Driver data operations \`\`\`typescript useDriversQuery({ selection: { fields: { id: true, name: true, licenseNumber: true } } }) -useDriverQuery({ id: '', selection: { fields: { id: true, name: true, licenseNumber: true } } }) +useDriverQuery({ id: '', selection: { fields: { id: true, name: true, licenseNumber: true } } }) useCreateDriverMutation({ selection: { fields: { id: true } } }) useUpdateDriverMutation({ selection: { fields: { id: true } } }) useDeleteDriverMutation({}) @@ -1545,7 +1545,7 @@ const { data, isLoading } = useDriversQuery({ const { mutate } = useCreateDriverMutation({ selection: { fields: { id: true } }, }); -mutate({ name: '', licenseNumber: '' }); +mutate({ name: '', licenseNumber: '' }); \`\`\` " `; @@ -1583,7 +1583,7 @@ Authenticate a user ## Usage \`\`\`typescript -const { mutate } = useLoginMutation(); mutate({ email: '', password: '' }); +const { mutate } = useLoginMutation(); mutate({ email: '', password: '' }); \`\`\` ## Examples @@ -1592,7 +1592,7 @@ const { mutate } = useLoginMutation(); mutate({ email: '', password: '', password: '' }); +mutate({ email: '', password: '' }); \`\`\` " `; @@ -2654,10 +2654,10 @@ CRUD operations for User records via myapp CLI (auth target) \`\`\`bash myapp auth:user list -myapp auth:user get --id -myapp auth:user create --email --name -myapp auth:user update --id [--email ] [--name ] -myapp auth:user delete --id +myapp auth:user get --id +myapp auth:user create --email --name +myapp auth:user update --id [--email ] [--name ] +myapp auth:user delete --id \`\`\` ## Examples @@ -2671,7 +2671,7 @@ myapp auth:user list ### Create a user \`\`\`bash -myapp auth:user create --email --name +myapp auth:user create --email --name \`\`\` ", "fileName": "cli-auth/references/user.md", @@ -2709,8 +2709,8 @@ Authenticate a user (auth target) ## Usage \`\`\`bash -myapp auth:login --email --password -myapp auth:login --email --password --save-token +myapp auth:login --email --password +myapp auth:login --email --password --save-token \`\`\` ## Examples @@ -2718,7 +2718,7 @@ myapp auth:login --email --password --save-token ### Run login \`\`\`bash -myapp auth:login --email --password +myapp auth:login --email --password \`\`\` ", "fileName": "cli-auth/references/login.md", @@ -2782,10 +2782,10 @@ CRUD operations for Member records via myapp CLI (members target) \`\`\`bash myapp members:member list -myapp members:member get --id -myapp members:member create --role -myapp members:member update --id [--role ] -myapp members:member delete --id +myapp members:member get --id +myapp members:member create --role +myapp members:member update --id [--role ] +myapp members:member delete --id \`\`\` ## Examples @@ -2799,7 +2799,7 @@ myapp members:member list ### Create a member \`\`\`bash -myapp members:member create --role +myapp members:member create --role \`\`\` ", "fileName": "cli-members/references/member.md", @@ -2861,10 +2861,10 @@ CRUD operations for Car records via myapp CLI (app target) \`\`\`bash myapp app:car list -myapp app:car get --id -myapp app:car create --make --model --year --isElectric -myapp app:car update --id [--make ] [--model ] [--year ] [--isElectric ] -myapp app:car delete --id +myapp app:car get --id +myapp app:car create --make --model --year --isElectric +myapp app:car update --id [--make ] [--model ] [--year ] [--isElectric ] +myapp app:car delete --id \`\`\` ## Examples @@ -2878,7 +2878,7 @@ myapp app:car list ### Create a car \`\`\`bash -myapp app:car create --make --model --year --isElectric +myapp app:car create --make --model --year --isElectric \`\`\` ", "fileName": "cli-app/references/car.md", @@ -4254,16 +4254,16 @@ CRUD operations for Car records. const items = await db.car.findMany({ select: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } }).execute(); // Get one by id -const item = await db.car.findOne({ id: '', select: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } }).execute(); +const item = await db.car.findOne({ id: '', select: { id: true, make: true, model: true, year: true, isElectric: true, createdAt: true } }).execute(); // Create -const created = await db.car.create({ data: { make: '', model: '', year: '', isElectric: '' }, select: { id: true } }).execute(); +const created = await db.car.create({ data: { make: '', model: '', year: '', isElectric: '' }, select: { id: true } }).execute(); // Update -const updated = await db.car.update({ where: { id: '' }, data: { make: '' }, select: { id: true } }).execute(); +const updated = await db.car.update({ where: { id: '' }, data: { make: '' }, select: { id: true } }).execute(); // Delete -const deleted = await db.car.delete({ where: { id: '' } }).execute(); +const deleted = await db.car.delete({ where: { id: '' } }).execute(); \`\`\` ### \`db.driver\` @@ -4285,16 +4285,16 @@ CRUD operations for Driver records. const items = await db.driver.findMany({ select: { id: true, name: true, licenseNumber: true } }).execute(); // Get one by id -const item = await db.driver.findOne({ id: '', select: { id: true, name: true, licenseNumber: true } }).execute(); +const item = await db.driver.findOne({ id: '', select: { id: true, name: true, licenseNumber: true } }).execute(); // Create -const created = await db.driver.create({ data: { name: '', licenseNumber: '' }, select: { id: true } }).execute(); +const created = await db.driver.create({ data: { name: '', licenseNumber: '' }, select: { id: true } }).execute(); // Update -const updated = await db.driver.update({ where: { id: '' }, data: { name: '' }, select: { id: true } }).execute(); +const updated = await db.driver.update({ where: { id: '' }, data: { name: '' }, select: { id: true } }).execute(); // Delete -const deleted = await db.driver.delete({ where: { id: '' } }).execute(); +const deleted = await db.driver.delete({ where: { id: '' } }).execute(); \`\`\` ## Custom Operations @@ -4323,7 +4323,7 @@ Authenticate a user | \`password\` | String (required) | \`\`\`typescript -const result = await db.mutation.login({ email: '', password: '' }).execute(); +const result = await db.mutation.login({ email: '', password: '' }).execute(); \`\`\` --- @@ -4349,10 +4349,10 @@ ORM operations for Car records \`\`\`typescript db.car.findMany({ select: { id: true } }).execute() -db.car.findOne({ id: '', select: { id: true } }).execute() -db.car.create({ data: { make: '', model: '', year: '', isElectric: '' }, select: { id: true } }).execute() -db.car.update({ where: { id: '' }, data: { make: '' }, select: { id: true } }).execute() -db.car.delete({ where: { id: '' } }).execute() +db.car.findOne({ id: '', select: { id: true } }).execute() +db.car.create({ data: { make: '', model: '', year: '', isElectric: '' }, select: { id: true } }).execute() +db.car.update({ where: { id: '' }, data: { make: '' }, select: { id: true } }).execute() +db.car.delete({ where: { id: '' } }).execute() \`\`\` ## Examples @@ -4369,7 +4369,7 @@ const items = await db.car.findMany({ \`\`\`typescript const item = await db.car.create({ - data: { make: 'value', model: 'value', year: 'value', isElectric: 'value' }, + data: { make: '', model: '', year: '', isElectric: '' }, select: { id: true } }).execute(); \`\`\` @@ -4387,10 +4387,10 @@ ORM operations for Driver records \`\`\`typescript db.driver.findMany({ select: { id: true } }).execute() -db.driver.findOne({ id: '', select: { id: true } }).execute() -db.driver.create({ data: { name: '', licenseNumber: '' }, select: { id: true } }).execute() -db.driver.update({ where: { id: '' }, data: { name: '' }, select: { id: true } }).execute() -db.driver.delete({ where: { id: '' } }).execute() +db.driver.findOne({ id: '', select: { id: true } }).execute() +db.driver.create({ data: { name: '', licenseNumber: '' }, select: { id: true } }).execute() +db.driver.update({ where: { id: '' }, data: { name: '' }, select: { id: true } }).execute() +db.driver.delete({ where: { id: '' } }).execute() \`\`\` ## Examples @@ -4407,7 +4407,7 @@ const items = await db.driver.findMany({ \`\`\`typescript const item = await db.driver.create({ - data: { name: 'value', licenseNumber: 'value' }, + data: { name: '', licenseNumber: '' }, select: { id: true } }).execute(); \`\`\` @@ -4447,7 +4447,7 @@ Authenticate a user ## Usage \`\`\`typescript -db.mutation.login({ email: '', password: '' }).execute() +db.mutation.login({ email: '', password: '' }).execute() \`\`\` ## Examples @@ -4455,7 +4455,7 @@ db.mutation.login({ email: '', password: '' }).execute() ### Run login \`\`\`typescript -const result = await db.mutation.login({ email: '', password: '' }).execute(); +const result = await db.mutation.login({ email: '', password: '' }).execute(); \`\`\` " `; @@ -4480,10 +4480,10 @@ import { db } from './orm'; // Available models: car, driver db..findMany({ select: { id: true } }).execute() -db..findOne({ id: '', select: { id: true } }).execute() +db..findOne({ id: '', select: { id: true } }).execute() db..create({ data: { ... }, select: { id: true } }).execute() -db..update({ where: { id: '' }, data: { ... }, select: { id: true } }).execute() -db..delete({ where: { id: '' } }).execute() +db..update({ where: { id: '' }, data: { ... }, select: { id: true } }).execute() +db..delete({ where: { id: '' } }).execute() \`\`\` ## Examples diff --git a/graphql/codegen/src/core/codegen/cli/docs-generator.ts b/graphql/codegen/src/core/codegen/cli/docs-generator.ts index ea2c4eb6d..33ef82fb8 100644 --- a/graphql/codegen/src/core/codegen/cli/docs-generator.ts +++ b/graphql/codegen/src/core/codegen/cli/docs-generator.ts @@ -5,6 +5,7 @@ import { flattenArgs, flattenedArgsToFlags, cleanTypeName, + fieldPlaceholder, getEditableFields, getSearchFields, categorizeSpecialFields, @@ -621,8 +622,8 @@ export function generateSkills( const editableFields = getEditableFields(table, registry); const defaultFields = getFieldsWithDefaults(table, registry); const createFlags = [ - ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} `), - ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} ]`), + ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} <${cleanTypeName(f.type.gqlType)}>`), + ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} <${cleanTypeName(f.type.gqlType)}>]`), ].join(' '); referenceNames.push(kebab); @@ -640,10 +641,10 @@ export function generateSkills( description: skillSpecialDesc, usage: [ `${toolName} ${kebab} list`, - `${toolName} ${kebab} get --${pk.name} `, + `${toolName} ${kebab} get --${pk.name} <${cleanTypeName(pk.gqlType)}>`, `${toolName} ${kebab} create ${createFlags}`, - `${toolName} ${kebab} update --${pk.name} ${editableFields.map((f) => `[--${f.name} ]`).join(' ')}`, - `${toolName} ${kebab} delete --${pk.name} `, + `${toolName} ${kebab} update --${pk.name} <${cleanTypeName(pk.gqlType)}> ${editableFields.map((f) => `[--${f.name} <${cleanTypeName(f.type.gqlType)}>]`).join(' ')}`, + `${toolName} ${kebab} delete --${pk.name} <${cleanTypeName(pk.gqlType)}>`, ], examples: [ { @@ -1519,8 +1520,8 @@ export function generateMultiTargetSkills( const editableFields = getEditableFields(table, registry); const defaultFields = getFieldsWithDefaults(table, registry); const createFlags = [ - ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} `), - ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} ]`), + ...editableFields.filter((f) => !defaultFields.has(f.name)).map((f) => `--${f.name} <${cleanTypeName(f.type.gqlType)}>`), + ...editableFields.filter((f) => defaultFields.has(f.name)).map((f) => `[--${f.name} <${cleanTypeName(f.type.gqlType)}>]`), ].join(' '); const cmd = `${tgt.name}:${kebab}`; @@ -1539,10 +1540,10 @@ export function generateMultiTargetSkills( description: mtSkillSpecialDesc, usage: [ `${toolName} ${cmd} list`, - `${toolName} ${cmd} get --${pk.name} `, + `${toolName} ${cmd} get --${pk.name} <${cleanTypeName(pk.gqlType)}>`, `${toolName} ${cmd} create ${createFlags}`, - `${toolName} ${cmd} update --${pk.name} ${editableFields.map((f) => `[--${f.name} ]`).join(' ')}`, - `${toolName} ${cmd} delete --${pk.name} `, + `${toolName} ${cmd} update --${pk.name} <${cleanTypeName(pk.gqlType)}> ${editableFields.map((f) => `[--${f.name} <${cleanTypeName(f.type.gqlType)}>]`).join(' ')}`, + `${toolName} ${cmd} delete --${pk.name} <${cleanTypeName(pk.gqlType)}>`, ], examples: [ { diff --git a/graphql/codegen/src/core/codegen/docs-utils.ts b/graphql/codegen/src/core/codegen/docs-utils.ts index 786314fde..adb0eb0a9 100644 --- a/graphql/codegen/src/core/codegen/docs-utils.ts +++ b/graphql/codegen/src/core/codegen/docs-utils.ts @@ -421,10 +421,63 @@ export function flattenArgs(args: CleanArgument[], registry?: TypeRegistry): Fla /** * Build CLI flags string from flattened args. - * e.g. '--input.email --input.password ' + * e.g. '--input.email --input.password ' */ export function flattenedArgsToFlags(flatArgs: FlattenedArg[]): string { - return flatArgs.map((a) => `--${a.flag} `).join(' '); + return flatArgs.map((a) => `--${a.flag} <${a.type}>`).join(' '); +} + +// --------------------------------------------------------------------------- +// Type-aware placeholder helpers for code examples +// --------------------------------------------------------------------------- + +/** + * Generate a type-aware placeholder for a table field value in code examples. + * Returns a quoted placeholder string, e.g. `''`, `''`, `''`. + */ +export function fieldPlaceholder(field: CleanField): string { + return `'<${cleanTypeName(field.type.gqlType)}>'`; +} + +/** + * Generate a type-aware placeholder for a primary key value in code examples. + * PrimaryKeyField has `gqlType` directly (not nested under `.type`). + */ +export function pkPlaceholder(pk: { gqlType: string }): string { + return `'<${cleanTypeName(pk.gqlType)}>'`; +} + +/** + * Generate a type-aware placeholder for an operation argument value. + * + * - Scalar args: `''` + * - INPUT_OBJECT with resolvable fields (up to a limit): `{ email: '', password: '' }` + * - INPUT_OBJECT without resolvable fields: `''` + * + * The result is a ready-to-embed JS expression (quotes included for scalars). + */ +export function argPlaceholder(arg: CleanArgument, registry?: TypeRegistry): string { + const { inner } = unwrapNonNull(arg.type); + + if (inner.kind === 'INPUT_OBJECT') { + const fields = resolveInputFields(inner, registry); + if (fields && fields.length > 0) { + const meaningful = fields.filter((f) => f.name !== 'clientMutationId'); + if (meaningful.length > 0 && meaningful.length <= 5) { + const parts = meaningful.map((f) => { + const typeName = cleanTypeName(getScalarTypeName(f.type)); + return `${f.name}: '<${typeName}>'`; + }); + return '{ ' + parts.join(', ') + ' }'; + } + } + if (inner.name) { + return `'<${cleanTypeName(inner.name)}>'`; + } + } + + const typeName = cleanTypeName(getScalarTypeName(arg.type)); + return `'<${typeName}>'`; } export function gqlTypeToJsonSchemaType(gqlType: string): string { diff --git a/graphql/codegen/src/core/codegen/hooks-docs-generator.ts b/graphql/codegen/src/core/codegen/hooks-docs-generator.ts index 4d455973d..5e16f420a 100644 --- a/graphql/codegen/src/core/codegen/hooks-docs-generator.ts +++ b/graphql/codegen/src/core/codegen/hooks-docs-generator.ts @@ -1,10 +1,13 @@ import { toKebabCase } from 'komoji'; -import type { CleanOperation, CleanTable } from '../../types/schema'; +import type { CleanOperation, CleanTable, TypeRegistry } from '../../types/schema'; import { buildSkillFile, buildSkillReference, formatArgType, + fieldPlaceholder, + pkPlaceholder, + argPlaceholder, getReadmeHeader, getReadmeFooter, gqlTypeToJsonSchemaType, @@ -35,6 +38,7 @@ function getCustomHookName(op: CleanOperation): string { export function generateHooksReadme( tables: CleanTable[], customOperations: CleanOperation[], + registry?: TypeRegistry, ): GeneratedDocFile { const lines: string[] = []; @@ -122,7 +126,7 @@ export function generateHooksReadme( lines.push( `const { data: item } = ${getSingleQueryHookName(table)}({`, ); - lines.push(` ${pk.name}: '',`); + lines.push(` ${pk.name}: ${pkPlaceholder(pk)},`); lines.push( ` selection: { fields: { ${scalarFields.map((f) => `${f.name}: true`).join(', ')} } },`, ); @@ -139,7 +143,7 @@ export function generateHooksReadme( ); lines.push('});'); lines.push( - `create({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ''`).join(', ')} });`, + `create({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} });`, ); lines.push('```'); lines.push(''); @@ -372,6 +376,7 @@ export function generateHooksSkills( tables: CleanTable[], customOperations: CleanOperation[], targetName: string, + registry?: TypeRegistry, ): GeneratedDocFile[] { const files: GeneratedDocFile[] = []; const skillName = `hooks-${targetName}`; @@ -399,7 +404,7 @@ export function generateHooksSkills( `${getListQueryHookName(table)}({ selection: { fields: { ${selectFields} } } })`, ...(hasValidPrimaryKey(table) ? [ - `${getSingleQueryHookName(table)}({ ${pk.name}: '', selection: { fields: { ${selectFields} } } })`, + `${getSingleQueryHookName(table)}({ ${pk.name}: ${pkPlaceholder(pk)}, selection: { fields: { ${selectFields} } } })`, ] : []), `${getCreateMutationHookName(table)}({ selection: { fields: { ${pk.name}: true } } })`, @@ -425,7 +430,7 @@ export function generateHooksSkills( `const { mutate } = ${getCreateMutationHookName(table)}({`, ` selection: { fields: { ${pk.name}: true } },`, '});', - `mutate({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ''`).join(', ')} });`, + `mutate({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} });`, ], }, ], @@ -438,7 +443,7 @@ export function generateHooksSkills( const hookName = getCustomHookName(op); const callArgs = op.args.length > 0 - ? `{ ${op.args.map((a) => `${a.name}: ''`).join(', ')} }` + ? `{ ${op.args.map((a) => `${a.name}: ${argPlaceholder(a, registry)}`).join(', ')} }` : ''; const refName = toKebabCase(op.name); diff --git a/graphql/codegen/src/core/codegen/orm/docs-generator.ts b/graphql/codegen/src/core/codegen/orm/docs-generator.ts index 7e6bfae7a..730ab3d42 100644 --- a/graphql/codegen/src/core/codegen/orm/docs-generator.ts +++ b/graphql/codegen/src/core/codegen/orm/docs-generator.ts @@ -1,10 +1,13 @@ import { toKebabCase } from 'komoji'; -import type { CleanOperation, CleanTable } from '../../../types/schema'; +import type { CleanOperation, CleanTable, TypeRegistry } from '../../../types/schema'; import { buildSkillFile, buildSkillReference, formatArgType, + fieldPlaceholder, + pkPlaceholder, + argPlaceholder, getEditableFields, categorizeSpecialFields, buildSpecialFieldsMarkdown, @@ -24,6 +27,7 @@ import { export function generateOrmReadme( tables: CleanTable[], customOperations: CleanOperation[], + registry?: TypeRegistry, ): GeneratedDocFile { const lines: string[] = []; @@ -87,22 +91,22 @@ export function generateOrmReadme( lines.push(''); lines.push(`// Get one by ${pk.name}`); lines.push( - `const item = await db.${singularName}.findOne({ ${pk.name}: '', select: { ${scalarFields.map((f) => `${f.name}: true`).join(', ')} } }).execute();`, + `const item = await db.${singularName}.findOne({ ${pk.name}: ${pkPlaceholder(pk)}, select: { ${scalarFields.map((f) => `${f.name}: true`).join(', ')} } }).execute();`, ); lines.push(''); lines.push(`// Create`); lines.push( - `const created = await db.${singularName}.create({ data: { ${editableFields.map((f) => `${f.name}: ''`).join(', ')} }, select: { ${pk.name}: true } }).execute();`, + `const created = await db.${singularName}.create({ data: { ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} }, select: { ${pk.name}: true } }).execute();`, ); lines.push(''); lines.push(`// Update`); lines.push( - `const updated = await db.${singularName}.update({ where: { ${pk.name}: '' }, data: { ${editableFields[0]?.name || 'field'}: '' }, select: { ${pk.name}: true } }).execute();`, + `const updated = await db.${singularName}.update({ where: { ${pk.name}: ${pkPlaceholder(pk)} }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? fieldPlaceholder(editableFields[0]) : "''"} }, select: { ${pk.name}: true } }).execute();`, ); lines.push(''); lines.push(`// Delete`); lines.push( - `const deleted = await db.${singularName}.delete({ where: { ${pk.name}: '' } }).execute();`, + `const deleted = await db.${singularName}.delete({ where: { ${pk.name}: ${pkPlaceholder(pk)} } }).execute();`, ); lines.push('```'); lines.push(''); @@ -132,7 +136,7 @@ export function generateOrmReadme( lines.push(''); lines.push('```typescript'); lines.push( - `const result = await db.${accessor}.${op.name}({ ${op.args.map((a) => `${a.name}: ''`).join(', ')} }).execute();`, + `const result = await db.${accessor}.${op.name}({ ${op.args.map((a) => `${a.name}: ${argPlaceholder(a, registry)}`).join(', ')} }).execute();`, ); lines.push('```'); } else { @@ -358,6 +362,7 @@ export function generateOrmSkills( tables: CleanTable[], customOperations: CleanOperation[], targetName: string, + registry?: TypeRegistry, ): GeneratedDocFile[] { const files: GeneratedDocFile[] = []; const skillName = `orm-${targetName}`; @@ -388,10 +393,10 @@ export function generateOrmSkills( language: 'typescript', usage: [ `db.${modelName}.findMany({ select: { id: true } }).execute()`, - `db.${modelName}.findOne({ ${pk.name}: '', select: { id: true } }).execute()`, - `db.${modelName}.create({ data: { ${editableFields.map((f) => `${f.name}: ''`).join(', ')} }, select: { id: true } }).execute()`, - `db.${modelName}.update({ where: { ${pk.name}: '' }, data: { ${editableFields[0]?.name || 'field'}: '' }, select: { id: true } }).execute()`, - `db.${modelName}.delete({ where: { ${pk.name}: '' } }).execute()`, + `db.${modelName}.findOne({ ${pk.name}: ${pkPlaceholder(pk)}, select: { id: true } }).execute()`, + `db.${modelName}.create({ data: { ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} }, select: { id: true } }).execute()`, + `db.${modelName}.update({ where: { ${pk.name}: ${pkPlaceholder(pk)} }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? fieldPlaceholder(editableFields[0]) : "''"} }, select: { id: true } }).execute()`, + `db.${modelName}.delete({ where: { ${pk.name}: ${pkPlaceholder(pk)} } }).execute()`, ], examples: [ { @@ -406,7 +411,7 @@ export function generateOrmSkills( description: `Create a ${singularName}`, code: [ `const item = await db.${modelName}.create({`, - ` data: { ${editableFields.map((f) => `${f.name}: 'value'`).join(', ')} },`, + ` data: { ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} },`, ` select: { ${pk.name}: true }`, '}).execute();', ], @@ -421,7 +426,7 @@ export function generateOrmSkills( const accessor = op.kind === 'query' ? 'query' : 'mutation'; const callArgs = op.args.length > 0 - ? `{ ${op.args.map((a) => `${a.name}: ''`).join(', ')} }` + ? `{ ${op.args.map((a) => `${a.name}: ${argPlaceholder(a, registry)}`).join(', ')} }` : ''; const refName = toKebabCase(op.name); @@ -459,10 +464,10 @@ export function generateOrmSkills( '', `// Available models: ${tableNames.slice(0, 8).join(', ')}${tableNames.length > 8 ? ', ...' : ''}`, `db..findMany({ select: { id: true } }).execute()`, - `db..findOne({ id: '', select: { id: true } }).execute()`, + `db..findOne({ id: '', select: { id: true } }).execute()`, `db..create({ data: { ... }, select: { id: true } }).execute()`, - `db..update({ where: { id: '' }, data: { ... }, select: { id: true } }).execute()`, - `db..delete({ where: { id: '' } }).execute()`, + `db..update({ where: { id: '' }, data: { ... }, select: { id: true } }).execute()`, + `db..delete({ where: { id: '' } }).execute()`, ], examples: [ { diff --git a/graphql/codegen/src/core/generate.ts b/graphql/codegen/src/core/generate.ts index bdd4f9fdb..20dde7156 100644 --- a/graphql/codegen/src/core/generate.ts +++ b/graphql/codegen/src/core/generate.ts @@ -348,7 +348,7 @@ export async function generate( if (runOrm) { if (docsConfig.readme) { - const readme = generateOrmReadme(tables, allCustomOps); + const readme = generateOrmReadme(tables, allCustomOps, customOperations.typeRegistry); filesToWrite.push({ path: path.posix.join('orm', readme.fileName), content: readme.content }); } if (docsConfig.agents) { @@ -359,7 +359,7 @@ export async function generate( allMcpTools.push(...getOrmMcpTools(tables, allCustomOps)); } if (docsConfig.skills) { - for (const skill of generateOrmSkills(tables, allCustomOps, targetName)) { + for (const skill of generateOrmSkills(tables, allCustomOps, targetName, customOperations.typeRegistry)) { skillsToWrite.push({ path: skill.fileName, content: skill.content }); } } @@ -367,7 +367,7 @@ export async function generate( if (runReactQuery) { if (docsConfig.readme) { - const readme = generateHooksReadme(tables, allCustomOps); + const readme = generateHooksReadme(tables, allCustomOps, customOperations.typeRegistry); filesToWrite.push({ path: path.posix.join('hooks', readme.fileName), content: readme.content }); } if (docsConfig.agents) { @@ -378,7 +378,7 @@ export async function generate( allMcpTools.push(...getHooksMcpTools(tables, allCustomOps)); } if (docsConfig.skills) { - for (const skill of generateHooksSkills(tables, allCustomOps, targetName)) { + for (const skill of generateHooksSkills(tables, allCustomOps, targetName, customOperations.typeRegistry)) { skillsToWrite.push({ path: skill.fileName, content: skill.content }); } }