use crate::query_planner::{
tests::testkit::{build_query_plan_with_defaults, init_logger},
utils::parsing::parse_operation,
};
use std::error::Error;
#[test]
fn interface_object_field_local() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
# Resolves `[NodeWithName]`
# where `NodeWithName` is an object type with @interfaceObject.
anotherUsers {
id
name
# The `username` field is in another subgraph.
# We do not query `username` of a specific object type,
# we query `NodeWithName.username`.
# The `NodeWithName` is an interface type with `@key`, so
# we're able to perform an entity call directly to NodeWithName,
# and fetch it.
username
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
anotherUsers {
__typename
id
username
}
}
},
Flatten(path: "anotherUsers.@") {
Fetch(service: "a") {
{
... on NodeWithName {
__typename
id
}
} =>
{
... on NodeWithName {
name
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_field_remote() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
users {
id
name
username
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
users {
__typename
id
name
}
}
},
Flatten(path: "users.@") {
Fetch(service: "b") {
{
... on NodeWithName {
__typename
id
}
} =>
{
... on NodeWithName {
username
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_field_local_object_type() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
anotherUsers {
... on User {
age
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
anotherUsers {
__typename
id
}
}
},
Flatten(path: "anotherUsers.@") {
Fetch(service: "a") {
{
... on NodeWithName {
__typename
id
}
} =>
{
... on NodeWithName {
__typename
... on User {
age
}
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_to_object_type_locally() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
users {
... on User {
age
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Fetch(service: "a") {
{
users {
__typename
... on User {
age
}
}
}
},
},
"#);
Ok(())
}
#[test]
fn interface_object_with_inline_fragment_resolving_remote_interface_field_simple(
) -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
anotherUsers {
... on User {
username
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
anotherUsers {
__typename
id
}
}
},
Flatten(path: "anotherUsers.@") {
Fetch(service: "a") {
{
... on NodeWithName {
__typename
id
}
} =>
{
... on NodeWithName {
__typename
}
}
},
},
Flatten(path: "anotherUsers.@") {
Fetch(service: "b") {
{
... on User {
__typename
id
}
} =>
{
... on NodeWithName {
username
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_with_inline_fragment_resolving_remote_interface_field(
) -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
anotherUsers {
... on User {
age
id
name
username
}
id
name
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
anotherUsers {
__typename
id
}
}
},
Flatten(path: "anotherUsers.@") {
Fetch(service: "a") {
{
... on NodeWithName {
__typename
id
}
} =>
{
... on NodeWithName {
__typename
... on User {
age
name
}
name
}
}
},
},
Flatten(path: "anotherUsers.@") {
Fetch(service: "b") {
{
... on User {
__typename
id
}
} =>
{
... on NodeWithName {
id
username
}
}
},
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "b",
"operationKind": "query",
"operation": "{anotherUsers{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "anotherUsers"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on NodeWithName{__typename ...on User{age name} name}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "NodeWithName",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
],
"inputRewrites": [
{
"ValueSetter": {
"path": [
{
"TypenameEquals": [
"NodeWithName"
]
},
{
"Key": "__typename"
}
],
"setValueTo": "NodeWithName"
}
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "anotherUsers"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "b",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on NodeWithName{id username}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "User",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
],
"inputRewrites": [
{
"ValueSetter": {
"path": [
{
"TypenameEquals": [
"NodeWithName"
]
},
{
"Key": "__typename"
}
],
"setValueTo": "NodeWithName"
}
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn interface_field_with_inline_fragment_resolving_remote_interface_object_field(
) -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
users {
... on User {
age
id
name
username
}
id
name
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
users {
__typename
... on User {
__typename
age
id
name
}
id
name
}
}
},
Flatten(path: "users.@|[User]") {
Fetch(service: "b") {
{
... on User {
__typename
id
}
} =>
{
... on NodeWithName {
username
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_field_local_direct_resolution() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
accounts {
name
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Fetch(service: "b") {
{
accounts {
name
}
}
},
},
"#);
Ok(())
}
#[test]
fn interface_object_field_with_inline_fragment_requiring_typename_check(
) -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
accounts {
... on Admin {
name
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
accounts {
__typename
id
}
}
},
Flatten(path: "accounts.@") {
Fetch(service: "a") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
__typename
}
}
},
},
Flatten(path: "accounts.@") {
Fetch(service: "b") {
{
... on Admin {
__typename
id
}
} =>
{
... on Account {
name
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_field_local_with_remote_typename() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
accounts {
name
__typename
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
accounts {
__typename
name
id
}
}
},
Flatten(path: "accounts.@") {
Fetch(service: "a") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
__typename
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_inline_fragment_with_remote_typename() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
accounts {
... on Admin {
__typename
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
accounts {
__typename
id
}
}
},
Flatten(path: "accounts.@") {
Fetch(service: "a") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
__typename
... on Admin {
__typename
}
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_local_id_remote_field() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
accounts {
id
isActive
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
accounts {
__typename
id
}
}
},
Flatten(path: "accounts.@") {
Fetch(service: "c") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
isActive
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_local_id_remote_field_with_inline_fragment() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
accounts {
# NOTE
# id is available in the interfaceObject and can be resolved as there's no type condition involved
id
... on Admin {
isActive
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-interface-object.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
accounts {
__typename
id
}
}
},
Flatten(path: "accounts.@") {
Fetch(service: "a") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
__typename
... on Admin {
isActive
}
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_list_field_with_type_condition() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
{
me {
friends {
... on User {
name
}
credits
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/interface-object-nested-list.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "social") {
{
me {
friends {
__typename
id
credits
}
}
}
},
Flatten(path: "me.friends.@") {
Fetch(service: "users") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
__typename
... on User {
name
}
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn interface_object_type_condition_on_root_field() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
{
me {
... on User {
name
}
}
}
"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/interface-object-nested-list.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "social") {
{
me {
__typename
id
}
}
},
Flatten(path: "me") {
Fetch(service: "users") {
{
... on Account {
__typename
id
}
} =>
{
... on Account {
__typename
... on User {
name
}
}
}
},
},
},
},
"#);
Ok(())
}