Skip to content

Commit 4326695

Browse files
authored
feat: add @oneOf support to introspection (#1177)
1 parent 2dec9c4 commit 4326695

File tree

13 files changed

+209
-8
lines changed

13 files changed

+209
-8
lines changed

cynic-cli/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Options:
8888
Possible values:
8989
- 2018: Run an introspection query compatible with the 2018 GraphQL specification
9090
- 2021: Run an introspection query compatible with the 2021 GraphQL specification
91+
- 2025: Run an introspection query compatible with the 2025 GraphQL specification
9192
- auto: Run an additional query to determine what the GraphQL server supports
9293

9394
-h, --help

cynic-cli/src/introspect.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub(crate) fn introspect(args: IntrospectArgs) -> Result<(), IntrospectError> {
1212
let capabilities = match args.server_version {
1313
GraphQlVersion::TwentyEighteen => SpecificationVersion::June2018.capabilities(),
1414
GraphQlVersion::TwentyTwentyOne => SpecificationVersion::October2021.capabilities(),
15+
GraphQlVersion::TwentyTwentyFive => SpecificationVersion::September2025.capabilities(),
1516
GraphQlVersion::AutoDetect => detect_capabilities(&client, &args)?,
1617
};
1718

cynic-cli/src/main.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ enum GraphQlVersion {
9696
/// Run an introspection query compatible with the 2021 GraphQL specification
9797
#[value(name = "2021")]
9898
TwentyTwentyOne,
99+
/// Run an introspection query compatible with the 2025 GraphQL specification
100+
#[value(name = "2025")]
101+
TwentyTwentyFive,
99102
/// Run an additional query to determine what the GraphQL server supports
100103
#[value(name = "auto")]
101104
#[default]
@@ -107,6 +110,7 @@ impl std::fmt::Display for GraphQlVersion {
107110
match self {
108111
GraphQlVersion::TwentyEighteen => write!(f, "2018"),
109112
GraphQlVersion::TwentyTwentyOne => write!(f, "2021"),
113+
GraphQlVersion::TwentyTwentyFive => write!(f, "2025"),
110114
GraphQlVersion::AutoDetect => write!(f, "auto"),
111115
}
112116
}

cynic-cli/tests/cases/help/introspect-help.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Options:
2929
Possible values:
3030
- 2018: Run an introspection query compatible with the 2018 GraphQL specification
3131
- 2021: Run an introspection query compatible with the 2021 GraphQL specification
32+
- 2025: Run an introspection query compatible with the 2025 GraphQL specification
3233
- auto: Run an additional query to determine what the GraphQL server supports
3334

3435
-h, --help

cynic-introspection/src/detection.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,15 @@ impl CapabilitiesQuery {
5959
.iter()
6060
.find(|field| field.name == "specifiedByURL");
6161

62-
match specified_by_field {
63-
Some(_) => SpecificationVersion::October2021,
64-
None => SpecificationVersion::June2018,
62+
let one_of_field = type_type
63+
.fields
64+
.iter()
65+
.find(|field| field.name == "isOneOf");
66+
67+
match (one_of_field, specified_by_field) {
68+
(Some(_), _) => SpecificationVersion::September2025,
69+
(None, Some(_)) => SpecificationVersion::October2021,
70+
_ => SpecificationVersion::June2018,
6571
}
6672
}
6773
}
@@ -78,6 +84,8 @@ pub enum SpecificationVersion {
7884
June2018,
7985
/// The GraphQL specification published in October 2021
8086
October2021,
87+
/// The GraphQL specification published in September 2025
88+
September2025,
8189
}
8290

8391
#[derive(cynic::QueryFragment, Debug)]

cynic-introspection/src/query.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ pub struct Type {
7878
/// A URL pointing to a specification for this scalar, if there is one
7979
#[cynic(rename = "specifiedByURL", feature = "2021")]
8080
pub specified_by_url: Option<String>,
81+
/// Whether this type is a oneOf input object.
82+
///
83+
/// This will be present on input objects from servers supporting `oneOf`
84+
/// and null on other types
85+
#[cynic(feature = "2025")]
86+
pub is_one_of: Option<bool>,
8187
}
8288

8389
#[derive(cynic::QueryFragment, Debug)]

cynic-introspection/src/query_builder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ impl IntrospectionQuery {
99
match capabilities.specification_version {
1010
SpecificationVersion::Unknown | SpecificationVersion::June2018 => {}
1111
SpecificationVersion::October2021 => builder.enable_feature("2021"),
12+
SpecificationVersion::September2025 => {
13+
builder.enable_feature("2021");
14+
builder.enable_feature("2025");
15+
}
1216
}
1317
builder.build().expect("to succeed")
1418
}

cynic-introspection/src/schema.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ type __Type {
3434
ofType: __Type
3535
# may be non-null for custom SCALAR, otherwise null.
3636
specifiedByURL: String
37+
# must be non-null for INPUT_OBJECT, otherwise null.
38+
isOneOf: Boolean
3739
}
3840

3941
enum __TypeKind {

cynic-introspection/src/schema/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ pub struct InputObjectType {
102102
pub description: Option<String>,
103103
/// The fields of the input object
104104
pub fields: Vec<InputValue>,
105+
/// Whether this object is a oneOf input object or not
106+
pub is_one_of: bool,
105107
}
106108

107109
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -433,6 +435,7 @@ impl TryFrom<crate::query::Type> for Type {
433435
.into_iter()
434436
.map(InputValue::try_from)
435437
.collect::<Result<Vec<_>, _>>()?,
438+
is_one_of: ty.is_one_of.unwrap_or_default(),
436439
})),
437440
crate::query::TypeKind::List => Err(SchemaError::UnexpectedList),
438441
crate::query::TypeKind::NonNull => Err(SchemaError::UnexpectedNonNull),

cynic-introspection/src/schema/sdl.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,21 @@ impl std::fmt::Display for TypeDisplay<'_> {
126126
name,
127127
description,
128128
fields,
129+
is_one_of,
129130
}) => {
130131
write!(f, "{}", DescriptionDisplay(description.as_deref()))?;
131-
if fields.is_empty() {
132-
writeln!(f, "input {name}")
133-
} else {
134-
writeln!(f, "input {name} {{")?;
132+
write!(f, "input {name}")?;
133+
if *is_one_of {
134+
write!(f, " @oneOf")?;
135+
}
136+
if !fields.is_empty() {
137+
writeln!(f, " {{")?;
135138
for field in fields {
136139
writeln!(indented(f), "{}", InputValueDisplay(field))?;
137140
}
138-
writeln!(f, "}}\n")
141+
writeln!(f, "}}")?;
139142
}
143+
writeln!(f)
140144
}
141145
Type::Enum(EnumType {
142146
name,

0 commit comments

Comments
 (0)