@constructive-io/graphql-codegen 2.17.38 → 2.17.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -86,26 +86,16 @@ Endpoint introspection:
86
86
 
87
87
  ## Selection Options
88
88
 
89
- Configure result field selections, mutation input style, and connection pagination shape.
89
+ Configure mutation input style and connection pagination shape.
90
90
 
91
91
  ```ts
92
92
  selection: {
93
- defaultMutationModelFields?: string[]
94
- modelFields?: Record<string, string[]>
95
93
  mutationInputMode?: 'expanded' | 'model' | 'raw' | 'patchCollapsed'
96
94
  connectionStyle?: 'nodes' | 'edges'
97
95
  forceModelOutput?: boolean
98
96
  }
99
97
  ```
100
98
 
101
- - `defaultMutationModelFields`
102
- - Sets default fields selected from the object payload returned by mutations when the mutation exposes an OBJECT output.
103
- - Example: `['id']` will select only the `id` from the returned model unless overridden per model.
104
-
105
- - `modelFields`
106
- - Per‑model overrides for returned object payload fields.
107
- - Example: `{ domain: ['id','domain','subdomain'] }` selects those fields from the `domain` object output.
108
-
109
99
  - `mutationInputMode`
110
100
  - Controls how mutation variables and `input` are generated.
111
101
  - `expanded`: one variable per input property; `input` is a flat object of those variables.
@@ -119,8 +109,7 @@ selection: {
119
109
  - `edges`: emits `totalCount`, `pageInfo { ... }`, and `edges { cursor node { ... } }`.
120
110
 
121
111
  - `forceModelOutput`
122
- - When `true`, ensures the object payload is selected even if `defaultMutationModelFields` is empty, defaulting to `['id']`.
123
- - Useful to avoid generating mutations that only return `clientMutationId`.
112
+ - When `true`, ensures the object payload selection is emitted to avoid a payload with only `clientMutationId`.
124
113
 
125
114
  ### Examples
126
115
 
package/esm/gql.js CHANGED
@@ -480,12 +480,27 @@ export const createOne = ({ operationName, mutation, selection, }, typeNameOverr
480
480
  }),
481
481
  }),
482
482
  ];
483
- const selections = allAttrs.map((field) => t.field({ name: 'id' }));
484
- const modelFields = selection?.modelFields?.[modelName] || selection?.defaultMutationModelFields || ['id'];
485
- const nested = (modelFields.length > 0)
483
+ let idExists = true;
484
+ let availableFieldNames = [];
485
+ if (typeIndex) {
486
+ const typ = typeIndex.byName?.[mutation.model];
487
+ const fields = (typ && Array.isArray(typ.fields)) ? typ.fields : [];
488
+ idExists = fields.some((f) => f && f.name === 'id');
489
+ availableFieldNames = fields
490
+ .filter((f) => {
491
+ let r = f.type;
492
+ while (r && (r.kind === 'NON_NULL' || r.kind === 'LIST'))
493
+ r = r.ofType;
494
+ const kind = r?.kind;
495
+ return kind === 'SCALAR' || kind === 'ENUM';
496
+ })
497
+ .map((f) => f.name);
498
+ }
499
+ const finalFields = Array.from(new Set([...(idExists ? ['id'] : []), ...availableFieldNames]));
500
+ const nested = (finalFields.length > 0)
486
501
  ? [t.field({
487
502
  name: modelName,
488
- selectionSet: t.selectionSet({ selections: modelFields.map((f) => t.field({ name: f })) }),
503
+ selectionSet: t.selectionSet({ selections: finalFields.map((f) => t.field({ name: f })) }),
489
504
  })]
490
505
  : [];
491
506
  const ast = createGqlMutation({
@@ -577,7 +592,7 @@ export const patchOne = ({ operationName, mutation, selection, }, typeNameOverri
577
592
  unresolved++;
578
593
  return t.variableDefinition({ variable: t.variable({ name }), type: gqlType });
579
594
  });
580
- const mustUseRaw = useCollapsedOpt || unresolved > 0;
595
+ const mustUseRaw = unresolved > 0;
581
596
  const selectArgs = mustUseRaw
582
597
  ? [t.argument({ name: 'input', value: t.variable({ name: 'input' }) })]
583
598
  : [
@@ -598,11 +613,18 @@ export const patchOne = ({ operationName, mutation, selection, }, typeNameOverri
598
613
  }),
599
614
  }),
