Skip to content

Commit 0ad37ba

Browse files
committed
support auto exhaustive
1 parent 908ebe8 commit 0ad37ba

File tree

7 files changed

+126
-11
lines changed

7 files changed

+126
-11
lines changed

compiler/crates/relay-transforms/src/validations/validate_exhaustive_directive.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,16 @@ impl<'schema, 'program, 'pc> ExhaustiveDirectiveValidator<'schema, 'program, 'pc
380380
.named(*NON_EXHAUSTIVE_DIRECTIVE_NAME)
381381
.is_some();
382382

383+
// Determine the type against which to validate coverage.
384+
let target_type = if let Some(type_condition) = inline_fragment.type_condition {
385+
type_condition
386+
} else if let Some(parent_type) = self.parent_type {
387+
parent_type
388+
} else {
389+
// Should not happen in practice, but bail out safely.
390+
return;
391+
};
392+
383393
if let Some(directive) = inline_fragment.directives.named(*EXHAUSTIVE_DIRECTIVE_NAME) {
384394
has_directive = true;
385395
let (parsed_ignored, parsed_disabled) =
@@ -388,22 +398,14 @@ impl<'schema, 'program, 'pc> ExhaustiveDirectiveValidator<'schema, 'program, 'pc
388398
disabled = parsed_disabled;
389399
} else if has_non_exhaustive {
390400
return;
401+
} else if self.type_is_auto_exhaustive(target_type) {
402+
has_directive = true;
391403
}
392404

393405
if !has_directive || disabled {
394406
return;
395407
}
396408

397-
// Determine the type against which to validate coverage.
398-
let target_type = if let Some(type_condition) = inline_fragment.type_condition {
399-
type_condition
400-
} else if let Some(parent_type) = self.parent_type {
401-
parent_type
402-
} else {
403-
// Should not happen in practice, but bail out safely.
404-
return;
405-
};
406-
407409
let (missing_members, type_description) = match target_type {
408410
Type::Union(id) => (
409411
self.check_exhaustive_union_coverage(id, &ignored, |object_id| {

compiler/crates/relay-transforms/tests/validate_exhaustive_directive.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use relay_transforms::validate_exhaustive_directive;
1313

1414
pub async fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
1515
apply_transform_for_test(fixture, |program| {
16-
let auto_exhaustive_types = if fixture.file_name.contains("auto-type") {
16+
let auto_exhaustive_types = if fixture.file_name.contains("auto-type")
17+
|| fixture.file_name.contains("inline-fragment-auto-type")
18+
{
1719
vec!["UserNameRenderer".intern()]
1820
} else {
1921
vec![]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
==================================== INPUT ====================================
2+
#expected-to-throw
3+
query InlineFragmentAutoTypeMissing {
4+
me {
5+
nameRenderer @nonExhaustive {
6+
... {
7+
... on PlainUserNameRenderer { __typename }
8+
... on MarkdownUserNameRenderer { __typename }
9+
}
10+
}
11+
}
12+
}
13+
==================================== ERROR ====================================
14+
✖︎ Inline fragment marked with @exhaustive is missing selection for union members: 'CustomNameRenderer'.
15+
16+
inline-fragment-auto-type-missing.invalid.graphql:5:7
17+
4 │ nameRenderer @nonExhaustive {
18+
5 │ ... {
19+
│ ^^^
20+
6 │ ... on PlainUserNameRenderer { __typename }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#expected-to-throw
2+
query InlineFragmentAutoTypeMissing {
3+
me {
4+
nameRenderer @nonExhaustive {
5+
... {
6+
... on PlainUserNameRenderer { __typename }
7+
... on MarkdownUserNameRenderer { __typename }
8+
}
9+
}
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
==================================== INPUT ====================================
2+
query InlineFragmentWithAliasExhaustive {
3+
me {
4+
nameRenderer {
5+
... @alias(as: "widget") @exhaustive {
6+
... on PlainUserNameRenderer { __typename }
7+
... on MarkdownUserNameRenderer { __typename }
8+
... on CustomNameRenderer { __typename }
9+
}
10+
}
11+
}
12+
}
13+
==================================== OUTPUT ===================================
14+
query InlineFragmentWithAliasExhaustive {
15+
me {
16+
nameRenderer {
17+
... @alias(as: "widget") @exhaustive {
18+
... on PlainUserNameRenderer {
19+
__typename
20+
}
21+
... on MarkdownUserNameRenderer {
22+
__typename
23+
}
24+
... on CustomNameRenderer {
25+
__typename
26+
}
27+
}
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
query InlineFragmentWithAliasExhaustive {
2+
me {
3+
nameRenderer {
4+
... @alias(as: "widget") @exhaustive {
5+
... on PlainUserNameRenderer { __typename }
6+
... on MarkdownUserNameRenderer { __typename }
7+
... on CustomNameRenderer { __typename }
8+
}
9+
}
10+
}
11+
}
12+

compiler/crates/relay-transforms/tests/validate_exhaustive_directive_test.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,25 @@ async fn interface_all_members_valid() {
189189
.await;
190190
}
191191

192+
#[tokio::test]
193+
async fn inline_fragment_with_alias_exhaustive() {
194+
let input = include_str!(
195+
"validate_exhaustive_directive/fixtures/inline-fragment-with-alias-exhaustive.graphql"
196+
);
197+
let expected = include_str!(
198+
"validate_exhaustive_directive/fixtures/inline-fragment-with-alias-exhaustive.expected"
199+
);
200+
test_fixture(
201+
transform_fixture,
202+
file!(),
203+
"inline-fragment-with-alias-exhaustive.graphql",
204+
"validate_exhaustive_directive/fixtures/inline-fragment-with-alias-exhaustive.expected",
205+
input,
206+
expected,
207+
)
208+
.await;
209+
}
210+
192211
#[tokio::test]
193212
async fn interface_missing_member() {
194213
let input = include_str!(
@@ -245,3 +264,22 @@ async fn inline_fragment_missing_member() {
245264
)
246265
.await;
247266
}
267+
268+
#[tokio::test]
269+
async fn inline_fragment_auto_type_missing() {
270+
let input = include_str!(
271+
"validate_exhaustive_directive/fixtures/inline-fragment-auto-type-missing.invalid.graphql"
272+
);
273+
let expected = include_str!(
274+
"validate_exhaustive_directive/fixtures/inline-fragment-auto-type-missing.invalid.expected"
275+
);
276+
test_fixture(
277+
transform_fixture,
278+
file!(),
279+
"inline-fragment-auto-type-missing.invalid.graphql",
280+
"validate_exhaustive_directive/fixtures/inline-fragment-auto-type-missing.invalid.expected",
281+
input,
282+
expected,
283+
)
284+
.await;
285+
}

0 commit comments

Comments
 (0)