@constructive-io/graphql-codegen 4.41.1 → 4.41.2

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.
@@ -111,6 +111,18 @@ function generateReadme(tables, customOperations, toolName, registry) {
111
111
  lines.push(`| \`create\` | Create a new ${singularName} |`);
112
112
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
113
113
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
114
+ if (table.query?.bulkInsert) {
115
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
116
+ }
117
+ if (table.query?.bulkUpsert) {
118
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
119
+ }
120
+ if (table.query?.bulkUpdate) {
121
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
122
+ }
123
+ if (table.query?.bulkDelete) {
124
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
125
+ }
114
126
  lines.push('');
115
127
  lines.push('**Fields:**');
116
128
  lines.push('');
@@ -403,6 +415,10 @@ function generateSkills(tables, customOperations, toolName, targetName, registry
403
415
  `${toolName} ${kebab} create ${createFlags}`,
404
416
  `${toolName} ${kebab} update --${pk.name} <${(0, docs_utils_1.cleanTypeName)(pk.gqlType)}> ${editableFields.map((f) => `[--${f.name} <${(0, docs_utils_1.cleanTypeName)(f.type.gqlType)}>]`).join(' ')}`,
405
417
  `${toolName} ${kebab} delete --${pk.name} <${(0, docs_utils_1.cleanTypeName)(pk.gqlType)}>`,
418
+ ...(table.query?.bulkInsert ? [`${toolName} ${kebab} bulk-create --data '<JSON array>'`] : []),
419
+ ...(table.query?.bulkUpsert ? [`${toolName} ${kebab} bulk-upsert --data '<JSON array>'`] : []),
420
+ ...(table.query?.bulkUpdate ? [`${toolName} ${kebab} bulk-update --where '<JSON>' --data '<JSON>'`] : []),
421
+ ...(table.query?.bulkDelete ? [`${toolName} ${kebab} bulk-delete --where '<JSON>'`] : []),
406
422
  ],
407
423
  examples: [
408
424
  {
@@ -694,6 +710,18 @@ function generateMultiTargetReadme(input) {
694
710
  lines.push(`| \`create\` | Create a new ${singularName} |`);
695
711
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
696
712
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
713
+ if (table.query?.bulkInsert) {
714
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
715
+ }
716
+ if (table.query?.bulkUpsert) {
717
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
718
+ }
719
+ if (table.query?.bulkUpdate) {
720
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
721
+ }
722
+ if (table.query?.bulkDelete) {
723
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
724
+ }
697
725
  lines.push('');
698
726
  lines.push('**Fields:**');
699
727
  lines.push('');
@@ -52,6 +52,18 @@ function generateHooksReadme(tables, customOperations, registry) {
52
52
  lines.push(`| \`${(0, utils_1.getUpdateMutationHookName)(table)}\` | Mutation | ${table.description || `Update a ${singularName}`} |`);
53
53
  lines.push(`| \`${(0, utils_1.getDeleteMutationHookName)(table)}\` | Mutation | ${table.description || `Delete a ${singularName}`} |`);
54
54
  }
55
+ if (table.query?.bulkInsert) {
56
+ lines.push(`| \`${(0, utils_1.getBulkCreateMutationHookName)(table)}\` | Mutation | Bulk create ${pluralName} |`);
57
+ }
58
+ if (table.query?.bulkUpsert) {
59
+ lines.push(`| \`${(0, utils_1.getBulkUpsertMutationHookName)(table)}\` | Mutation | Bulk upsert ${pluralName} |`);
60
+ }
61
+ if (table.query?.bulkUpdate) {
62
+ lines.push(`| \`${(0, utils_1.getBulkUpdateMutationHookName)(table)}\` | Mutation | Bulk update ${pluralName} |`);
63
+ }
64
+ if (table.query?.bulkDelete) {
65
+ lines.push(`| \`${(0, utils_1.getBulkDeleteMutationHookName)(table)}\` | Mutation | Bulk delete ${pluralName} |`);
66
+ }
55
67
  }
56
68
  for (const op of customOperations) {
57
69
  lines.push(`| \`${getCustomHookName(op)}\` | ${(0, utils_1.ucFirst)(op.kind)} | ${op.description || op.name} |`);
@@ -85,6 +97,14 @@ function generateHooksReadme(tables, customOperations, registry) {
85
97
  lines.push(` selection: { fields: { ${pk.name}: true } },`);
86
98
  lines.push('});');
87
99
  lines.push(`create({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} });`);
100
+ if (table.query?.bulkInsert) {
101
+ lines.push('');
102
+ lines.push(`// Bulk create ${pluralName}`);
103
+ lines.push(`const { mutate: bulkCreate } = ${(0, utils_1.getBulkCreateMutationHookName)(table)}({`);
104
+ lines.push(` selection: { fields: { ${pk.name}: true } },`);
105
+ lines.push('});');
106
+ lines.push(`bulkCreate({ data: [{ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }] });`);
107
+ }
88
108
  lines.push('```');
89
109
  lines.push('');
90
110
  }
@@ -155,6 +175,7 @@ function generateHooksAgentsDocs(tables, customOperations) {
155
175
  lines.push('');
156
176
  lines.push('- Query hooks: `use<PluralName>Query`, `use<SingularName>Query`');
157
177
  lines.push('- Mutation hooks: `useCreate<Name>Mutation`, `useUpdate<Name>Mutation`, `useDelete<Name>Mutation`');
178
+ lines.push('- Bulk mutation hooks (when enabled): `useBulkCreate<Name>Mutation`, `useBulkUpsert<Name>Mutation`, `useBulkUpdate<Name>Mutation`, `useBulkDelete<Name>Mutation`');
158
179
  lines.push('- All hooks accept a `selection` parameter to pick fields');
159
180
  lines.push('');
160
181
  lines.push('## Boundaries');
@@ -200,6 +221,10 @@ function generateHooksSkills(tables, customOperations, targetName, registry) {
200
221
  `${(0, utils_1.getDeleteMutationHookName)(table)}({})`,
201
222
  ]
202
223
  : []),
224
+ ...(table.query?.bulkInsert ? [`${(0, utils_1.getBulkCreateMutationHookName)(table)}() — bulk create with data array`] : []),
225
+ ...(table.query?.bulkUpsert ? [`${(0, utils_1.getBulkUpsertMutationHookName)(table)}() — bulk upsert with onConflict`] : []),
226
+ ...(table.query?.bulkUpdate ? [`${(0, utils_1.getBulkUpdateMutationHookName)(table)}() — bulk update with where + data`] : []),
227
+ ...(table.query?.bulkDelete ? [`${(0, utils_1.getBulkDeleteMutationHookName)(table)}() — bulk delete with where`] : []),
203
228
  ],
204
229
  examples: [
205
230
  {
@@ -275,6 +300,7 @@ function generateHooksSkills(tables, customOperations, targetName, registry) {
275
300
  '',
276
301
  `// Query hooks: use<Model>Query, use<Model>sQuery`,
277
302
  `// Mutation hooks: useCreate<Model>Mutation, useUpdate<Model>Mutation, useDelete<Model>Mutation`,
303
+ `// Bulk mutation hooks (when enabled): useBulkCreate<Model>Mutation, useBulkUpsert<Model>Mutation, etc.`,
278
304
  '',
279
305
  `const { data, isLoading } = ${hookExamples[0] || 'useModelQuery'}({`,
280
306
  ` selection: { fields: { id: true } },`,
@@ -26,7 +26,17 @@ function generateOrmReadme(tables, customOperations, registry) {
26
26
  lines.push('|-------|------------|');
27
27
  for (const table of tables) {
28
28
  const { singularName } = (0, utils_1.getTableNames)(table);
29
- lines.push(`| \`${singularName}\` | findMany, findOne, create, update, delete |`);
29
+ const bulkOps = [];
30
+ if (table.query?.bulkInsert)
31
+ bulkOps.push('bulkCreate');
32
+ if (table.query?.bulkUpsert)
33
+ bulkOps.push('bulkUpsert');
34
+ if (table.query?.bulkUpdate)
35
+ bulkOps.push('bulkUpdate');
36
+ if (table.query?.bulkDelete)
37
+ bulkOps.push('bulkDelete');
38
+ const ops = ['findMany', 'findOne', 'create', 'update', 'delete', ...bulkOps].join(', ');
39
+ lines.push(`| \`${singularName}\` | ${ops} |`);
30
40
  }
31
41
  lines.push('');
32
42
  if (tables.length > 0) {
@@ -67,6 +77,26 @@ function generateOrmReadme(tables, customOperations, registry) {
67
77
  lines.push('');
68
78
  lines.push(`// Delete`);
69
79
  lines.push(`const deleted = await db.${singularName}.delete({ where: { ${pk.name}: ${(0, docs_utils_1.pkPlaceholder)(pk)} } }).execute();`);
80
+ if (table.query?.bulkInsert) {
81
+ lines.push('');
82
+ lines.push(`// Bulk Create`);
83
+ lines.push(`const bulkCreated = await db.${singularName}.bulkCreate({ data: [{ ${editableFields.map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }], select: { ${pk.name}: true } }).execute();`);
84
+ }
85
+ if (table.query?.bulkUpsert) {
86
+ lines.push('');
87
+ lines.push(`// Bulk Upsert`);
88
+ lines.push(`const bulkUpserted = await db.${singularName}.bulkUpsert({ data: [{ ${editableFields.map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }], onConflict: { constraint: 'PRIMARY_KEY', action: 'UPDATE' }, select: { ${pk.name}: true } }).execute();`);
89
+ }
90
+ if (table.query?.bulkUpdate) {
91
+ lines.push('');
92
+ lines.push(`// Bulk Update`);
93
+ lines.push(`const bulkUpdated = await db.${singularName}.bulkUpdate({ where: { ${editableFields[0]?.name || 'field'}: { equalTo: ${editableFields[0] ? (0, docs_utils_1.fieldPlaceholder)(editableFields[0]) : "'<String>'"} } }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? (0, docs_utils_1.fieldPlaceholder)(editableFields[0]) : "'<String>'"} }, select: { ${pk.name}: true } }).execute();`);
94
+ }
95
+ if (table.query?.bulkDelete) {
96
+ lines.push('');
97
+ lines.push(`// Bulk Delete`);
98
+ lines.push(`const bulkDeleted = await db.${singularName}.bulkDelete({ where: { ${pk.name}: { equalTo: ${(0, docs_utils_1.pkPlaceholder)(pk)} } } }).execute();`);
99
+ }
70
100
  lines.push('```');
71
101
  lines.push('');
72
102
  const ormSpecialGroups = (0, docs_utils_1.categorizeSpecialFields)(table);
@@ -170,6 +200,7 @@ function generateOrmAgentsDocs(tables, customOperations) {
170
200
  lines.push('');
171
201
  lines.push('- Access models via `db.<ModelName>` (e.g. `db.User`)');
172
202
  lines.push('- CRUD methods: `findMany`, `findOne`, `create`, `update`, `delete`');
203
+ lines.push('- Bulk methods (when enabled via smart tags): `bulkCreate`, `bulkUpsert`, `bulkUpdate`, `bulkDelete`');
173
204
  lines.push('- Chain `.execute().unwrap()` to run and throw on error, or `.execute()` alone for discriminated union result');
174
205
  lines.push('- Custom operations via `db.query.<name>` or `db.mutation.<name>`');
175
206
  lines.push('');
@@ -200,6 +231,19 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
200
231
  ? ormSkillBaseDesc + '\n\n' +
201
232
  ormSkillSpecialGroups.map((g) => `**${g.label}:** ${g.fields.map((f) => `\`${f.name}\``).join(', ')}\n${g.description}`).join('\n\n')
202
233
  : ormSkillBaseDesc;
234
+ const bulkUsageLines = [];
235
+ if (table.query?.bulkInsert) {
236
+ bulkUsageLines.push(`db.${modelName}.bulkCreate({ data: [...], select: { id: true } }).execute()`);
237
+ }
238
+ if (table.query?.bulkUpsert) {
239
+ bulkUsageLines.push(`db.${modelName}.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`);
240
+ }
241
+ if (table.query?.bulkUpdate) {
242
+ bulkUsageLines.push(`db.${modelName}.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`);
243
+ }
244
+ if (table.query?.bulkDelete) {
245
+ bulkUsageLines.push(`db.${modelName}.bulkDelete({ where: {...} }).execute()`);
246
+ }
203
247
  files.push({
204
248
  fileName: `${skillName}/references/${refName}.md`,
205
249
  content: (0, docs_utils_1.buildSkillReference)({
@@ -212,6 +256,7 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
212
256
  `db.${modelName}.create({ data: { ${editableFields.map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }, select: { id: true } }).execute()`,
213
257
  `db.${modelName}.update({ where: { ${pk.name}: ${(0, docs_utils_1.pkPlaceholder)(pk)} }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? (0, docs_utils_1.fieldPlaceholder)(editableFields[0]) : "'<String>'"} }, select: { id: true } }).execute()`,
214
258
  `db.${modelName}.delete({ where: { ${pk.name}: ${(0, docs_utils_1.pkPlaceholder)(pk)} } }).execute()`,
259
+ ...bulkUsageLines,
215
260
  ],
216
261
  examples: [
217
262
  {
@@ -261,6 +306,7 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
261
306
  }
262
307
  // Generate the overview SKILL.md
263
308
  const tableNames = tables.map((t) => (0, utils_1.lcFirst)((0, utils_1.getTableNames)(t).singularName));
309
+ const hasBulkTables = tables.some((t) => t.query?.bulkInsert || t.query?.bulkUpsert || t.query?.bulkUpdate || t.query?.bulkDelete);
264
310
  files.push({
265
311
  fileName: `${skillName}/SKILL.md`,
266
312
  content: (0, docs_utils_1.buildSkillFile)({
@@ -277,6 +323,14 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
277
323
  `db.<model>.create({ data: { ... }, select: { id: true } }).execute()`,
278
324
  `db.<model>.update({ where: { id: '<UUID>' }, data: { ... }, select: { id: true } }).execute()`,
279
325
  `db.<model>.delete({ where: { id: '<UUID>' } }).execute()`,
326
+ ...(hasBulkTables ? [
327
+ '',
328
+ `// Bulk operations (on tables with @behavior +bulkInsert/+bulkUpsert/+bulkUpdate/+bulkDelete)`,
329
+ `db.<model>.bulkCreate({ data: [...], select: { id: true } }).execute()`,
330
+ `db.<model>.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`,
331
+ `db.<model>.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`,
332
+ `db.<model>.bulkDelete({ where: {...} }).execute()`,
333
+ ] : []),
280
334
  ],
281
335
  examples: [
282
336
  {
@@ -21,7 +21,7 @@ export interface PageInfo {
21
21
  endCursor?: string | null;
22
22
  }
23
23
 
24
- export interface FindManyArgs<TSelect, TWhere, TOrderBy = never> {
24
+ export interface FindManyArgs<TSelect, TWhere, TOrderBy> {
25
25
  select?: TSelect;
26
26
  where?: TWhere;
27
27
  orderBy?: TOrderBy[];
@@ -101,6 +101,18 @@ export function generateReadme(tables, customOperations, toolName, registry) {
101
101
  lines.push(`| \`create\` | Create a new ${singularName} |`);
102
102
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
103
103
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
104
+ if (table.query?.bulkInsert) {
105
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
106
+ }
107
+ if (table.query?.bulkUpsert) {
108
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
109
+ }
110
+ if (table.query?.bulkUpdate) {
111
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
112
+ }
113
+ if (table.query?.bulkDelete) {
114
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
115
+ }
104
116
  lines.push('');
105
117
  lines.push('**Fields:**');
106
118
  lines.push('');
@@ -393,6 +405,10 @@ export function generateSkills(tables, customOperations, toolName, targetName, r
393
405
  `${toolName} ${kebab} create ${createFlags}`,
394
406
  `${toolName} ${kebab} update --${pk.name} <${cleanTypeName(pk.gqlType)}> ${editableFields.map((f) => `[--${f.name} <${cleanTypeName(f.type.gqlType)}>]`).join(' ')}`,
395
407
  `${toolName} ${kebab} delete --${pk.name} <${cleanTypeName(pk.gqlType)}>`,
408
+ ...(table.query?.bulkInsert ? [`${toolName} ${kebab} bulk-create --data '<JSON array>'`] : []),
409
+ ...(table.query?.bulkUpsert ? [`${toolName} ${kebab} bulk-upsert --data '<JSON array>'`] : []),
410
+ ...(table.query?.bulkUpdate ? [`${toolName} ${kebab} bulk-update --where '<JSON>' --data '<JSON>'`] : []),
411
+ ...(table.query?.bulkDelete ? [`${toolName} ${kebab} bulk-delete --where '<JSON>'`] : []),
396
412
  ],
397
413
  examples: [
398
414
  {
@@ -684,6 +700,18 @@ export function generateMultiTargetReadme(input) {
684
700
  lines.push(`| \`create\` | Create a new ${singularName} |`);
685
701
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
686
702
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
703
+ if (table.query?.bulkInsert) {
704
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
705
+ }
706
+ if (table.query?.bulkUpsert) {
707
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
708
+ }
709
+ if (table.query?.bulkUpdate) {
710
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
711
+ }
712
+ if (table.query?.bulkDelete) {
713
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
714
+ }
687
715
  lines.push('');
688
716
  lines.push('**Fields:**');
689
717
  lines.push('');
@@ -1,6 +1,6 @@
1
1
  import { toKebabCase } from 'inflekt';
2
2
  import { buildSkillFile, buildSkillReference, formatArgType, fieldPlaceholder, pkPlaceholder, argPlaceholder, getReadmeHeader, getReadmeFooter, } from './docs-utils';
3
- import { getTableNames, getScalarFields, getPrimaryKeyInfo, getListQueryHookName, getSingleQueryHookName, getCreateMutationHookName, getUpdateMutationHookName, getDeleteMutationHookName, hasValidPrimaryKey, ucFirst, } from './utils';
3
+ import { getTableNames, getScalarFields, getPrimaryKeyInfo, getListQueryHookName, getSingleQueryHookName, getCreateMutationHookName, getUpdateMutationHookName, getDeleteMutationHookName, getBulkCreateMutationHookName, getBulkUpsertMutationHookName, getBulkUpdateMutationHookName, getBulkDeleteMutationHookName, hasValidPrimaryKey, ucFirst, } from './utils';
4
4
  function getCustomHookName(op) {
5
5
  if (op.kind === 'query') {
6
6
  return `use${ucFirst(op.name)}Query`;
@@ -47,6 +47,18 @@ export function generateHooksReadme(tables, customOperations, registry) {
47
47
  lines.push(`| \`${getUpdateMutationHookName(table)}\` | Mutation | ${table.description || `Update a ${singularName}`} |`);
48
48
  lines.push(`| \`${getDeleteMutationHookName(table)}\` | Mutation | ${table.description || `Delete a ${singularName}`} |`);
49
49
  }
50
+ if (table.query?.bulkInsert) {
51
+ lines.push(`| \`${getBulkCreateMutationHookName(table)}\` | Mutation | Bulk create ${pluralName} |`);
52
+ }
53
+ if (table.query?.bulkUpsert) {
54
+ lines.push(`| \`${getBulkUpsertMutationHookName(table)}\` | Mutation | Bulk upsert ${pluralName} |`);
55
+ }
56
+ if (table.query?.bulkUpdate) {
57
+ lines.push(`| \`${getBulkUpdateMutationHookName(table)}\` | Mutation | Bulk update ${pluralName} |`);
58
+ }
59
+ if (table.query?.bulkDelete) {
60
+ lines.push(`| \`${getBulkDeleteMutationHookName(table)}\` | Mutation | Bulk delete ${pluralName} |`);
61
+ }
50
62
  }
51
63
  for (const op of customOperations) {
52
64
  lines.push(`| \`${getCustomHookName(op)}\` | ${ucFirst(op.kind)} | ${op.description || op.name} |`);
@@ -80,6 +92,14 @@ export function generateHooksReadme(tables, customOperations, registry) {
80
92
  lines.push(` selection: { fields: { ${pk.name}: true } },`);
81
93
  lines.push('});');
82
94
  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(', ')} });`);
95
+ if (table.query?.bulkInsert) {
96
+ lines.push('');
97
+ lines.push(`// Bulk create ${pluralName}`);
98
+ lines.push(`const { mutate: bulkCreate } = ${getBulkCreateMutationHookName(table)}({`);
99
+ lines.push(` selection: { fields: { ${pk.name}: true } },`);
100
+ lines.push('});');
101
+ 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(', ')} }] });`);
102
+ }
83
103
  lines.push('```');
84
104
  lines.push('');
85
105
  }
@@ -150,6 +170,7 @@ export function generateHooksAgentsDocs(tables, customOperations) {
150
170
  lines.push('');
151
171
  lines.push('- Query hooks: `use<PluralName>Query`, `use<SingularName>Query`');
152
172
  lines.push('- Mutation hooks: `useCreate<Name>Mutation`, `useUpdate<Name>Mutation`, `useDelete<Name>Mutation`');
173
+ lines.push('- Bulk mutation hooks (when enabled): `useBulkCreate<Name>Mutation`, `useBulkUpsert<Name>Mutation`, `useBulkUpdate<Name>Mutation`, `useBulkDelete<Name>Mutation`');
153
174
  lines.push('- All hooks accept a `selection` parameter to pick fields');
154
175
  lines.push('');
155
176
  lines.push('## Boundaries');
@@ -195,6 +216,10 @@ export function generateHooksSkills(tables, customOperations, targetName, regist
195
216
  `${getDeleteMutationHookName(table)}({})`,
196
217
  ]
197
218
  : []),
219
+ ...(table.query?.bulkInsert ? [`${getBulkCreateMutationHookName(table)}() — bulk create with data array`] : []),
220
+ ...(table.query?.bulkUpsert ? [`${getBulkUpsertMutationHookName(table)}() — bulk upsert with onConflict`] : []),
221
+ ...(table.query?.bulkUpdate ? [`${getBulkUpdateMutationHookName(table)}() — bulk update with where + data`] : []),
222
+ ...(table.query?.bulkDelete ? [`${getBulkDeleteMutationHookName(table)}() — bulk delete with where`] : []),
198
223
  ],
199
224
  examples: [
200
225
  {
@@ -270,6 +295,7 @@ export function generateHooksSkills(tables, customOperations, targetName, regist
270
295
  '',
271
296
  `// Query hooks: use<Model>Query, use<Model>sQuery`,
272
297
  `// Mutation hooks: useCreate<Model>Mutation, useUpdate<Model>Mutation, useDelete<Model>Mutation`,
298
+ `// Bulk mutation hooks (when enabled): useBulkCreate<Model>Mutation, useBulkUpsert<Model>Mutation, etc.`,
273
299
  '',
274
300
  `const { data, isLoading } = ${hookExamples[0] || 'useModelQuery'}({`,
275
301
  ` selection: { fields: { id: true } },`,
@@ -21,7 +21,17 @@ export function generateOrmReadme(tables, customOperations, registry) {
21
21
  lines.push('|-------|------------|');
22
22
  for (const table of tables) {
23
23
  const { singularName } = getTableNames(table);
24
- lines.push(`| \`${singularName}\` | findMany, findOne, create, update, delete |`);
24
+ const bulkOps = [];
25
+ if (table.query?.bulkInsert)
26
+ bulkOps.push('bulkCreate');
27
+ if (table.query?.bulkUpsert)
28
+ bulkOps.push('bulkUpsert');
29
+ if (table.query?.bulkUpdate)
30
+ bulkOps.push('bulkUpdate');
31
+ if (table.query?.bulkDelete)
32
+ bulkOps.push('bulkDelete');
33
+ const ops = ['findMany', 'findOne', 'create', 'update', 'delete', ...bulkOps].join(', ');
34
+ lines.push(`| \`${singularName}\` | ${ops} |`);
25
35
  }
26
36
  lines.push('');
27
37
  if (tables.length > 0) {
@@ -62,6 +72,26 @@ export function generateOrmReadme(tables, customOperations, registry) {
62
72
  lines.push('');
63
73
  lines.push(`// Delete`);
64
74
  lines.push(`const deleted = await db.${singularName}.delete({ where: { ${pk.name}: ${pkPlaceholder(pk)} } }).execute();`);
75
+ if (table.query?.bulkInsert) {
76
+ lines.push('');
77
+ lines.push(`// Bulk Create`);
78
+ lines.push(`const bulkCreated = await db.${singularName}.bulkCreate({ data: [{ ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} }], select: { ${pk.name}: true } }).execute();`);
79
+ }
80
+ if (table.query?.bulkUpsert) {
81
+ lines.push('');
82
+ lines.push(`// Bulk Upsert`);
83
+ 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();`);
84
+ }
85
+ if (table.query?.bulkUpdate) {
86
+ lines.push('');
87
+ lines.push(`// Bulk Update`);
88
+ 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();`);
89
+ }
90
+ if (table.query?.bulkDelete) {
91
+ lines.push('');
92
+ lines.push(`// Bulk Delete`);
93
+ lines.push(`const bulkDeleted = await db.${singularName}.bulkDelete({ where: { ${pk.name}: { equalTo: ${pkPlaceholder(pk)} } } }).execute();`);
94
+ }
65
95
  lines.push('```');
66
96
  lines.push('');
67
97
  const ormSpecialGroups = categorizeSpecialFields(table);
@@ -165,6 +195,7 @@ export function generateOrmAgentsDocs(tables, customOperations) {
165
195
  lines.push('');
166
196
  lines.push('- Access models via `db.<ModelName>` (e.g. `db.User`)');
167
197
  lines.push('- CRUD methods: `findMany`, `findOne`, `create`, `update`, `delete`');
198
+ lines.push('- Bulk methods (when enabled via smart tags): `bulkCreate`, `bulkUpsert`, `bulkUpdate`, `bulkDelete`');
168
199
  lines.push('- Chain `.execute().unwrap()` to run and throw on error, or `.execute()` alone for discriminated union result');
169
200
  lines.push('- Custom operations via `db.query.<name>` or `db.mutation.<name>`');
170
201
  lines.push('');
@@ -195,6 +226,19 @@ export function generateOrmSkills(tables, customOperations, targetName, registry
195
226
  ? ormSkillBaseDesc + '\n\n' +
196
227
  ormSkillSpecialGroups.map((g) => `**${g.label}:** ${g.fields.map((f) => `\`${f.name}\``).join(', ')}\n${g.description}`).join('\n\n')
197
228
  : ormSkillBaseDesc;
229
+ const bulkUsageLines = [];
230
+ if (table.query?.bulkInsert) {
231
+ bulkUsageLines.push(`db.${modelName}.bulkCreate({ data: [...], select: { id: true } }).execute()`);
232
+ }
233
+ if (table.query?.bulkUpsert) {
234
+ bulkUsageLines.push(`db.${modelName}.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`);
235
+ }
236
+ if (table.query?.bulkUpdate) {
237
+ bulkUsageLines.push(`db.${modelName}.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`);
238
+ }
239
+ if (table.query?.bulkDelete) {
240
+ bulkUsageLines.push(`db.${modelName}.bulkDelete({ where: {...} }).execute()`);
241
+ }
198
242
  files.push({
199
243
  fileName: `${skillName}/references/${refName}.md`,
200
244
  content: buildSkillReference({
@@ -207,6 +251,7 @@ export function generateOrmSkills(tables, customOperations, targetName, registry
207
251
  `db.${modelName}.create({ data: { ${editableFields.map((f) => `${f.name}: ${fieldPlaceholder(f)}`).join(', ')} }, select: { id: true } }).execute()`,
208
252
  `db.${modelName}.update({ where: { ${pk.name}: ${pkPlaceholder(pk)} }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? fieldPlaceholder(editableFields[0]) : "'<String>'"} }, select: { id: true } }).execute()`,
209
253
  `db.${modelName}.delete({ where: { ${pk.name}: ${pkPlaceholder(pk)} } }).execute()`,
254
+ ...bulkUsageLines,
210
255
  ],
211
256
  examples: [
212
257
  {
@@ -256,6 +301,7 @@ export function generateOrmSkills(tables, customOperations, targetName, registry
256
301
  }
257
302
  // Generate the overview SKILL.md
258
303
  const tableNames = tables.map((t) => lcFirst(getTableNames(t).singularName));
304
+ const hasBulkTables = tables.some((t) => t.query?.bulkInsert || t.query?.bulkUpsert || t.query?.bulkUpdate || t.query?.bulkDelete);
259
305
  files.push({
260
306
  fileName: `${skillName}/SKILL.md`,
261
307
  content: buildSkillFile({
@@ -272,6 +318,14 @@ export function generateOrmSkills(tables, customOperations, targetName, registry
272
318
  `db.<model>.create({ data: { ... }, select: { id: true } }).execute()`,
273
319
  `db.<model>.update({ where: { id: '<UUID>' }, data: { ... }, select: { id: true } }).execute()`,
274
320
  `db.<model>.delete({ where: { id: '<UUID>' } }).execute()`,
321
+ ...(hasBulkTables ? [
322
+ '',
323
+ `// Bulk operations (on tables with @behavior +bulkInsert/+bulkUpsert/+bulkUpdate/+bulkDelete)`,
324
+ `db.<model>.bulkCreate({ data: [...], select: { id: true } }).execute()`,
325
+ `db.<model>.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`,
326
+ `db.<model>.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`,
327
+ `db.<model>.bulkDelete({ where: {...} }).execute()`,
328
+ ] : []),
275
329
  ],
276
330
  examples: [
277
331
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-codegen",
3
- "version": "4.41.1",
3
+ "version": "4.41.2",
4
4
  "description": "GraphQL SDK generator for Constructive databases with React Query hooks",
5
5
  "keywords": [
6
6
  "graphql",
@@ -56,7 +56,7 @@
56
56
  "@0no-co/graphql.web": "^1.1.2",
57
57
  "@babel/generator": "^7.29.1",
58
58
  "@babel/types": "^7.29.0",
59
- "@constructive-io/graphql-query": "^3.24.0",
59
+ "@constructive-io/graphql-query": "^3.24.1",
60
60
  "@constructive-io/graphql-types": "^3.9.1",
61
61
  "@inquirerer/utils": "^3.3.5",
62
62
  "@pgpmjs/core": "^6.17.1",
@@ -64,7 +64,7 @@
64
64
  "deepmerge": "^4.3.1",
65
65
  "find-and-require-package-json": "^0.9.1",
66
66
  "gql-ast": "^3.9.1",
67
- "graphile-schema": "^1.19.4",
67
+ "graphile-schema": "^1.19.5",
68
68
  "graphql": "16.13.0",
69
69
  "inflekt": "^0.7.1",
70
70
  "inquirerer": "^4.7.0",
@@ -100,5 +100,5 @@
100
100
  "tsx": "^4.21.0",
101
101
  "typescript": "^5.9.3"
102
102
  },
103
- "gitHead": "0b23c8c5c65e408576cd1fe3e21b20ae6db8f492"
103
+ "gitHead": "42ff6bf5fa2e400bb63f78745a1f5a76209677b6"
104
104
  }