Skip to content

Commit 4bd0da4

Browse files
authored
fix: references to inputs with consolidated classes (#47)
* fix input references * fix resolver argument case * refactor
1 parent 9a40a3d commit 4bd0da4

File tree

11 files changed

+90
-46
lines changed

11 files changed

+90
-46
lines changed

src/definitions/input.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function buildInputObjectDefinition(
2828
return "";
2929
}
3030

31-
const typeWillBeConsolidated = inputTypeHasMatchingOutputType(node, schema);
31+
const typeWillBeConsolidated = inputTypeHasMatchingOutputType(schema, node);
3232
if (typeWillBeConsolidated) {
3333
return "";
3434
}

src/definitions/interface.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ export function buildInterfaceDefinition(
3636
config,
3737
definitionNode: fieldNode,
3838
});
39-
const fieldDefinition = buildFieldDefinition(fieldNode, node, config);
39+
const fieldDefinition = buildFieldDefinition(
40+
fieldNode,
41+
node,
42+
schema,
43+
config,
44+
);
4045
const fieldText = indent(
4146
`${fieldDefinition}: ${typeToUse.typeName}${
4247
typeToUse.isNullable ? "?" : ""

src/definitions/object.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ ${getDataClassMembers({ node, schema, config, completableFuture: true })}
5959
}
6060

6161
const potentialMatchingInputType = schema.getType(`${name}Input`)?.astNode;
62-
const typeWillBeConsolidated =
63-
potentialMatchingInputType?.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION &&
64-
inputTypeHasMatchingOutputType(potentialMatchingInputType, schema);
62+
const typeWillBeConsolidated = inputTypeHasMatchingOutputType(
63+
schema,
64+
potentialMatchingInputType,
65+
);
6566
const outputRestrictionAnnotation = typeWillBeConsolidated
6667
? ""
6768
: "@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])\n";
@@ -85,7 +86,7 @@ function getDataClassMembers({
8586

8687
return node.fields
8788
?.map((fieldNode) => {
88-
const typeToUse = buildTypeMetadata(fieldNode.type, schema, config);
89+
const typeMetadata = buildTypeMetadata(fieldNode.type, schema, config);
8990
const shouldOverrideField =
9091
!completableFuture &&
9192
node.interfaces?.some((i) => {
@@ -98,19 +99,20 @@ function getDataClassMembers({
9899
const fieldDefinition = buildFieldDefinition(
99100
fieldNode,
100101
node,
102+
schema,
101103
config,
102104
completableFuture,
103105
);
104-
const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeToUse.typeName}${typeToUse.isNullable ? "?" : ""}>`;
105-
const defaultDefinition = `${typeToUse.typeName}${isExternalField(fieldNode) ? (typeToUse.isNullable ? "?" : "") : typeToUse.defaultValue}`;
106+
const completableFutureDefinition = `java.util.concurrent.CompletableFuture<${typeMetadata.typeName}${typeMetadata.isNullable ? "?" : ""}>`;
107+
const defaultDefinition = `${typeMetadata.typeName}${isExternalField(fieldNode) ? (typeMetadata.isNullable ? "?" : "") : typeMetadata.defaultValue}`;
106108
const field = indent(
107109
`${shouldOverrideField ? "override " : ""}${fieldDefinition}: ${completableFuture ? completableFutureDefinition : defaultDefinition}`,
108110
2,
109111
);
110112
const annotations = buildAnnotations({
111113
config,
112114
definitionNode: fieldNode,
113-
resolvedType: typeToUse,
115+
typeMetadata,
114116
});
115117
return `${annotations}${field}`;
116118
})

