Skip to content

Commit

Permalink
feat: Support @OneOf (#358)
Browse files Browse the repository at this point in the history
Closes #354
  • Loading branch information
budde377 authored Aug 31, 2024
1 parent 4751004 commit 26c47db
Show file tree
Hide file tree
Showing 6 changed files with 592 additions and 30 deletions.
13 changes: 13 additions & 0 deletions packages/graphql_codegen/lib/src/context/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ abstract class Context<TKey extends Object, TType extends TypeDefinitionNode> {
) !=
null;

bool get isOneOf => false;

Name get path => throw StateError("Path not available");

Context withNameAndType(
Expand Down Expand Up @@ -680,6 +682,17 @@ class ContextInput<TKey extends Object>
NameNode get currentTypeName => currentType.name;

final bool isDefinitionContext = true;

bool get isOneOf {
final hasOneOfDirective = currentType.directives
.any((directive) => directive.name.value == 'oneOf');

final allFieldsAreNullable = currentType.fields.every(
(field) => !field.type.isNonNull,
);

return hasOneOfDirective && allFieldsAreNullable;
}
}

class ContextOperation<TKey extends Object>
Expand Down
94 changes: 64 additions & 30 deletions packages/graphql_codegen/lib/src/printer/base/input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ import 'package:graphql_codegen/src/printer/utils.dart';

List<Spec> printInputClasses(PrintContext<ContextInput> context) =>
_printInputClasses(
context,
context.namePrinter.printClassName,
context.context.properties,
context: context,
name: context.namePrinter.printClassName,
properties: context.context.properties,
);

List<Spec> printVariableClasses(PrintContext context) => _printInputClasses(
context,
context.namePrinter.printVariableClassName,
context.context.variables,
context: context,
name: context.namePrinter.printVariableClassName,
properties: context.context.variables,
);

List<Spec> _printInputClasses(
PrintContext context,
String Function(Name) name,
Iterable<ContextProperty> properties,
) {
List<Spec> _printInputClasses({
required PrintContext context,
required String Function(Name) name,
required Iterable<ContextProperty> properties,
}) {
final factoryParameters = ListBuilder<Parameter>(
properties.map(
(property) => Parameter(
Expand All @@ -51,31 +51,65 @@ List<Spec> _printInputClasses(
(b) => b
..name = name(context.path)
..constructors = ListBuilder([
Constructor(
(b) => b
..factory = true
..optionalParameters = factoryParameters
..body = refer(name(context.path)).property('_').call([
CodeExpression(Code(
"""
if (context.context.isOneOf)
...properties.map(
(property) => Constructor(
(b) => b
..requiredParameters = ListBuilder([
Parameter(
(b) => b
..name = context.namePrinter.printPropertyName(
property.name,
)
..type = asNonNullable(
printClassPropertyType(
context,
property,
),
),
)
])
..factory = true
..name = context.namePrinter.printPropertyName(property.name)
..body = refer(name(context.path)).property('_').call([
literalMap(
{
property.name.value: refer(
context.namePrinter.printPropertyName(
property.name,
),
),
},
),
]).code,
),
)
else
Constructor(
(b) => b
..factory = true
..optionalParameters = factoryParameters
..body = refer(name(context.path)).property('_').call([
CodeExpression(Code(
"""
{
${properties.map((property) {
final key = property.name.value;
final value =
context.namePrinter.printPropertyName(property.name);
final entry = "r'${key}': ${value},";
if (property.isRequired) {
return entry;
}
return """
final key = property.name.value;
final value =
context.namePrinter.printPropertyName(property.name);
final entry = "r'${key}': ${value},";
if (property.isRequired) {
return entry;
}
return """
if (${value} != null) ${entry}
""";
}).join()}
}).join()}
}
""",
)),
]).code,
),
)),
]).code,
),
Constructor((b) => b
..name = '_'
..requiredParameters = ListBuilder([
Expand Down
7 changes: 7 additions & 0 deletions packages/graphql_codegen/lib/src/printer/base/property.dart
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,13 @@ TypeReference asNullable(TypeReference reference) => TypeReference(
..types = reference.types.toBuilder(),
);

TypeReference asNonNullable(TypeReference reference) => TypeReference(
(b) => b
..isNullable = false
..symbol = reference.symbol
..types = reference.types.toBuilder(),
);

TypeReference _asList(TypeReference reference) => TypeReference(
(b) => b
..symbol = 'List'
Expand Down
11 changes: 11 additions & 0 deletions packages/graphql_codegen/test/assets/input_oneOf/input.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
input I1 @oneOf {
v1: Int
v2: Int
v3: Int
}

input I2 @oneOf {
v1: Int
v2: Int
v3: Int!
}
Loading

0 comments on commit 26c47db

Please sign in to comment.