From f223cb19e6ec3cb58f92d30cf3bf3790545b6bce Mon Sep 17 00:00:00 2001 From: Panagiotis Date: Wed, 9 Oct 2024 12:44:34 +0300 Subject: [PATCH 1/2] fix(discriminator): union nullable --- src/core/ir/discriminator.rs | 16 +++-- .../snapshots/test-union-optional.md_0.snap | 15 +++++ .../test-union-optional.md_client.snap | 59 +++++++++++++++++++ .../test-union-optional.md_merged.snap | 23 ++++++++ tests/execution/test-union-optional.md | 43 ++++++++++++++ 5 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 tests/core/snapshots/test-union-optional.md_0.snap create mode 100644 tests/core/snapshots/test-union-optional.md_client.snap create mode 100644 tests/core/snapshots/test-union-optional.md_merged.snap create mode 100644 tests/execution/test-union-optional.md diff --git a/src/core/ir/discriminator.rs b/src/core/ir/discriminator.rs index 127cc59414..ee534da1c4 100644 --- a/src/core/ir/discriminator.rs +++ b/src/core/ir/discriminator.rs @@ -36,10 +36,14 @@ where if let Some(obj) = self.as_object_mut() { obj.insert_key(TYPENAME_FIELD, T::string(type_name.into())); - Ok(()) - } else { - bail!("Expected object") + return Ok(()); } + + if self.is_null() { + return Ok(()); + } + + bail!("Value expected to be object") } } @@ -70,6 +74,8 @@ pub struct Discriminator { /// Set of all fields that are part of types with /// the [FieldInfo] about their relations to types. fields_info: IndexMap, + /// The name of parent type + name: String, } impl std::fmt::Debug for Discriminator { @@ -227,7 +233,7 @@ impl Discriminator { .collect() }; - let discriminator = Self { fields_info, types }; + let discriminator = Self { fields_info, types, name: union_name.to_string() }; tracing::debug!( "Generated discriminator for union type '{union_name}':\n{discriminator:?}", @@ -238,7 +244,7 @@ impl Discriminator { pub fn resolve_type(&self, value: &Value) -> Result<&str> { let Value::Object(obj) = value else { - bail!("Value expected to be object"); + return Ok(&self.name); }; let mut possible_types = Repr::all_covered(self.types.len()); diff --git a/tests/core/snapshots/test-union-optional.md_0.snap b/tests/core/snapshots/test-union-optional.md_0.snap new file mode 100644 index 0000000000..ee973d9b45 --- /dev/null +++ b/tests/core/snapshots/test-union-optional.md_0.snap @@ -0,0 +1,15 @@ +--- +source: tests/core/spec.rs +expression: response +--- +{ + "status": 200, + "headers": { + "content-type": "application/json" + }, + "body": { + "data": { + "nodes": null + } + } +} diff --git a/tests/core/snapshots/test-union-optional.md_client.snap b/tests/core/snapshots/test-union-optional.md_client.snap new file mode 100644 index 0000000000..6af9763662 --- /dev/null +++ b/tests/core/snapshots/test-union-optional.md_client.snap @@ -0,0 +1,59 @@ +--- +source: tests/core/spec.rs +expression: formatted +--- +scalar Bytes + +scalar Date + +scalar DateTime + +scalar Email + +scalar Empty + +scalar Int128 + +scalar Int16 + +scalar Int32 + +scalar Int64 + +scalar Int8 + +scalar JSON + +union Node = Page | User + +type Page { + id: ID! + slug: String! +} + +scalar PhoneNumber + +type Query { + nodes: Node +} + +scalar UInt128 + +scalar UInt16 + +scalar UInt32 + +scalar UInt64 + +scalar UInt8 + +scalar Url + +type User { + id: ID! + username: String! +} + +schema { + query: Query +} diff --git a/tests/core/snapshots/test-union-optional.md_merged.snap b/tests/core/snapshots/test-union-optional.md_merged.snap new file mode 100644 index 0000000000..1e4e7086c9 --- /dev/null +++ b/tests/core/snapshots/test-union-optional.md_merged.snap @@ -0,0 +1,23 @@ +--- +source: tests/core/spec.rs +expression: formatter +--- +schema @server @upstream { + query: Query +} + +union Node = Page | User + +type Page { + id: ID! + slug: String! +} + +type Query { + nodes: Node @expr +} + +type User { + id: ID! + username: String! +} diff --git a/tests/execution/test-union-optional.md b/tests/execution/test-union-optional.md new file mode 100644 index 0000000000..238374f5f2 --- /dev/null +++ b/tests/execution/test-union-optional.md @@ -0,0 +1,43 @@ +# Test union optional + +```graphql @config +schema @server { + query: Query +} + +type Query { + nodes: Node @expr(body: null) +} + +union Node = User | Page + +type User { + id: ID! + username: String! +} + +type Page { + id: ID! + slug: String! +} +``` + +```yml @test +- method: POST + url: http://localhost:8080/graphql + body: + query: | + { + nodes { + __typename + ... on Page { + id + slug + } + ... on User { + id + username + } + } + } +``` From b0366aaacb8caa45371d0e2b2ae9260848817269 Mon Sep 17 00:00:00 2001 From: Panagiotis Date: Wed, 9 Oct 2024 17:32:30 +0300 Subject: [PATCH 2/2] fix: unit tests --- src/core/ir/discriminator.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/ir/discriminator.rs b/src/core/ir/discriminator.rs index ee534da1c4..76630061e9 100644 --- a/src/core/ir/discriminator.rs +++ b/src/core/ir/discriminator.rs @@ -1234,17 +1234,15 @@ mod tests { assert_eq!( discriminator .resolve_type(&Value::from_json(json!("string")).unwrap()) - .unwrap_err() - .to_string(), - "Value expected to be object" + .unwrap(), + "Test" ); assert_eq!( discriminator .resolve_type(&Value::from_json(json!(25)).unwrap()) - .unwrap_err() - .to_string(), - "Value expected to be object" + .unwrap(), + "Test" ); } }