Skip to content

Commit 26c47db

Browse files
authored
feat: Support @OneOf (#358)
Closes #354
1 parent 4751004 commit 26c47db

6 files changed

Lines changed: 592 additions & 30 deletions

File tree

packages/graphql_codegen/lib/src/context/context.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,8 @@ abstract class Context<TKey extends Object, TType extends TypeDefinitionNode> {
491491
) !=
492492
null;
493493

494+
bool get isOneOf => false;
495+
494496
Name get path => throw StateError("Path not available");
495497

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

682684
final bool isDefinitionContext = true;
685+
686+
bool get isOneOf {
687+
final hasOneOfDirective = currentType.directives
688+
.any((directive) => directive.name.value == 'oneOf');
689+
690+
final allFieldsAreNullable = currentType.fields.every(
691+
(field) => !field.type.isNonNull,
692+
);
693+
694+
return hasOneOfDirective && allFieldsAreNullable;
695+
}
683696
}
684697

685698
class ContextOperation<TKey extends Object>

packages/graphql_codegen/lib/src/printer/base/input.dart

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ import 'package:graphql_codegen/src/printer/utils.dart';
1313

1414
List<Spec> printInputClasses(PrintContext<ContextInput> context) =>
1515
_printInputClasses(
16-
context,
17-
context.namePrinter.printClassName,
18-
context.context.properties,
16+
context: context,
17+
name: context.namePrinter.printClassName,
18+
properties: context.context.properties,
1919
);
2020

2121
List<Spec> printVariableClasses(PrintContext context) => _printInputClasses(
22-
context,
23-
context.namePrinter.printVariableClassName,
24-
context.context.variables,
22+
context: context,
23+
name: context.namePrinter.printVariableClassName,
24+
properties: context.context.variables,
2525
);
2626

27-
List<Spec> _printInputClasses(
28-
PrintContext context,
29-
String Function(Name) name,
30-
Iterable<ContextProperty> properties,
31-
) {
27+
List<Spec> _printInputClasses({
28+
required PrintContext context,
29+
required String Function(Name) name,
30+
required Iterable<ContextProperty> properties,
31+
}) {
3232
final factoryParameters = ListBuilder<Parameter>(
3333
properties.map(
3434
(property) => Parameter(
@@ -51,31 +51,65 @@ List<Spec> _printInputClasses(
5151
(b) => b
5252
..name = name(context.path)
5353
..constructors = ListBuilder([
54-
Constructor(
55-
(b) => b
56-
..factory = true
57-
..optionalParameters = factoryParameters
58-
..body = refer(name(context.path)).property('_').call([
59-
CodeExpression(Code(
60-
"""
54+
if (context.context.isOneOf)
55+
...properties.map(
56+
(property) => Constructor(
57+
(b) => b
58+
..requiredParameters = ListBuilder([
59+
Parameter(
60+
(b) => b
61+
..name = context.namePrinter.printPropertyName(
62+
property.name,
63+
)
64+
..type = asNonNullable(
65+
printClassPropertyType(
66+
context,
67+
property,
68+
),
69+
),
70+
)
71+
])
72+
..factory = true
73+
..name = context.namePrinter.printPropertyName(property.name)
74+
..body = refer(name(context.path)).property('_').call([
75+
literalMap(
76+
{
77+
property.name.value: refer(
78+
context.namePrinter.printPropertyName(
79+
property.name,
80+
),
81+
),
82+
},
83+
),
84+
]).code,
85+
),
86+
)
87+
else
88+
Constructor(
89+
(b) => b
90+
..factory = true
91+
..optionalParameters = factoryParameters
92+
..body = refer(name(context.path)).property('_').call([
93+
CodeExpression(Code(
94+
"""
6195
{
6296
${properties.map((property) {
63-
final key = property.name.value;
64-
final value =
65-
context.namePrinter.printPropertyName(property.name);
66-
final entry = "r'${key}': ${value},";
67-
if (property.isRequired) {
68-
return entry;
69-
}
70-
return """
97+
final key = property.name.value;
98+
final value =
99+
context.namePrinter.printPropertyName(property.name);
100+
final entry = "r'${key}': ${value},";
101+
if (property.isRequired) {
102+
return entry;
103+
}
104+
return """
71105
if (${value} != null) ${entry}
72106
""";
73-
}).join()}
107+
}).join()}
74108
}
75109
""",
76-
)),
77-
]).code,
78-
),
110+
)),
111+
]).code,
112+
),
79113
Constructor((b) => b
80114
..name = '_'
81115
..requiredParameters = ListBuilder([

packages/graphql_codegen/lib/src/printer/base/property.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,13 @@ TypeReference asNullable(TypeReference reference) => TypeReference(
197197
..types = reference.types.toBuilder(),
198198
);
199199

200+
TypeReference asNonNullable(TypeReference reference) => TypeReference(
201+
(b) => b
202+
..isNullable = false
203+
..symbol = reference.symbol
204+
..types = reference.types.toBuilder(),
205+
);
206+
200207
TypeReference _asList(TypeReference reference) => TypeReference(
201208
(b) => b
202209
..symbol = 'List'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
input I1 @oneOf {
2+
v1: Int
3+
v2: Int
4+
v3: Int
5+
}
6+
7+
input I2 @oneOf {
8+
v1: Int
9+
v2: Int
10+
v3: Int!
11+
}

0 commit comments

Comments
 (0)