Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,7 @@ import { useCarsQuery } from './hooks';

// Query hooks: use<Model>Query, use<Model>sQuery
// Mutation hooks: useCreate<Model>Mutation, useUpdate<Model>Mutation, useDelete<Model>Mutation
// Bulk mutation hooks (when enabled): useBulkCreate<Model>Mutation, useBulkUpsert<Model>Mutation, etc.

const { data, isLoading } = useCarsQuery({
selection: { fields: { id: true } },
Expand Down
28 changes: 28 additions & 0 deletions graphql/codegen/src/core/codegen/cli/docs-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ export function generateReadme(
lines.push(`| \`create\` | Create a new ${singularName} |`);
lines.push(`| \`update\` | Update an existing ${singularName} |`);
lines.push(`| \`delete\` | Delete a ${singularName} |`);
if (table.query?.bulkInsert) {
lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
}
if (table.query?.bulkUpsert) {
lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
}
if (table.query?.bulkUpdate) {
lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
}
if (table.query?.bulkDelete) {
lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
}
lines.push('');
lines.push('**Fields:**');
lines.push('');
Expand Down Expand Up @@ -465,6 +477,10 @@ export function generateSkills(
`${toolName} ${kebab} create ${createFlags}`,
`${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)}>`,
...(table.query?.bulkInsert ? [`${toolName} ${kebab} bulk-create --data '<JSON array>'`] : []),
...(table.query?.bulkUpsert ? [`${toolName} ${kebab} bulk-upsert --data '<JSON array>'`] : []),
...(table.query?.bulkUpdate ? [`${toolName} ${kebab} bulk-update --where '<JSON>' --data '<JSON>'`] : []),
...(table.query?.bulkDelete ? [`${toolName} ${kebab} bulk-delete --where '<JSON>'`] : []),
],
examples: [
{
Expand Down Expand Up @@ -797,6 +813,18 @@ export function generateMultiTargetReadme(
lines.push(`| \`create\` | Create a new ${singularName} |`);
lines.push(`| \`update\` | Update an existing ${singularName} |`);
lines.push(`| \`delete\` | Delete a ${singularName} |`);
if (table.query?.bulkInsert) {
lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
}
if (table.query?.bulkUpsert) {
lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
}
if (table.query?.bulkUpdate) {
lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
}
if (table.query?.bulkDelete) {
lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
}
lines.push('');
lines.push('**Fields:**');
lines.push('');
Expand Down
44 changes: 44 additions & 0 deletions graphql/codegen/src/core/codegen/hooks-docs-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import {
getCreateMutationHookName,
getUpdateMutationHookName,
getDeleteMutationHookName,
getBulkCreateMutationHookName,
getBulkUpsertMutationHookName,
getBulkUpdateMutationHookName,
getBulkDeleteMutationHookName,
hasValidPrimaryKey,
ucFirst,
lcFirst,
Expand Down Expand Up @@ -91,6 +95,26 @@ export function generateHooksReadme(
`| \`${getDeleteMutationHookName(table)}\` | Mutation | ${table.description || `Delete a ${singularName}`} |`,
);
}
if (table.query?.bulkInsert) {
lines.push(
`| \`${getBulkCreateMutationHookName(table)}\` | Mutation | Bulk create ${pluralName} |`,
);
}
if (table.query?.bulkUpsert) {
lines.push(
`| \`${getBulkUpsertMutationHookName(table)}\` | Mutation | Bulk upsert ${pluralName} |`,
);
}
if (table.query?.bulkUpdate) {
lines.push(
`| \`${getBulkUpdateMutationHookName(table)}\` | Mutation | Bulk update ${pluralName} |`,
);
}
if (table.query?.bulkDelete) {
lines.push(
`| \`${getBulkDeleteMutationHookName(table)}\` | Mutation | Bulk delete ${pluralName} |`,
);
}
}
for (const op of customOperations) {
lines.push(
Expand Down Expand Up @@ -145,6 +169,20 @@ export function generateHooksReadme(
lines.push(
`create({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} });`,
);
if (table.query?.bulkInsert) {
lines.push('');
lines.push(`// Bulk create ${pluralName}`);
lines.push(
`const { mutate: bulkCreate } = ${getBulkCreateMutationHookName(table)}({`,
);
lines.push(
` selection: { fields: { ${pk.name}: true } },`,
);
lines.push('});');
lines.push(
`bulkCreate({ data: [{ ${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('');
}
Expand Down Expand Up @@ -226,6 +264,7 @@ export function generateHooksAgentsDocs(
lines.push('');
lines.push('- Query hooks: `use<PluralName>Query`, `use<SingularName>Query`');
lines.push('- Mutation hooks: `useCreate<Name>Mutation`, `useUpdate<Name>Mutation`, `useDelete<Name>Mutation`');
lines.push('- Bulk mutation hooks (when enabled): `useBulkCreate<Name>Mutation`, `useBulkUpsert<Name>Mutation`, `useBulkUpdate<Name>Mutation`, `useBulkDelete<Name>Mutation`');
lines.push('- All hooks accept a `selection` parameter to pick fields');
lines.push('');

Expand Down Expand Up @@ -282,6 +321,10 @@ export function generateHooksSkills(
`${getDeleteMutationHookName(table)}({})`,
]
: []),
...(table.query?.bulkInsert ? [`${getBulkCreateMutationHookName(table)}() — bulk create with data array`] : []),
...(table.query?.bulkUpsert ? [`${getBulkUpsertMutationHookName(table)}() — bulk upsert with onConflict`] : []),
...(table.query?.bulkUpdate ? [`${getBulkUpdateMutationHookName(table)}() — bulk update with where + data`] : []),
...(table.query?.bulkDelete ? [`${getBulkDeleteMutationHookName(table)}() — bulk delete with where`] : []),
],
examples: [
{
Expand Down Expand Up @@ -365,6 +408,7 @@ export function generateHooksSkills(
'',
`// Query hooks: use<Model>Query, use<Model>sQuery`,
`// Mutation hooks: useCreate<Model>Mutation, useUpdate<Model>Mutation, useDelete<Model>Mutation`,
`// Bulk mutation hooks (when enabled): useBulkCreate<Model>Mutation, useBulkUpsert<Model>Mutation, etc.`,
'',
`const { data, isLoading } = ${hookExamples[0] || 'useModelQuery'}({`,
` selection: { fields: { id: true } },`,
Expand Down
61 changes: 60 additions & 1 deletion graphql/codegen/src/core/codegen/orm/docs-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ export function generateOrmReadme(
lines.push('|-------|------------|');
for (const table of tables) {
const { singularName } = getTableNames(table);
const bulkOps: string[] = [];
if (table.query?.bulkInsert) bulkOps.push('bulkCreate');
if (table.query?.bulkUpsert) bulkOps.push('bulkUpsert');
if (table.query?.bulkUpdate) bulkOps.push('bulkUpdate');
if (table.query?.bulkDelete) bulkOps.push('bulkDelete');
const ops = ['findMany', 'findOne', 'create', 'update', 'delete', ...bulkOps].join(', ');
lines.push(
`| \`${singularName}\` | findMany, findOne, create, update, delete |`,
`| \`${singularName}\` | ${ops} |`,
);
}
lines.push('');
Expand Down Expand Up @@ -108,6 +114,34 @@ export function generateOrmReadme(
lines.push(
`const deleted = await db.${singularName}.delete({ where: { ${pk.name}: ${pkPlaceholder(pk)} } }).execute();`,
);
if (table.query?.bulkInsert) {
lines.push('');
lines.push(`// Bulk Create`);
lines.push(
`const bulkCreated = await db.${singularName}.bulkCreate({ data: [{ ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} }], select: { ${pk.name}: true } }).execute();`,
);
}
if (table.query?.bulkUpsert) {
lines.push('');
lines.push(`// Bulk Upsert`);
lines.push(
`const bulkUpserted = await db.${singularName}.bulkUpsert({ data: [{ ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} }], onConflict: { constraint: 'PRIMARY_KEY', action: 'UPDATE' }, select: { ${pk.name}: true } }).execute();`,
);
}
if (table.query?.bulkUpdate) {
lines.push('');
lines.push(`// Bulk Update`);
lines.push(
`const bulkUpdated = await db.${singularName}.bulkUpdate({ where: { ${editableFields[0]?.name || 'field'}: { equalTo: ${editableFields[0] ? fieldPlaceholder(editableFields[0]) : "'<String>'"} } }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? fieldPlaceholder(editableFields[0]) : "'<String>'"} }, select: { ${pk.name}: true } }).execute();`,
);
}
if (table.query?.bulkDelete) {
lines.push('');
lines.push(`// Bulk Delete`);
lines.push(
`const bulkDeleted = await db.${singularName}.bulkDelete({ where: { ${pk.name}: { equalTo: ${pkPlaceholder(pk)} } } }).execute();`,
);
}
lines.push('```');
lines.push('');
const ormSpecialGroups = categorizeSpecialFields(table);
Expand Down Expand Up @@ -227,6 +261,7 @@ export function generateOrmAgentsDocs(
lines.push('');
lines.push('- Access models via `db.<ModelName>` (e.g. `db.User`)');
lines.push('- CRUD methods: `findMany`, `findOne`, `create`, `update`, `delete`');
lines.push('- Bulk methods (when enabled via smart tags): `bulkCreate`, `bulkUpsert`, `bulkUpdate`, `bulkDelete`');
lines.push('- Chain `.execute().unwrap()` to run and throw on error, or `.execute()` alone for discriminated union result');
lines.push('- Custom operations via `db.query.<name>` or `db.mutation.<name>`');
lines.push('');
Expand Down Expand Up @@ -269,6 +304,20 @@ export function generateOrmSkills(
ormSkillSpecialGroups.map((g) => `**${g.label}:** ${g.fields.map((f) => `\`${f.name}\``).join(', ')}\n${g.description}`).join('\n\n')
: ormSkillBaseDesc;

const bulkUsageLines: string[] = [];
if (table.query?.bulkInsert) {
bulkUsageLines.push(`db.${modelName}.bulkCreate({ data: [...], select: { id: true } }).execute()`);
}
if (table.query?.bulkUpsert) {
bulkUsageLines.push(`db.${modelName}.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`);
}
if (table.query?.bulkUpdate) {
bulkUsageLines.push(`db.${modelName}.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`);
}
if (table.query?.bulkDelete) {
bulkUsageLines.push(`db.${modelName}.bulkDelete({ where: {...} }).execute()`);
}

files.push({
fileName: `${skillName}/references/${refName}.md`,
content: buildSkillReference({
Expand All @@ -281,6 +330,7 @@ export function generateOrmSkills(
`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]) : "'<String>'"} }, select: { id: true } }).execute()`,
`db.${modelName}.delete({ where: { ${pk.name}: ${pkPlaceholder(pk)} } }).execute()`,
...bulkUsageLines,
],
examples: [
{
Expand Down Expand Up @@ -335,6 +385,7 @@ export function generateOrmSkills(

// Generate the overview SKILL.md
const tableNames = tables.map((t) => lcFirst(getTableNames(t).singularName));
const hasBulkTables = tables.some((t) => t.query?.bulkInsert || t.query?.bulkUpsert || t.query?.bulkUpdate || t.query?.bulkDelete);
files.push({
fileName: `${skillName}/SKILL.md`,
content: buildSkillFile(
Expand All @@ -352,6 +403,14 @@ export function generateOrmSkills(
`db.<model>.create({ data: { ... }, select: { id: true } }).execute()`,
`db.<model>.update({ where: { id: '<UUID>' }, data: { ... }, select: { id: true } }).execute()`,
`db.<model>.delete({ where: { id: '<UUID>' } }).execute()`,
...(hasBulkTables ? [
'',
`// Bulk operations (on tables with @behavior +bulkInsert/+bulkUpsert/+bulkUpdate/+bulkDelete)`,
`db.<model>.bulkCreate({ data: [...], select: { id: true } }).execute()`,
`db.<model>.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`,
`db.<model>.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`,
`db.<model>.bulkDelete({ where: {...} }).execute()`,
] : []),
],
examples: [
{
Expand Down
Loading