600
615
  ];
601
- const modelFields = selection?.modelFields?.[modelName] || selection?.defaultMutationModelFields || ['id'];
602
- const nestedPatch = (modelFields.length > 0)
616
+ let idExistsPatch = true;
617
+ if (typeIndex) {
618
+ const typ = typeIndex.byName?.[mutation.model];
619
+ const fields = (typ && Array.isArray(typ.fields)) ? typ.fields : [];
620
+ idExistsPatch = fields.some((f) => f && f.name === 'id');
621
+ }
622
+ const shouldDropIdPatch = /Extension$/i.test(modelName) || !idExistsPatch;
623
+ const idSelection = shouldDropIdPatch ? [] : ['id'];
624
+ const nestedPatch = (idSelection.length > 0)
603
625
  ? [t.field({
604
626
  name: modelName,
605
- selectionSet: t.selectionSet({ selections: modelFields.map((f) => t.field({ name: f })) }),
627
+ selectionSet: t.selectionSet({ selections: idSelection.map((f) => t.field({ name: f })) }),
606
628
  })]
607
629
  : [];
608
630
  const ast = createGqlMutation({
@@ -729,20 +751,41 @@ export const createMutation = ({ operationName, mutation, selection, }, typeName
729
751
  const scalarOutputs = (mutation.outputs || [])
730
752
  .filter((field) => field.type.kind === 'SCALAR')
731
753
  .map((f) => f.name);
732
- const objectOutput = (mutation.outputs || []).find((field) => field.type.kind === 'OBJECT');
733
- const selections = [];
734
- if (objectOutput?.name) {
735
- const modelFieldsRaw = selection?.modelFields?.[objectOutput.name] || selection?.defaultMutationModelFields || [];
736
- const shouldDropId = /Extension$/i.test(objectOutput.name);
737
- const fallbackFields = shouldDropId ? [] : ['id'];
738
- const modelFields = (selection?.forceModelOutput && modelFieldsRaw.length === 0) ? fallbackFields : (modelFieldsRaw.length > 0 ? modelFieldsRaw : []);
739
- if (modelFields.length > 0) {
740
- selections.push(t.field({
741
- name: objectOutput.name,
742
- selectionSet: t.selectionSet({ selections: modelFields.map((f) => t.field({ name: f })) }),
743
- }));
754
+ let objectOutputName = (mutation.outputs || [])
755
+ .find((field) => field.type.kind === 'OBJECT')?.name;
756
+ if (!objectOutputName) {
757
+ const payloadTypeName = mutation?.output?.name;
758
+ if (typeIndex && payloadTypeName) {
759
+ const payloadType = typeIndex.byName?.[payloadTypeName];
760
+ const fields = (payloadType && Array.isArray(payloadType.fields)) ? payloadType.fields : [];
761
+ const match = fields
762
+ .filter((f) => f && f.name !== 'clientMutationId')
763
+ .filter((f) => (refToNamedTypeName(f.type) || f.type?.name) !== 'Query')
764
+ .find((f) => (refToNamedTypeName(f.type) || f.type?.name) === mutation?.model);
765
+ if (match)
766
+ objectOutputName = match.name;
744
767
  }
745
768
  }
769
+ const selections = [];
770
+ if (objectOutputName) {
771
+ const modelTypeName = mutation?.model;
772
+ const modelType = typeIndex && modelTypeName ? typeIndex.byName?.[modelTypeName] : null;
773
+ const fieldNames = (modelType && Array.isArray(modelType.fields))
774
+ ? modelType.fields
775
+ .filter((f) => {
776
+ let r = f.type;
777
+ while (r && (r.kind === 'NON_NULL' || r.kind === 'LIST'))
778
+ r = r.ofType;
779
+ const kind = r?.kind;
780
+ return kind === 'SCALAR' || kind === 'ENUM';
781
+ })
782
+ .map((f) => f.name)
783
+ : [];
784
+ selections.push(t.field({
785
+ name: objectOutputName,
786
+ selectionSet: t.selectionSet({ selections: fieldNames.map((n) => t.field({ name: n })) }),
787
+ }));
788
+ }
746
789
  if (scalarOutputs.length > 0) {
747
790
  selections.push(...scalarOutputs.map((o) => t.field({ name: o })));
748
791
  }
package/esm/options.js CHANGED
@@ -10,7 +10,7 @@ export const defaultGraphQLCodegenOptions = {
10
10
  documents: { format: 'gql', convention: 'dashed', allowQueries: [], excludeQueries: [], excludePatterns: [] },
11
11
  features: { emitTypes: true, emitOperations: true, emitSdk: true, emitReactQuery: true },
12
12
  reactQuery: { fetcher: 'graphql-request', legacyMode: false, exposeDocument: false, addInfiniteQuery: false, reactQueryVersion: 5 },
13
- selection: { defaultMutationModelFields: ['id'], modelFields: {}, mutationInputMode: 'patchCollapsed', connectionStyle: 'edges', forceModelOutput: true },
13
+ selection: { mutationInputMode: 'patchCollapsed', connectionStyle: 'edges', forceModelOutput: true },
14
14
  scalars: {},
15
15
  typeNameOverrides: {}
16
16
  };
package/gql.d.ts CHANGED
@@ -84,8 +84,6 @@ export interface CreateOneArgs {
84
84
  operationName: string;
85
85
  mutation: MutationSpec;
86
86
  selection?: {
87
- defaultMutationModelFields?: string[];
88
- modelFields?: Record<string, string[]>;
89
87
  mutationInputMode?: 'expanded' | 'model' | 'raw' | 'patchCollapsed';
90
88
  connectionStyle?: 'nodes' | 'edges';
91
89
  forceModelOutput?: boolean;
@@ -115,8 +113,6 @@ export interface PatchOneArgs {
115
113
  operationName: string;
116
114
  mutation: MutationSpec;
117
115
  selection?: {
118
- defaultMutationModelFields?: string[];
119
- modelFields?: Record<string, string[]>;
120
116
  mutationInputMode?: 'expanded' | 'model' | 'raw' | 'patchCollapsed';
121
117
  connectionStyle?: 'nodes' | 'edges';
122
118
  forceModelOutput?: boolean;
@@ -140,8 +136,6 @@ export interface CreateMutationArgs {
140
136
  operationName: string;
141
137
  mutation: MutationSpec;
142
138
  selection?: {
143
- defaultMutationModelFields?: string[];
144
- modelFields?: Record<string, string[]>;
145
139
  mutationInputMode?: 'expanded' | 'model' | 'raw' | 'patchCollapsed';
146
140
  connectionStyle?: 'nodes' | 'edges';
147
141
  forceModelOutput?: boolean;
package/gql.js CHANGED
@@ -527,12 +527,27 @@ const createOne = ({ operationName, mutation, selection, }, typeNameOverrides, t
527
527
  }),
528
528
  }),
529
529
  ];
530
- const selections = allAttrs.map((field) => t.field({ name: 'id' }));
531
- const modelFields = selection?.modelFields?.[modelName] || selection?.defaultMutationModelFields || ['id'];
532
- const nested = (modelFields.length > 0)
530
+ let idExists = true;
531
+ let availableFieldNames = [];
532
+ if (typeIndex) {
533
+ const typ = typeIndex.byName?.[mutation.model];
534
+ const fields = (typ && Array.isArray(typ.fields)) ? typ.fields : [];
535
+ idExists = fields.some((f) => f && f.name === 'id');
536
+ availableFieldNames = fields
537
+ .filter((f) => {
538
+ let r = f.type;
539
+ while (r && (r.kind === 'NON_NULL' || r.kind === 'LIST'))
540
+ r = r.ofType;
541
+ const kind = r?.kind;
542
+ return kind === 'SCALAR' || kind === 'ENUM';
543
+ })
544
+ .map((f) => f.name);
545
+ }
546
+ const finalFields = Array.from(new Set([...(idExists ? ['id'] : []), ...availableFieldNames]));
547
+ const nested = (finalFields.length > 0)
533
548
  ? [t.field({
534
549
  name: modelName,
535
- selectionSet: t.selectionSet({ selections: modelFields.map((f) => t.field({ name: f })) }),
550
+ selectionSet: t.selectionSet({ selections: finalFields.map((f) => t.field({ name: f })) }),
536
551
  })]
537
552
  : [];
538
553
  const ast = (0, exports.createGqlMutation)({
@@ -625,7 +640,7 @@ const patchOne = ({ operationName, mutation, selection, }, typeNameOverrides, ty
625
640
  unresolved++;
626
641
  return t.variableDefinition({ variable: t.variable({ name }), type: gqlType });
627
642
  });
628
- const mustUseRaw = useCollapsedOpt || unresolved > 0;
643
+ const mustUseRaw = unresolved > 0;
629
644
  const selectArgs = mustUseRaw
630
645
  ? [t.argument({ name: 'input', value: t.variable({ name: 'input' }) })]
631
646
  : [
@@ -646,11 +661,18 @@ const patchOne = ({ operationName, mutation, selection, }, typeNameOverrides, ty
646
661
  }),
647
662
  }),
648
663
  ];
649
- const modelFields = selection?.modelFields?.[modelName] || selection?.defaultMutationModelFields || ['id'];
650
- const nestedPatch = (modelFields.length > 0)
664
+ let idExistsPatch = true;
665
+ if (typeIndex) {
666
+ const typ = typeIndex.byName?.[mutation.model];
667
+ const fields = (typ && Array.isArray(typ.fields)) ? typ.fields : [];
668
+ idExistsPatch = fields.some((f) => f && f.name === 'id');
669
+ }
670
+ const shouldDropIdPatch = /Extension$/i.test(modelName) || !idExistsPatch;
671
+ const idSelection = shouldDropIdPatch ? [] : ['id'];
672
+ const nestedPatch = (idSelection.length > 0)
651
673
  ? [t.field({
652
674
  name: modelName,
653
- selectionSet: t.selectionSet({ selections: modelFields.map((f) => t.field({ name: f })) }),
675
+ selectionSet: t.selectionSet({ selections: idSelection.map((f) => t.field({ name: f })) }),
654
676
  })]
655
677
  : [];
656
678
  const ast = (0, exports.createGqlMutation)({
@@ -779,20 +801,41 @@ const createMutation = ({ operationName, mutation, selection, }, typeNameOverrid
779
801
  const scalarOutputs = (mutation.outputs || [])
780
802
  .filter((field) => field.type.kind === 'SCALAR')
781
803
  .map((f) => f.name);
782
- const objectOutput = (mutation.outputs || []).find((field) => field.type.kind === 'OBJECT');
783
- const selections = [];
784
- if (objectOutput?.name) {
785
- const modelFieldsRaw = selection?.modelFields?.[objectOutput.name] || selection?.defaultMutationModelFields || [];
786
- const shouldDropId = /Extension$/i.test(objectOutput.name);
787
- const fallbackFields = shouldDropId ? [] : ['id'];
788
- const modelFields = (selection?.forceModelOutput && modelFieldsRaw.length === 0) ? fallbackFields : (modelFieldsRaw.length > 0 ? modelFieldsRaw : []);
789
- if (modelFields.length > 0) {
790
- selections.push(t.field({
791
- name: objectOutput.name,
792
- selectionSet: t.selectionSet({ selections: modelFields.map((f) => t.field({ name: f })) }),
793
- }));
804
+ let objectOutputName = (mutation.outputs || [])
805
+ .find((field) => field.type.kind === 'OBJECT')?.name;
806
+ if (!objectOutputName) {
807
+ const payloadTypeName = mutation?.output?.name;
808
+ if (typeIndex && payloadTypeName) {
809
+ const payloadType = typeIndex.byName?.[payloadTypeName];
810
+ const fields = (payloadType && Array.isArray(payloadType.fields)) ? payloadType.fields : [];
811
+ const match = fields
812
+ .filter((f) => f && f.name !== 'clientMutationId')
813
+ .filter((f) => (refToNamedTypeName(f.type) || f.type?.name) !== 'Query')
814
+ .find((f) => (refToNamedTypeName(f.type) || f.type?.name) === mutation?.model);
815
+ if (match)
816
+ objectOutputName = match.name;
794
817
  }
795
818
  }
819
+ const selections = [];
820
+ if (objectOutputName) {
821
+ const modelTypeName = mutation?.model;
822
+ const modelType = typeIndex && modelTypeName ? typeIndex.byName?.[modelTypeName] : null;
823
+ const fieldNames = (modelType && Array.isArray(modelType.fields))
824
+ ? modelType.fields
825
+ .filter((f) => {
826
+ let r = f.type;
827
+ while (r && (r.kind === 'NON_NULL' || r.kind === 'LIST'))
828
+ r = r.ofType;
829
+ const kind = r?.kind;
830
+ return kind === 'SCALAR' || kind === 'ENUM';
831
+ })
832
+ .map((f) => f.name)
833
+ : [];
834
+ selections.push(t.field({
835
+ name: objectOutputName,
836
+ selectionSet: t.selectionSet({ selections: fieldNames.map((n) => t.field({ name: n })) }),
837
+ }));
838
+ }
796
839
  if (scalarOutputs.length > 0) {
797
840
  selections.push(...scalarOutputs.map((o) => t.field({ name: o })));
798
841
  }
package/options.d.ts CHANGED
@@ -34,8 +34,6 @@ export interface GraphQLCodegenOptions {
34
34
  reactQueryVersion?: number;
35
35
  };
36
36
  selection?: {
37
- defaultMutationModelFields?: string[];
38
- modelFields?: Record<string, string[]>;
39
37
  mutationInputMode?: 'expanded' | 'model' | 'raw' | 'patchCollapsed';
40
38
  connectionStyle?: 'nodes' | 'edges';
41
39
  forceModelOutput?: boolean;
package/options.js CHANGED
@@ -14,7 +14,7 @@ exports.defaultGraphQLCodegenOptions = {
14
14
  documents: { format: 'gql', convention: 'dashed', allowQueries: [], excludeQueries: [], excludePatterns: [] },
15
15
  features: { emitTypes: true, emitOperations: true, emitSdk: true, emitReactQuery: true },
16
16
  reactQuery: { fetcher: 'graphql-request', legacyMode: false, exposeDocument: false, addInfiniteQuery: false, reactQueryVersion: 5 },
17
- selection: { defaultMutationModelFields: ['id'], modelFields: {}, mutationInputMode: 'patchCollapsed', connectionStyle: 'edges', forceModelOutput: true },
17
+ selection: { mutationInputMode: 'patchCollapsed', connectionStyle: 'edges', forceModelOutput: true },
18
18
  scalars: {},
19
19
  typeNameOverrides: {}
20
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-codegen",
3
- "version": "2.17.38",
3
+ "version": "2.17.39",
4
4
  "description": "Generate queries and mutations for use with Graphile",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "main": "index.js",
@@ -29,7 +29,7 @@
29
29
  "test:watch": "jest --watch"
30
30
  },
31
31
  "devDependencies": {
32
- "@constructive-io/graphql-test": "^2.11.31",
32
+ "@constructive-io/graphql-test": "^2.11.32",
33
33
  "@types/babel__generator": "^7.27.0",
34
34
  "@types/pluralize": "0.0.33",
35
35
  "makage": "^0.1.9"
@@ -48,7 +48,7 @@
48
48
  "graphql-request": "6.1.0",
49
49
  "graphql-tag": "2.12.6",
50
50
  "inflection": "^1.12.0",
51
- "introspectron": "^2.14.36",
51
+ "introspectron": "^2.14.37",
52
52
  "pluralize": "^8.0.0"
53
53
  },
54
54
  "keywords": [
@@ -58,5 +58,5 @@
58
58
  "graphile",
59
59
  "constructive"
60
60
  ],
61
- "gitHead": "09721f934b339bd8c55d2e633abaded6d20b0f65"
61
+ "gitHead": "6883e3b93da28078483bc6aa25862613ef4405b2"
62
62
  }