src/helpers/build-annotations.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,25 @@ export type DefinitionNode =
3232
export function buildAnnotations({
3333
config,
3434
definitionNode,
35-
resolvedType,
35+
typeMetadata,
3636
}: {
3737
config: CodegenConfigWithDefaults;
3838
definitionNode: DefinitionNode;
39-
resolvedType?: TypeMetadata;
39+
typeMetadata?: TypeMetadata;
4040
}) {
4141
const description = definitionNode?.description?.value ?? "";
4242
const descriptionAnnotation = buildDescriptionAnnotation(
4343
description,
4444
definitionNode,
4545
config,
46-
resolvedType,
46+
typeMetadata,
4747
);
4848
const directiveAnnotations = buildDirectiveAnnotations(
4949
definitionNode,
5050
config,
5151
);
52-
const unionAnnotation = resolvedType?.unionAnnotation
53-
? `@${resolvedType.unionAnnotation}\n`
52+
const unionAnnotation = typeMetadata?.unionAnnotation
53+
? `@${typeMetadata.unionAnnotation}\n`
5454
: "";
5555

5656
const annotations = [

src/helpers/build-description-annotation.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ export function buildDescriptionAnnotation(
88
description: string,
99
definitionNode: DefinitionNode,
1010
config: CodegenConfigWithDefaults,
11-
resolvedType?: TypeMetadata,
11+
typeMetadata?: TypeMetadata,
1212
) {
1313
const trimmedDescription = trimDescription(description);
1414
const isDeprecatedDescription = trimmedDescription.startsWith(
1515
deprecatedDescriptionPrefix,
1616
);
17-
if (isDeprecatedDescription && resolvedType?.unionAnnotation) {
17+
if (isDeprecatedDescription && typeMetadata?.unionAnnotation) {
1818
return `@GraphQLDescription("${trimmedDescription}")\n`;
1919
} else if (isDeprecatedDescription) {
2020
const descriptionValue = description.replace(
@@ -36,7 +36,7 @@ export function buildDescriptionAnnotation(
3636
: "";
3737
const trimmedDeprecatedReason = trimDescription(deprecatedReason);
3838

39-
if (deprecatedDirective && resolvedType?.unionAnnotation) {
39+
if (deprecatedDirective && typeMetadata?.unionAnnotation) {
4040
return `@GraphQLDescription("${trimmedDeprecatedReason}")\n`;
4141
} else if (deprecatedDirective) {
4242
const graphqlDescription = trimmedDescription

src/helpers/build-field-definition.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ See the License for the specific language governing permissions and
1111
limitations under the License.
1212
*/
1313

14-
import { buildListType } from "./build-type-metadata";
15-
import { getFieldTypeName } from "./dependent-type-utils";
14+
import { buildTypeMetadata } from "./build-type-metadata";
1615
import {
1716
FieldDefinitionNode,
17+
GraphQLSchema,
1818
InterfaceTypeDefinitionNode,
1919
Kind,
2020
ObjectTypeDefinitionNode,
@@ -26,6 +26,7 @@ import { CodegenConfigWithDefaults } from "./build-config-with-defaults";
2626
export function buildFieldDefinition(
2727
fieldNode: FieldDefinitionNode,
2828
definitionNode: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode,
29+
schema: GraphQLSchema,
2930
config: CodegenConfigWithDefaults,
3031
completableFuture?: boolean,
3132
) {
@@ -36,10 +37,10 @@ export function buildFieldDefinition(
3637
? "fun"
3738
: "suspend fun"
3839
: "val";
39-
const existingFieldArguments = fieldNode.arguments?.map(
40-
(arg) =>
41-
`${arg.name.value}: ${buildListType(arg.type, getFieldTypeName(arg.type))}${arg.type.kind === Kind.NON_NULL_TYPE ? "" : "?"}`,
42-
);
40+
const existingFieldArguments = fieldNode.arguments?.map((arg) => {
41+
const typeMetadata = buildTypeMetadata(arg.type, schema, config);
42+
return `${arg.name.value}: ${typeMetadata.typeName}${arg.type.kind === Kind.NON_NULL_TYPE ? "" : "?"}`;
43+
});
4344
const additionalFieldArguments = config.extraResolverArguments
4445
?.map(({ typeNames, argumentType, argumentName }) => {
4546
const shouldIncludeArg =

src/helpers/build-type-metadata.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ import {
2222
import { getBaseTypeNode } from "@graphql-codegen/visitor-plugin-common";
2323
import { wrapTypeWithModifiers } from "@graphql-codegen/java-common";
2424
import { CodegenConfigWithDefaults } from "./build-config-with-defaults";
25+
import {
26+
getTypeNameWithoutInput,
27+
inputTypeHasMatchingOutputType,
28+
} from "./input-type-has-matching-output-type";
2529

2630
export interface TypeMetadata {
2731
typeName: string;
@@ -73,14 +77,21 @@ export function buildTypeMetadata(
7377
),
7478
};
7579
} else {
80+
const typeWillBeConsolidated = inputTypeHasMatchingOutputType(
81+
schema,
82+
schemaType.astNode,
83+
);
84+
const typeName = typeWillBeConsolidated
85+
? getTypeNameWithoutInput(schemaType.name)
86+
: schemaType.name;
7687
return {
7788
...commonMetadata,
78-
typeName: buildListType(typeNode, schemaType.name),
89+
typeName: buildListType(typeNode, typeName),
7990
};
8091
}
8192
}
8293

83-
export function buildListType(typeNode: TypeNode, typeName: string) {
94+
function buildListType(typeNode: TypeNode, typeName: string) {
8495
const isNullable = typeNode.kind !== Kind.NON_NULL_TYPE;
8596
const listTypeNullableWithNullableMember =
8697
typeNode.kind == Kind.LIST_TYPE &&

src/helpers/dependent-type-utils.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
TypeNode,
2020
} from "graphql";
2121
import { CodegenConfigWithDefaults } from "./build-config-with-defaults";
22+
import { getBaseTypeNode } from "@graphql-codegen/visitor-plugin-common";
2223

2324
export function getDependentFieldTypeNames(
2425
node: TypeDefinitionNode,
@@ -35,20 +36,8 @@ export function getDependentFieldTypeNames(
3536
: [];
3637
}
3738

38-
export function getFieldTypeName(fieldType: TypeNode) {
39-
switch (fieldType.kind) {
40-
case Kind.NAMED_TYPE:
41-
return fieldType.name.value;
42-
case Kind.LIST_TYPE:
43-
return getFieldTypeName(fieldType.type);
44-
case Kind.NON_NULL_TYPE:
45-
switch (fieldType.type.kind) {
46-
case Kind.NAMED_TYPE:
47-
return fieldType.type.name.value;
48-
case Kind.LIST_TYPE:
49-
return getFieldTypeName(fieldType.type.type);
50-
}
51-
}
39+
function getFieldTypeName(fieldType: TypeNode) {
40+
return getBaseTypeNode(fieldType).name.value;
5241
}
5342

5443
export function getDependentInterfaceNames(node: TypeDefinitionNode) {

src/helpers/input-type-has-matching-output-type.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import { Kind, TypeNode } from "graphql/index";
2-
import { GraphQLSchema, InputObjectTypeDefinitionNode } from "graphql";
2+
import { GraphQLSchema, TypeDefinitionNode } from "graphql";
33

44
export function inputTypeHasMatchingOutputType(
5-
inputTypeNode: InputObjectTypeDefinitionNode,
65
schema: GraphQLSchema,
6+
typeNode?: TypeDefinitionNode | null,
77
) {
8-
const typeNameWithoutInput = getTypeNameWithoutInput(
9-
inputTypeNode.name.value,
10-
);
8+
if (typeNode?.kind !== Kind.INPUT_OBJECT_TYPE_DEFINITION) {
9+
return false;
10+
}
11+
12+
const typeNameWithoutInput = getTypeNameWithoutInput(typeNode.name.value);
1113
const matchingType = schema.getType(typeNameWithoutInput)?.astNode;
1214
const matchingTypeFields =
1315
matchingType?.kind === Kind.OBJECT_TYPE_DEFINITION
1416
? matchingType.fields
1517
: [];
16-
const inputFields = inputTypeNode.fields;
18+
const inputFields = typeNode.fields;
1719
const fieldsMatch = matchingTypeFields?.every((field) => {
1820
const matchingInputField = inputFields?.find(
1921
(inputField) => inputField.name.value === field.name.value,
@@ -24,7 +26,7 @@ export function inputTypeHasMatchingOutputType(
2426
return Boolean(matchingTypeFields?.length && fieldsMatch);
2527
}
2628

27-
function getTypeNameWithoutInput(name: string) {
29+
export function getTypeNameWithoutInput(name: string) {
2830
return name.endsWith("Input") ? name.replace("Input", "") : name;
2931
}
3032

test/unit/should_consolidate_input_and_output_types/expected.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,23 @@ data class MyTypeWhereFieldsDoNotMatchInput(
5757
val field: String? = null,
5858
val field2: Int? = null
5959
)
60+
61+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.OBJECT])
62+
data class MyTypeToConsolidateParent(
63+
val field: MyTypeToConsolidate? = null
64+
)
65+
66+
@GraphQLValidObjectLocations(locations = [GraphQLValidObjectLocations.Locations.INPUT_OBJECT])
67+
data class MyTypeToConsolidateInputParent(
68+
val field: MyTypeToConsolidate? = null
69+
)
70+
71+
@GraphQLIgnore
72+
interface MyTypeToConsolidateParent2 {
73+
suspend fun field(input: MyTypeToConsolidate): String? = null
74+
}
75+
76+
@GraphQLIgnore
77+
interface MyTypeToConsolidateParent2CompletableFuture {
78+
fun field(input: MyTypeToConsolidate): java.util.concurrent.CompletableFuture<String?>
79+
}

0 commit comments

Comments
 (0)