use crate::query_planner::{
tests::testkit::{build_query_plan_with_defaults, init_logger},
utils::parsing::parse_operation,
};
use std::error::Error;
#[test]
fn fed_audit_requires_with_argument_conflict() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
products {
upc
name
shippingEstimate
shippingEstimateEUR
isExpensiveCategory
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/requires-with-argument-conflict.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "b") {
{
products {
__typename
upc
name
price(currency: "USD")
weight
_internal_qp_alias_0: price(currency: "EUR")
category {
averagePrice(currency: "USD")
}
}
}
},
BatchFetch(service: "a") {
{
_e0 {
paths: [
"products.@"
]
{
... on Product {
__typename
category {
averagePrice
}
upc
price: _internal_qp_alias_0
weight
}
}
}
_e1 {
paths: [
"products.@"
]
{
... on Product {
__typename
price
weight
upc
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Product {
isExpensiveCategory
shippingEstimateEUR
}
}
_e1: _entities(representations: $__batch_reps_1) {
... on Product {
shippingEstimate
}
}
}
},
},
},
"#);
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": "{products{__typename upc name price(currency: \"USD\") weight _internal_qp_alias_0: price(currency: \"EUR\") category{averagePrice(currency: \"USD\")}}}"
},
{
"kind": "BatchFetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($__batch_reps_0:[_Any!]!, $__batch_reps_1:[_Any!]!){_e0: _entities(representations: $__batch_reps_0){...on Product{isExpensiveCategory shippingEstimateEUR}} _e1: _entities(representations: $__batch_reps_1){...on Product{shippingEstimate}}}",
"entityBatch": {
"aliases": [
{
"alias": "_e0",
"representationsVariableName": "__batch_reps_0",
"paths": [
[
{
"Field": "products"
},
"@"
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Product",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "category",
"selections": [
{
"kind": "Field",
"name": "averagePrice"
}
]
},
{
"kind": "Field",
"name": "upc"
},
{
"kind": "Field",
"name": "_internal_qp_alias_0",
"alias": "price"
},
{
"kind": "Field",
"name": "weight"
}
]
}
]
},
{
"alias": "_e1",
"representationsVariableName": "__batch_reps_1",
"paths": [
[
{
"Field": "products"
},
"@"
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Product",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "price"
},
{
"kind": "Field",
"name": "weight"
},
{
"kind": "Field",
"name": "upc"
}
]
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn requires_arguments_deeply_nested_requires() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
feed {
author {
id
}
comments(limit: 1) {
id
}
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/audit-requires-arguments.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "c") {
{
feed {
__typename
id
}
}
},
Flatten(path: "feed.@") {
Fetch(service: "d") {
{
... on Post {
__typename
id
}
} =>
{
... on Post {
_internal_qp_alias_0: comments(limit: 3) {
__typename
id
}
comments(limit: 1) {
id
}
}
}
},
},
Flatten(path: "feed.@._internal_qp_alias_0.@") {
Fetch(service: "c") {
{
... on Comment {
__typename
id
}
} =>
{
... on Comment {
authorId
}
}
},
},
Flatten(path: "feed.@") {
Fetch(service: "d") {
{
... on Post {
__typename
comments: _internal_qp_alias_0 {
authorId
}
id
}
} =>
{
... on Post {
author {
id
}
}
}
},
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "c",
"operationKind": "query",
"operation": "{feed{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "d",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Post{_internal_qp_alias_0: comments(limit: 3){__typename id} comments(limit: 1){id}}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Post",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@",
{
"Field": "_internal_qp_alias_0"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "c",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Comment{authorId}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Comment",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "d",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Post{author{id}}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Post",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "_internal_qp_alias_0",
"selections": [
{
"kind": "Field",
"name": "authorId"
}
],
"alias": "comments"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn requires_arguments_deeply_nested_requires_with_variable() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query ($limit: Int = 1) {
feed {
author {
id
}
comments(limit: $limit) {
id
}
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/audit-requires-arguments.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "c") {
{
feed {
__typename
id
}
}
},
Flatten(path: "feed.@") {
Fetch(service: "d") {
{
... on Post {
__typename
id
}
} =>
($limit:Int=1) {
... on Post {
_internal_qp_alias_0: comments(limit: 3) {
__typename
id
}
comments(limit: $limit) {
id
}
}
}
},
},
Flatten(path: "feed.@._internal_qp_alias_0.@") {
Fetch(service: "c") {
{
... on Comment {
__typename
id
}
} =>
{
... on Comment {
authorId
}
}
},
},
Flatten(path: "feed.@") {
Fetch(service: "d") {
{
... on Post {
__typename
comments: _internal_qp_alias_0 {
authorId
}
id
}
} =>
{
... on Post {
author {
id
}
}
}
},
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "c",
"operationKind": "query",
"operation": "{feed{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "d",
"variableUsages": [
"limit"
],
"operationKind": "query",
"operation": "query($representations:[_Any!]!, $limit:Int=1){_entities(representations: $representations){...on Post{_internal_qp_alias_0: comments(limit: 3){__typename id} comments(limit: $limit){id}}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Post",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@",
{
"Field": "_internal_qp_alias_0"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "c",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Comment{authorId}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Comment",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "d",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Post{author{id}}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Post",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "_internal_qp_alias_0",
"selections": [
{
"kind": "Field",
"name": "authorId"
}
],
"alias": "comments"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn requires_arguments_deeply_nested_requires_with_variables_and_fragments(
) -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query ($limit: Int = 1) {
feed {
author {
id
}
...Foo
...Bar
}
}
fragment Foo on Post {
comments(limit: $limit) {
id
}
}
fragment Bar on Post {
comments(limit: $limit) {
id
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/audit-requires-arguments.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "c") {
{
feed {
__typename
id
}
}
},
Flatten(path: "feed.@") {
Fetch(service: "d") {
{
... on Post {
__typename
id
}
} =>
($limit:Int=1) {
... on Post {
_internal_qp_alias_0: comments(limit: 3) {
__typename
id
}
comments(limit: $limit) {
id
}
}
}
},
},
Flatten(path: "feed.@._internal_qp_alias_0.@") {
Fetch(service: "c") {
{
... on Comment {
__typename
id
}
} =>
{
... on Comment {
authorId
}
}
},
},
Flatten(path: "feed.@") {
Fetch(service: "d") {
{
... on Post {
__typename
comments: _internal_qp_alias_0 {
authorId
}
id
}
} =>
{
... on Post {
author {
id
}
}
}
},
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "c",
"operationKind": "query",
"operation": "{feed{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "d",
"variableUsages": [
"limit"
],
"operationKind": "query",
"operation": "query($representations:[_Any!]!, $limit:Int=1){_entities(representations: $representations){...on Post{_internal_qp_alias_0: comments(limit: 3){__typename id} comments(limit: $limit){id}}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Post",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@",
{
"Field": "_internal_qp_alias_0"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "c",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Comment{authorId}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Comment",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "feed"
},
"@"
],
"node": {
"kind": "Fetch",
"serviceName": "d",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Post{author{id}}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Post",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "_internal_qp_alias_0",
"selections": [
{
"kind": "Field",
"name": "authorId"
}
],
"alias": "comments"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn multiple_requires_with_args_that_conflicts() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
{
test {
id
fieldWithRequiresAndArgs # requires(fields: "otherField(arg: 2)")
anotherWithRequiresAndArgs # requires(fields: "otherField(arg: 3)")
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-requires-args.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
test {
__typename
id
}
}
},
Flatten(path: "test") {
Fetch(service: "b") {
{
... on Test {
__typename
id
}
} =>
{
... on Test {
otherField(arg: 2)
_internal_qp_alias_0: otherField(arg: 3)
}
}
},
},
BatchFetch(service: "a") {
{
_e0 {
paths: [
"test"
]
{
... on Test {
__typename
otherField: _internal_qp_alias_0
id
}
}
}
_e1 {
paths: [
"test"
]
{
... on Test {
__typename
otherField
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Test {
anotherWithRequiresAndArgs
}
}
_e1: _entities(representations: $__batch_reps_1) {
... on Test {
fieldWithRequiresAndArgs
}
}
}
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "{test{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "test"
}
],
"node": {
"kind": "Fetch",
"serviceName": "b",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Test{otherField(arg: 2) _internal_qp_alias_0: otherField(arg: 3)}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "BatchFetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($__batch_reps_0:[_Any!]!, $__batch_reps_1:[_Any!]!){_e0: _entities(representations: $__batch_reps_0){...on Test{anotherWithRequiresAndArgs}} _e1: _entities(representations: $__batch_reps_1){...on Test{fieldWithRequiresAndArgs}}}",
"entityBatch": {
"aliases": [
{
"alias": "_e0",
"representationsVariableName": "__batch_reps_0",
"paths": [
[
{
"Field": "test"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "_internal_qp_alias_0",
"alias": "otherField"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
},
{
"alias": "_e1",
"representationsVariableName": "__batch_reps_1",
"paths": [
[
{
"Field": "test"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "otherField"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn multiple_plain_field_and_requires_with_args_that_conflicts() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
{
test {
id
fieldWithRequiresAndArgs # requires(fields: "otherField(arg: 2)")
anotherWithRequiresAndArgs # requires(fields: "otherField(arg: 3)")
otherField(arg: 1)
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-requires-args.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
test {
__typename
id
}
}
},
Flatten(path: "test") {
Fetch(service: "b") {
{
... on Test {
__typename
id
}
} =>
{
... on Test {
_internal_qp_alias_1: otherField(arg: 2)
_internal_qp_alias_0: otherField(arg: 3)
otherField(arg: 1)
}
}
},
},
BatchFetch(service: "a") {
{
_e0 {
paths: [
"test"
]
{
... on Test {
__typename
otherField: _internal_qp_alias_0
id
}
}
}
_e1 {
paths: [
"test"
]
{
... on Test {
__typename
otherField: _internal_qp_alias_1
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Test {
anotherWithRequiresAndArgs
}
}
_e1: _entities(representations: $__batch_reps_1) {
... on Test {
fieldWithRequiresAndArgs
}
}
}
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "{test{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "test"
}
],
"node": {
"kind": "Fetch",
"serviceName": "b",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Test{_internal_qp_alias_1: otherField(arg: 2) _internal_qp_alias_0: otherField(arg: 3) otherField(arg: 1)}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "BatchFetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($__batch_reps_0:[_Any!]!, $__batch_reps_1:[_Any!]!){_e0: _entities(representations: $__batch_reps_0){...on Test{anotherWithRequiresAndArgs}} _e1: _entities(representations: $__batch_reps_1){...on Test{fieldWithRequiresAndArgs}}}",
"entityBatch": {
"aliases": [
{
"alias": "_e0",
"representationsVariableName": "__batch_reps_0",
"paths": [
[
{
"Field": "test"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "_internal_qp_alias_0",
"alias": "otherField"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
},
{
"alias": "_e1",
"representationsVariableName": "__batch_reps_1",
"paths": [
[
{
"Field": "test"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "_internal_qp_alias_1",
"alias": "otherField"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn multiple_plain_field_and_requires_with_args_that_does_not_conflicts_should_merge(
) -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
{
test {
id
fieldWithRequiresAndArgs # requires(fields: "otherField(arg: 2)")
otherField(arg: 2)
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-requires-args.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
test {
__typename
id
}
}
},
Flatten(path: "test") {
Fetch(service: "b") {
{
... on Test {
__typename
id
}
} =>
{
... on Test {
otherField(arg: 2)
}
}
},
},
Flatten(path: "test") {
Fetch(service: "a") {
{
... on Test {
__typename
otherField
id
}
} =>
{
... on Test {
fieldWithRequiresAndArgs
}
}
},
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "{test{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "test"
}
],
"node": {
"kind": "Fetch",
"serviceName": "b",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Test{otherField(arg: 2)}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "test"
}
],
"node": {
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Test{fieldWithRequiresAndArgs}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "otherField"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn simple_requires_arguments() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
{
test {
id
fieldWithRequiresAndArgs
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/simple-requires-args.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
test {
__typename
id
}
}
},
Flatten(path: "test") {
Fetch(service: "b") {
{
... on Test {
__typename
id
}
} =>
{
... on Test {
otherField(arg: 2)
}
}
},
},
Flatten(path: "test") {
Fetch(service: "a") {
{
... on Test {
__typename
otherField
id
}
} =>
{
... on Test {
fieldWithRequiresAndArgs
}
}
},
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "{test{__typename id}}"
},
{
"kind": "Flatten",
"path": [
{
"Field": "test"
}
],
"node": {
"kind": "Fetch",
"serviceName": "b",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Test{otherField(arg: 2)}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
},
{
"kind": "Flatten",
"path": [
{
"Field": "test"
}
],
"node": {
"kind": "Fetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($representations:[_Any!]!){_entities(representations: $representations){...on Test{fieldWithRequiresAndArgs}}}",
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Test",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "otherField"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}
#[test]
fn requires_with_arguments() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
feed {
author {
id
}
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/arguments-requires.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "a") {
{
feed {
__typename
id
}
}
},
Flatten(path: "feed.@") {
Fetch(service: "b") {
{
... on Post {
__typename
id
}
} =>
{
... on Post {
comments(limit: 3) {
__typename
id
}
}
}
},
},
Flatten(path: "feed.@.comments.@") {
Fetch(service: "a") {
{
... on Comment {
__typename
id
}
} =>
{
... on Comment {
somethingElse
}
}
},
},
Flatten(path: "feed.@") {
Fetch(service: "b") {
{
... on Post {
__typename
comments {
somethingElse
}
id
}
} =>
{
... on Post {
author {
id
}
}
}
},
},
},
},
"#);
Ok(())
}
#[test]
fn arguments_in_different_levels() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
album(id: "5") {
albumType
name
genres
tracks(limit: 5, offset: 10) {
edges {
node {
name
}
}
}
}
}"#,
);
let query_plan =
build_query_plan_with_defaults("fixture/spotify-supergraph.graphql", document)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Fetch(service: "spotify") {
{
album(id: "5") {
albumType
name
genres
tracks(limit: 5, offset: 10) {
edges {
node {
name
}
}
}
}
}
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Fetch",
"serviceName": "spotify",
"operationKind": "query",
"operation": "{album(id: \"5\"){albumType name genres tracks(limit: 5, offset: 10){edges{node{name}}}}}"
}
}
"#);
Ok(())
}
#[test]
fn arguments_and_variables() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query test($id: ID!, $limit: Int) {
album(id: $id) {
albumType
name
genres
tracks(limit: $limit, offset: 10) {
edges {
node {
name
}
}
}
}
}"#,
);
let query_plan =
build_query_plan_with_defaults("fixture/spotify-supergraph.graphql", document)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Fetch(service: "spotify") {
query ($id:ID!,$limit:Int) {
album(id: $id) {
albumType
name
genres
tracks(limit: $limit, offset: 10) {
edges {
node {
name
}
}
}
}
}
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Fetch",
"serviceName": "spotify",
"variableUsages": [
"id",
"limit"
],
"operationKind": "query",
"operation": "query($id:ID!, $limit:Int){album(id: $id){albumType name genres tracks(limit: $limit, offset: 10){edges{node{name}}}}}"
}
}
"#);
Ok(())
}
#[test]
fn arguments_with_aliases() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query {
firstProduct: productFromD(id: "1") {
id
name
category {
id
name
details
}
}
secondProduct: productFromD(id: "2") {
id
name
category {
id
name
details
}
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/parent-entity-call-complex.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "d") {
{
firstProduct: productFromD(id: "1") {
...a
}
secondProduct: productFromD(id: "2") {
...a
}
}
fragment a on Product {
__typename
id
name
}
},
Parallel {
BatchFetch(service: "a") {
{
_e0 {
paths: [
"secondProduct"
"firstProduct"
]
{
... on Product {
__typename
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Product {
category {
details
}
}
}
}
},
BatchFetch(service: "b") {
{
_e0 {
paths: [
"secondProduct"
"firstProduct"
]
{
... on Product {
__typename
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Product {
category {
__typename
id
}
}
}
}
},
},
BatchFetch(service: "c") {
{
_e0 {
paths: [
"secondProduct.category"
"firstProduct.category"
]
{
... on Category {
__typename
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Category {
name
}
}
}
},
},
},
"#);
Ok(())
}
#[test]
fn arguments_variables_mixed() -> Result<(), Box<dyn Error>> {
init_logger();
let document = parse_operation(
r#"
query test($secondProductId: ID!) {
firstProduct: productFromD(id: "1") {
id
name
category {
id
name
details
}
}
secondProduct: productFromD(id: $secondProductId) {
id
name
category {
id
name
details
}
}
}"#,
);
let query_plan = build_query_plan_with_defaults(
"fixture/tests/parent-entity-call-complex.supergraph.graphql",
document,
)?;
insta::assert_snapshot!(format!("{}", query_plan), @r#"
QueryPlan {
Sequence {
Fetch(service: "d") {
query ($secondProductId:ID!) {
firstProduct: productFromD(id: "1") {
...a
}
secondProduct: productFromD(id: $secondProductId) {
...a
}
}
fragment a on Product {
__typename
id
name
}
},
Parallel {
BatchFetch(service: "a") {
{
_e0 {
paths: [
"secondProduct"
"firstProduct"
]
{
... on Product {
__typename
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Product {
category {
details
}
}
}
}
},
BatchFetch(service: "b") {
{
_e0 {
paths: [
"secondProduct"
"firstProduct"
]
{
... on Product {
__typename
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Product {
category {
__typename
id
}
}
}
}
},
},
BatchFetch(service: "c") {
{
_e0 {
paths: [
"secondProduct.category"
"firstProduct.category"
]
{
... on Category {
__typename
id
}
}
}
}
{
_e0: _entities(representations: $__batch_reps_0) {
... on Category {
name
}
}
}
},
},
},
"#);
insta::assert_snapshot!(format!("{}", sonic_rs::to_string_pretty(&query_plan).unwrap_or_default()), @r#"
{
"kind": "QueryPlan",
"node": {
"kind": "Sequence",
"nodes": [
{
"kind": "Fetch",
"serviceName": "d",
"variableUsages": [
"secondProductId"
],
"operationKind": "query",
"operation": "query($secondProductId:ID!){firstProduct: productFromD(id: \"1\"){...a} secondProduct: productFromD(id: $secondProductId){...a}}\n\nfragment a on Product {__typename id name}\n"
},
{
"kind": "Parallel",
"nodes": [
{
"kind": "BatchFetch",
"serviceName": "a",
"operationKind": "query",
"operation": "query($__batch_reps_0:[_Any!]!){_e0: _entities(representations: $__batch_reps_0){...on Product{category{details}}}}",
"entityBatch": {
"aliases": [
{
"alias": "_e0",
"representationsVariableName": "__batch_reps_0",
"paths": [
[
{
"Field": "secondProduct"
}
],
[
{
"Field": "firstProduct"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Product",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
]
}
},
{
"kind": "BatchFetch",
"serviceName": "b",
"operationKind": "query",
"operation": "query($__batch_reps_0:[_Any!]!){_e0: _entities(representations: $__batch_reps_0){...on Product{category{__typename id}}}}",
"entityBatch": {
"aliases": [
{
"alias": "_e0",
"representationsVariableName": "__batch_reps_0",
"paths": [
[
{
"Field": "secondProduct"
}
],
[
{
"Field": "firstProduct"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Product",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
]
}
}
]
},
{
"kind": "BatchFetch",
"serviceName": "c",
"operationKind": "query",
"operation": "query($__batch_reps_0:[_Any!]!){_e0: _entities(representations: $__batch_reps_0){...on Category{name}}}",
"entityBatch": {
"aliases": [
{
"alias": "_e0",
"representationsVariableName": "__batch_reps_0",
"paths": [
[
{
"Field": "secondProduct"
},
{
"Field": "category"
}
],
[
{
"Field": "firstProduct"
},
{
"Field": "category"
}
]
],
"requires": [
{
"kind": "InlineFragment",
"typeCondition": "Category",
"selections": [
{
"kind": "Field",
"name": "__typename"
},
{
"kind": "Field",
"name": "id"
}
]
}
]
}
]
}
}
]
}
}
"#);
Ok(())
}