@constructive-io/graphql-codegen 4.40.6 → 4.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -312,7 +312,7 @@ function buildFindManyArgsType(table) {
312
312
  }
313
313
  /**
314
314
  * Build the FindFirstArgs type instantiation for a table:
315
- * FindFirstArgs<SelectType, FilterType> & { select: SelectType }
315
+ * FindFirstArgs<SelectType, FilterType, OrderByType> & { select: SelectType }
316
316
  *
317
317
  * The intersection with { select: SelectType } makes select required,
318
318
  * matching what the ORM's findFirst method expects.
@@ -321,9 +321,11 @@ function buildFindFirstArgsType(table) {
321
321
  const { typeName } = (0, utils_1.getTableNames)(table);
322
322
  const selectTypeName = `${typeName}Select`;
323
323
  const whereTypeName = (0, utils_1.getFilterTypeName)(table);
324
+ const orderByTypeName = (0, utils_1.getOrderByTypeName)(table);
324
325
  const findFirstType = t.tsTypeReference(t.identifier('FindFirstArgs'), t.tsTypeParameterInstantiation([
325
326
  t.tsTypeReference(t.identifier(selectTypeName)),
326
327
  t.tsTypeReference(t.identifier(whereTypeName)),
328
+ t.tsTypeReference(t.identifier(orderByTypeName)),
327
329
  ]));
328
330
  // Intersect with { select: SelectType } to make select required
329
331
  return t.tsIntersectionType([
@@ -716,6 +718,114 @@ function buildMutationHandler(table, operation, vectorFieldNames, targetName, ty
716
718
  t.tryStatement(t.blockStatement(tryBody), buildErrorCatch(`Failed to ${operation} record.`)),
717
719
  ]), false, true);
718
720
  }
721
+ function buildBulkMutationHandler(table, operation, targetName) {
722
+ const { singularName } = (0, utils_1.getTableNames)(table);
723
+ const selectObj = buildSelectObject(table);
724
+ // Map CLI op name to ORM method name
725
+ const ormMethod = (() => {
726
+ switch (operation) {
727
+ case 'bulk-create': return 'bulkCreate';
728
+ case 'bulk-upsert': return 'bulkUpsert';
729
+ case 'bulk-update': return 'bulkUpdate';
730
+ case 'bulk-delete': return 'bulkDelete';
731
+ }
732
+ })();
733
+ const tryBody = [];
734
+ if (operation === 'bulk-create' || operation === 'bulk-upsert') {
735
+ // Parse --data (JSON array) from argv
736
+ tryBody.push(t.variableDeclaration('const', [
737
+ t.variableDeclarator(t.identifier('dataRaw'), t.memberExpression(t.identifier('argv'), t.identifier('data'))),
738
+ ]));
739
+ tryBody.push(t.ifStatement(t.unaryExpression('!', t.identifier('dataRaw')), t.blockStatement([
740
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [t.stringLiteral(`--data is required for ${operation}. Provide a JSON array.`)])),
741
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
742
+ ])));
743
+ tryBody.push(t.variableDeclaration('const', [
744
+ t.variableDeclarator(t.identifier('data'), t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [t.tsAsExpression(t.identifier('dataRaw'), t.tsStringKeyword())])),
745
+ ]));
746
+ let ormArgs;
747
+ if (operation === 'bulk-upsert') {
748
+ // Also parse --on-conflict
749
+ tryBody.push(t.variableDeclaration('const', [
750
+ t.variableDeclarator(t.identifier('onConflictRaw'), t.memberExpression(t.identifier('argv'), t.identifier('on-conflict'))),
751
+ ]));
752
+ tryBody.push(t.variableDeclaration('const', [
753
+ t.variableDeclarator(t.identifier('onConflict'), t.conditionalExpression(t.identifier('onConflictRaw'), t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [t.tsAsExpression(t.identifier('onConflictRaw'), t.tsStringKeyword())]), t.objectExpression([]))),
754
+ ]));
755
+ ormArgs = t.objectExpression([
756
+ t.objectProperty(t.identifier('data'), t.identifier('data')),
757
+ t.objectProperty(t.identifier('onConflict'), t.identifier('onConflict')),
758
+ t.objectProperty(t.identifier('select'), selectObj),
759
+ ]);
760
+ }
761
+ else {
762
+ ormArgs = t.objectExpression([
763
+ t.objectProperty(t.identifier('data'), t.identifier('data')),
764
+ t.objectProperty(t.identifier('select'), selectObj),
765
+ ]);
766
+ }
767
+ tryBody.push(buildGetClientStatement(targetName));
768
+ tryBody.push(t.variableDeclaration('const', [
769
+ t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCall(singularName, ormMethod, ormArgs))),
770
+ ]));
771
+ }
772
+ else if (operation === 'bulk-update') {
773
+ // Parse --where (JSON) and --data (JSON)
774
+ tryBody.push(t.variableDeclaration('const', [
775
+ t.variableDeclarator(t.identifier('whereRaw'), t.memberExpression(t.identifier('argv'), t.identifier('where'))),
776
+ ]));
777
+ tryBody.push(t.variableDeclaration('const', [
778
+ t.variableDeclarator(t.identifier('dataRaw'), t.memberExpression(t.identifier('argv'), t.identifier('data'))),
779
+ ]));
780
+ tryBody.push(t.ifStatement(t.logicalExpression('||', t.unaryExpression('!', t.identifier('whereRaw')), t.unaryExpression('!', t.identifier('dataRaw'))), t.blockStatement([
781
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [t.stringLiteral('--where and --data are required for bulk-update. Provide JSON objects.')])),
782
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
783
+ ])));
784
+ tryBody.push(t.variableDeclaration('const', [
785
+ t.variableDeclarator(t.identifier('where'), t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [t.tsAsExpression(t.identifier('whereRaw'), t.tsStringKeyword())])),
786
+ ]));
787
+ tryBody.push(t.variableDeclaration('const', [
788
+ t.variableDeclarator(t.identifier('data'), t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [t.tsAsExpression(t.identifier('dataRaw'), t.tsStringKeyword())])),
789
+ ]));
790
+ tryBody.push(buildGetClientStatement(targetName));
791
+ tryBody.push(t.variableDeclaration('const', [
792
+ t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCall(singularName, ormMethod, t.objectExpression([
793
+ t.objectProperty(t.identifier('where'), t.identifier('where')),
794
+ t.objectProperty(t.identifier('data'), t.identifier('data')),
795
+ t.objectProperty(t.identifier('select'), selectObj),
796
+ ])))),
797
+ ]));
798
+ }
799
+ else {
800
+ // bulk-delete: parse --where (JSON)
801
+ tryBody.push(t.variableDeclaration('const', [
802
+ t.variableDeclarator(t.identifier('whereRaw'), t.memberExpression(t.identifier('argv'), t.identifier('where'))),
803
+ ]));
804
+ tryBody.push(t.ifStatement(t.unaryExpression('!', t.identifier('whereRaw')), t.blockStatement([
805
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('console'), t.identifier('error')), [t.stringLiteral('--where is required for bulk-delete. Provide a JSON object.')])),
806
+ t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('process'), t.identifier('exit')), [t.numericLiteral(1)])),
807
+ ])));
808
+ tryBody.push(t.variableDeclaration('const', [
809
+ t.variableDeclarator(t.identifier('where'), t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [t.tsAsExpression(t.identifier('whereRaw'), t.tsStringKeyword())])),
810
+ ]));
811
+ tryBody.push(buildGetClientStatement(targetName));
812
+ tryBody.push(t.variableDeclaration('const', [
813
+ t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCall(singularName, ormMethod, t.objectExpression([
814
+ t.objectProperty(t.identifier('where'), t.identifier('where')),
815
+ t.objectProperty(t.identifier('select'), selectObj),
816
+ ])))),
817
+ ]));
818
+ }
819
+ tryBody.push(buildJsonLog(t.identifier('result')));
820
+ const argvParam = t.identifier('argv');
821
+ argvParam.typeAnnotation = buildArgvType();
822
+ const prompterParam = t.identifier('prompter');
823
+ prompterParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Inquirerer')));
824
+ const handlerName = `handle${(0, utils_1.toPascalCase)(operation)}`;
825
+ return t.functionDeclaration(t.identifier(handlerName), [argvParam, prompterParam], t.blockStatement([
826
+ t.tryStatement(t.blockStatement(tryBody), buildErrorCatch(`Failed to ${operation}.`)),
827
+ ]), false, true);
828
+ }
719
829
  function generateTableCommand(table, options) {
720
830
  const { singularName, typeName } = (0, utils_1.getTableNames)(table);
721
831
  const commandName = (0, inflekt_1.toKebabCase)(singularName);
@@ -793,6 +903,11 @@ function generateTableCommand(table, options) {
793
903
  const embedderPath = options?.targetName ? '../../embedder' : '../embedder';
794
904
  statements.push(createImportDeclaration(embedderPath, ['resolveEmbedder', 'autoEmbedWhere', 'autoEmbedInput']));
795
905
  }
906
+ // Detect bulk mutations
907
+ const hasBulkCreate = !!table.query?.bulkInsert;
908
+ const hasBulkUpsert = !!table.query?.bulkUpsert;
909
+ const hasBulkUpdate = !!table.query?.bulkUpdate;
910
+ const hasBulkDelete = !!table.query?.bulkDelete;
796
911
  const subcommands = ['list', 'find-first'];
797
912
  if (hasSearchFields)
798
913
  subcommands.push('search');
@@ -803,6 +918,14 @@ function generateTableCommand(table, options) {
803
918
  subcommands.push('update');
804
919
  if (hasDelete)
805
920
  subcommands.push('delete');
921
+ if (hasBulkCreate)
922
+ subcommands.push('bulk-create');
923
+ if (hasBulkUpsert)
924
+ subcommands.push('bulk-upsert');
925
+ if (hasBulkUpdate)
926
+ subcommands.push('bulk-update');
927
+ if (hasBulkDelete)
928
+ subcommands.push('bulk-delete');
806
929
  const usageLines = [
807
930
  '',
808
931
  `${commandName} <command>`,
@@ -823,7 +946,15 @@ function generateTableCommand(table, options) {
823
946
  }
824
947
  if (hasDelete)
825
948
  usageLines.push(` delete Delete a ${singularName}`);
826
- usageLines.push('', 'List Options:', ' --limit <n> Max number of records to return (forward pagination)', ' --last <n> Number of records from the end (backward pagination)', ' --after <cursor> Cursor for forward pagination', ' --before <cursor> Cursor for backward pagination', ' --offset <n> Number of records to skip', ' --select <fields> Comma-separated list of fields to return', ' --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)', ' --condition.<f>.<op> Condition filter (dot-notation)', ' --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)', '', 'Find-First Options:', ' --select <fields> Comma-separated list of fields to return', ' --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)', ' --condition.<f>.<op> Condition filter (dot-notation)', '');
949
+ if (hasBulkCreate)
950
+ usageLines.push(` bulk-create Bulk create ${singularName} records`);
951
+ if (hasBulkUpsert)
952
+ usageLines.push(` bulk-upsert Bulk upsert ${singularName} records`);
953
+ if (hasBulkUpdate)
954
+ usageLines.push(` bulk-update Bulk update ${singularName} records`);
955
+ if (hasBulkDelete)
956
+ usageLines.push(` bulk-delete Bulk delete ${singularName} records`);
957
+ usageLines.push('', 'List Options:', ' --limit <n> Max number of records to return (forward pagination)', ' --last <n> Number of records from the end (backward pagination)', ' --after <cursor> Cursor for forward pagination', ' --before <cursor> Cursor for backward pagination', ' --offset <n> Number of records to skip', ' --select <fields> Comma-separated list of fields to return', ' --where.<field>.<op> Filter (dot-notation, e.g. --where.name.equalTo foo)', ' --condition.<f>.<op> Condition filter (dot-notation)', ' --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)', '', 'Find-First Options:', ' --select <fields> Comma-separated list of fields to return', ' --where.<field>.<op> Filter (dot-notation, e.g. --where.status.equalTo active)', ' --condition.<f>.<op> Condition filter (dot-notation)', ' --orderBy <values> Comma-separated ordering values (e.g. NAME_ASC,CREATED_AT_DESC)', '');
827
958
  if (hasSearchFields) {
828
959
  usageLines.push('Search Options:', ' <query> Search query string (required)', ' --limit <n> Max number of records to return', ' --offset <n> Number of records to skip', ' --select <fields> Comma-separated list of fields to return', ' --orderBy <values> Comma-separated list of ordering values');
829
960
  if (hasEmbeddings) {
@@ -906,6 +1037,14 @@ function generateTableCommand(table, options) {
906
1037
  statements.push(buildMutationHandler(table, 'update', vectorFieldNames, tn, options?.typeRegistry, ormTypes));
907
1038
  if (hasDelete)
908
1039
  statements.push(buildMutationHandler(table, 'delete', vectorFieldNames, tn, options?.typeRegistry, ormTypes));
1040
+ if (hasBulkCreate)
1041
+ statements.push(buildBulkMutationHandler(table, 'bulk-create', tn));
1042
+ if (hasBulkUpsert)
1043
+ statements.push(buildBulkMutationHandler(table, 'bulk-upsert', tn));
1044
+ if (hasBulkUpdate)
1045
+ statements.push(buildBulkMutationHandler(table, 'bulk-update', tn));
1046
+ if (hasBulkDelete)
1047
+ statements.push(buildBulkMutationHandler(table, 'bulk-delete', tn));
909
1048
  const header = (0, utils_1.getGeneratedFileHeader)(`CLI commands for ${table.name}`);
910
1049
  const code = (0, babel_ast_1.generateCode)(statements);
911
1050
  return {
@@ -113,6 +113,24 @@ function generateEntityMutationKeysDeclaration(table, relationships) {
113
113
  const deleteProp = t.objectProperty(t.identifier('delete'), deleteArrowFn);
114
114
  (0, babel_ast_1.addJSDocComment)(deleteProp, [`Delete ${singularName} mutation key`]);
115
115
  properties.push(deleteProp);
116
+ // Bulk mutation keys (only if table has bulk operations)
117
+ const bulkOps = [
118
+ { key: 'bulkCreate', queryField: table.query?.bulkInsert },
119
+ { key: 'bulkUpsert', queryField: table.query?.bulkUpsert },
120
+ { key: 'bulkUpdate', queryField: table.query?.bulkUpdate },
121
+ { key: 'bulkDelete', queryField: table.query?.bulkDelete },
122
+ ];
123
+ for (const { key, queryField } of bulkOps) {
124
+ if (!queryField)
125
+ continue;
126
+ const arrowFn = t.arrowFunctionExpression([], (0, babel_ast_1.constArray)([
127
+ t.stringLiteral('mutation'),
128
+ t.stringLiteral(entityKey),
129
+ t.stringLiteral(key),
130
+ ]));
131
+ const prop = t.objectProperty(t.identifier(key), arrowFn);
132
+ properties.push(prop);
133
+ }
116
134
  return t.exportNamedDeclaration(t.variableDeclaration('const', [
117
135
  t.variableDeclarator(t.identifier(keysName), (0, babel_ast_1.asConst)(t.objectExpression(properties))),
118
136
  ]));
@@ -416,6 +416,185 @@ function generateDeleteMutationHook(table, options = {}) {
416
416
  content: (0, hooks_ast_1.generateHookFileCode)(table.description || `Delete mutation hook for ${typeName}`, statements),
417
417
  };
418
418
  }
419
+ function generateBulkMutationHook(table, op, options = {}) {
420
+ const { reactQueryEnabled = true, useCentralizedKeys = true } = options;
421
+ if (!reactQueryEnabled)
422
+ return null;
423
+ const mutationFieldName = (() => {
424
+ switch (op) {
425
+ case 'bulkCreate': return table.query?.bulkInsert;
426
+ case 'bulkUpsert': return table.query?.bulkUpsert;
427
+ case 'bulkUpdate': return table.query?.bulkUpdate;
428
+ case 'bulkDelete': return table.query?.bulkDelete;
429
+ }
430
+ })();
431
+ if (!mutationFieldName)
432
+ return null;
433
+ const { typeName, singularName } = (0, utils_1.getTableNames)(table);
434
+ const hookName = (() => {
435
+ switch (op) {
436
+ case 'bulkCreate': return (0, utils_1.getBulkCreateMutationHookName)(table);
437
+ case 'bulkUpsert': return (0, utils_1.getBulkUpsertMutationHookName)(table);
438
+ case 'bulkUpdate': return (0, utils_1.getBulkUpdateMutationHookName)(table);
439
+ case 'bulkDelete': return (0, utils_1.getBulkDeleteMutationHookName)(table);
440
+ }
441
+ })();
442
+ const fileName = (() => {
443
+ switch (op) {
444
+ case 'bulkCreate': return (0, utils_1.getBulkCreateMutationFileName)(table);
445
+ case 'bulkUpsert': return (0, utils_1.getBulkUpsertMutationFileName)(table);
446
+ case 'bulkUpdate': return (0, utils_1.getBulkUpdateMutationFileName)(table);
447
+ case 'bulkDelete': return (0, utils_1.getBulkDeleteMutationFileName)(table);
448
+ }
449
+ })();
450
+ const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
451
+ const mutationKeysName = `${(0, utils_1.lcFirst)(typeName)}MutationKeys`;
452
+ const selectTypeName = `${typeName}Select`;
453
+ const relationTypeName = `${typeName}WithRelations`;
454
+ const createInputTypeName = `Create${typeName}Input`;
455
+ const patchTypeName = `${typeName}Patch`;
456
+ const filterTypeName = `${typeName}Filter`;
457
+ const statements = [];
458
+ // Imports
459
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', [
460
+ 'useMutation',
461
+ 'useQueryClient',
462
+ ]));
463
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true));
464
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../client', ['getClient']));
465
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['buildSelectionArgs']));
466
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['SelectionConfig'], true));
467
+ if (useCentralizedKeys) {
468
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [keysName]));
469
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
470
+ }
471
+ // Determine which types to import
472
+ const typeImports = [selectTypeName, relationTypeName];
473
+ if (op === 'bulkCreate' || op === 'bulkUpsert') {
474
+ typeImports.push(createInputTypeName);
475
+ }
476
+ if (op === 'bulkUpdate') {
477
+ typeImports.push(patchTypeName);
478
+ typeImports.push(filterTypeName);
479
+ }
480
+ if (op === 'bulkDelete') {
481
+ typeImports.push(filterTypeName);
482
+ }
483
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', typeImports, true));
484
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'BulkMutationResult', 'HookStrictSelect'], true));
485
+ // Re-exports
486
+ statements.push((0, hooks_ast_1.createTypeReExport)(typeImports, '../../orm/input-types'));
487
+ // Build the variable type for the mutationFn parameter
488
+ const varType = (() => {
489
+ switch (op) {
490
+ case 'bulkCreate':
491
+ return t.tsTypeLiteral([
492
+ t.tsPropertySignature(t.identifier('data'), t.tsTypeAnnotation(t.tsArrayType(t.tsIndexedAccessType((0, hooks_ast_1.typeRef)(createInputTypeName), t.tsLiteralType(t.stringLiteral(singularName)))))),
493
+ (() => {
494
+ const p = t.tsPropertySignature(t.identifier('onConflict'), t.tsTypeAnnotation(t.tsUnknownKeyword()));
495
+ p.optional = true;
496
+ return p;
497
+ })(),
498
+ ]);
499
+ case 'bulkUpsert':
500
+ return t.tsTypeLiteral([
501
+ t.tsPropertySignature(t.identifier('data'), t.tsTypeAnnotation(t.tsArrayType(t.tsIndexedAccessType((0, hooks_ast_1.typeRef)(createInputTypeName), t.tsLiteralType(t.stringLiteral(singularName)))))),
502
+ t.tsPropertySignature(t.identifier('onConflict'), t.tsTypeAnnotation(t.tsUnknownKeyword())),
503
+ ]);
504
+ case 'bulkUpdate':
505
+ return t.tsTypeLiteral([
506
+ t.tsPropertySignature(t.identifier('where'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(filterTypeName))),
507
+ t.tsPropertySignature(t.identifier('data'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(patchTypeName))),
508
+ ]);
509
+ case 'bulkDelete':
510
+ return t.tsTypeLiteral([
511
+ t.tsPropertySignature(t.identifier('where'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(filterTypeName))),
512
+ ]);
513
+ }
514
+ })();
515
+ // Result type: BulkMutationResult<InferSelectResult<Relation, S>>
516
+ const bulkResultType = (sel) => (0, hooks_ast_1.typeRef)('BulkMutationResult', [(0, hooks_ast_1.inferSelectResultType)(relationTypeName, sel)]);
517
+ // Overload with fields
518
+ const o1ParamType = t.tsIntersectionType([
519
+ t.tsTypeLiteral([
520
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildFieldsSelectionType((0, hooks_ast_1.sRef)(), selectTypeName))),
521
+ ]),
522
+ (0, hooks_ast_1.useMutationOptionsType)(bulkResultType((0, hooks_ast_1.sRef)()), varType),
523
+ ]);
524
+ const o1 = (0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.useMutationResultType)(bulkResultType((0, hooks_ast_1.sRef)()), varType));
525
+ (0, hooks_ast_1.addJSDocComment)(o1, [
526
+ table.description || `Bulk ${op.replace('bulk', '').toLowerCase()} mutation hook for ${typeName}`,
527
+ ]);
528
+ statements.push(o1);
529
+ // Implementation
530
+ const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName))));
531
+ const implParamType = t.tsIntersectionType([
532
+ t.tsTypeLiteral([implSelProp]),
533
+ (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseMutationOptions', [
534
+ t.tsAnyKeyword(),
535
+ (0, hooks_ast_1.typeRef)('Error'),
536
+ varType,
537
+ ]), ['mutationFn']),
538
+ ]);
539
+ const body = [];
540
+ body.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
541
+ body.push((0, hooks_ast_1.destructureParamsWithSelection)('mutationOptions'));
542
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
543
+ body.push((0, hooks_ast_1.constDecl)('queryClient', (0, hooks_ast_1.callExpr)('useQueryClient', [])));
544
+ const mutationKeyExpr = useCentralizedKeys
545
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(mutationKeysName), t.identifier(op)), [])
546
+ : undefined;
547
+ // Build the ORM method call depending on the operation
548
+ const ormMethodName = op;
549
+ const mutationFnArgs = (() => {
550
+ switch (op) {
551
+ case 'bulkCreate':
552
+ return t.objectExpression([
553
+ (0, hooks_ast_1.shorthandProp)('data'),
554
+ (0, hooks_ast_1.objectProp)('onConflict', t.memberExpression(t.identifier('vars'), t.identifier('onConflict'))),
555
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
556
+ ]);
557
+ case 'bulkUpsert':
558
+ return t.objectExpression([
559
+ (0, hooks_ast_1.shorthandProp)('data'),
560
+ (0, hooks_ast_1.objectProp)('onConflict', t.memberExpression(t.identifier('vars'), t.identifier('onConflict'))),
561
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
562
+ ]);
563
+ case 'bulkUpdate':
564
+ return t.objectExpression([
565
+ (0, hooks_ast_1.objectProp)('where', t.memberExpression(t.identifier('vars'), t.identifier('where'))),
566
+ (0, hooks_ast_1.shorthandProp)('data'),
567
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
568
+ ]);
569
+ case 'bulkDelete':
570
+ return t.objectExpression([
571
+ (0, hooks_ast_1.objectProp)('where', t.memberExpression(t.identifier('vars'), t.identifier('where'))),
572
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
573
+ ]);
574
+ }
575
+ })();
576
+ const varsParam = (0, hooks_ast_1.createFunctionParam)('vars', varType);
577
+ const mutationFnExpr = t.arrowFunctionExpression([varsParam], (0, hooks_ast_1.getClientCallUnwrap)(singularName, ormMethodName, mutationFnArgs));
578
+ // onSuccess: invalidate lists
579
+ const listKeyExpr = useCentralizedKeys
580
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
581
+ : t.arrayExpression([
582
+ t.stringLiteral(typeName.toLowerCase()),
583
+ t.stringLiteral('list'),
584
+ ]);
585
+ const onSuccessFn = t.arrowFunctionExpression([], t.blockStatement([
586
+ t.expressionStatement((0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([(0, hooks_ast_1.objectProp)('queryKey', listKeyExpr)])])),
587
+ ]));
588
+ body.push((0, hooks_ast_1.returnUseMutation)(mutationFnExpr, [
589
+ (0, hooks_ast_1.objectProp)('onSuccess', onSuccessFn),
590
+ (0, hooks_ast_1.spreadObj)(t.identifier('mutationOptions')),
591
+ ], mutationKeyExpr));
592
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
593
+ return {
594
+ fileName,
595
+ content: (0, hooks_ast_1.generateHookFileCode)(table.description || `Bulk ${op.replace('bulk', '').toLowerCase()} mutation hook for ${typeName}`, statements),
596
+ };
597
+ }
419
598
  function generateAllMutationHooks(tables, options = {}) {
420
599
  const files = [];
421
600
  for (const table of tables) {
@@ -431,6 +610,14 @@ function generateAllMutationHooks(tables, options = {}) {
431
610
  if (deleteHook) {
432
611
  files.push(deleteHook);
433
612
  }
613
+ // Bulk mutation hooks
614
+ const bulkOps = ['bulkCreate', 'bulkUpsert', 'bulkUpdate', 'bulkDelete'];
615
+ for (const op of bulkOps) {
616
+ const hook = generateBulkMutationHook(table, op, options);
617
+ if (hook) {
618
+ files.push(hook);
619
+ }
620
+ }
434
621
  }
435
622
  return files;
436
623
  }
@@ -168,12 +168,6 @@ function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations,
168
168
  statements.push(t.exportAllDeclaration(t.stringLiteral('./select-types')));
169
169
  // Re-export all models
170
170
  statements.push(t.exportAllDeclaration(t.stringLiteral('./models')));
171
- // Re-export NodeHttpAdapter when enabled (for use in any Node.js application)
172
- if (options?.nodeHttpAdapter) {
173
- statements.push(t.exportNamedDeclaration(null, [
174
- t.exportSpecifier(t.identifier('NodeHttpAdapter'), t.identifier('NodeHttpAdapter')),
175
- ], t.stringLiteral('./node-fetch')));
176
- }
177
171
  // Re-export custom operations
178
172
  if (hasCustomQueries) {
179
173
  statements.push(t.exportNamedDeclaration(null, [