From 80a9e61ee240a6e1389205713c3f809a2b6ce95c Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Wed, 9 Oct 2024 11:34:12 +0100 Subject: [PATCH 1/8] fix: bug in modify for graphql --- src/core/blueprint/operators/graphql.rs | 15 +++++++++++++-- src/core/ir/eval_context.rs | 13 ++++++++----- src/core/ir/mod.rs | 4 ++-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/core/blueprint/operators/graphql.rs b/src/core/blueprint/operators/graphql.rs index 39eca0f634..272e7375c5 100644 --- a/src/core/blueprint/operators/graphql.rs +++ b/src/core/blueprint/operators/graphql.rs @@ -24,10 +24,21 @@ fn create_related_fields( if let Some(type_) = config.find_type(type_name) { for (name, field) in &type_.fields { - if !field.has_resolver() { + if field.modify.is_some() { + map.insert( + field.modify.clone().unwrap().name.unwrap(), + ( + name.clone(), + create_related_fields(config, field.type_of.name(), visited), + ), + ); + } else if !field.has_resolver() { map.insert( name.clone(), - create_related_fields(config, field.type_of.name(), visited), + ( + name.clone(), + create_related_fields(config, field.type_of.name(), visited), + ), ); } } diff --git a/src/core/ir/eval_context.rs b/src/core/ir/eval_context.rs index 1a79f561bb..c733882f85 100644 --- a/src/core/ir/eval_context.rs +++ b/src/core/ir/eval_context.rs @@ -130,9 +130,9 @@ fn format_selection_set<'a>( let set = selection_set .filter_map(|field| { // add to set only related fields that should be resolved with current resolver - related_fields - .get(field.name()) - .map(|related_fields| format_selection_field(field, related_fields)) + related_fields.get(field.name()).map(|related_fields| { + format_selection_field(field, &related_fields.0, &related_fields.1) + }) }) .collect::>(); @@ -143,8 +143,11 @@ fn format_selection_set<'a>( Some(format!("{{ {} }}", set.join(" "))) } -fn format_selection_field(field: &SelectionField, related_fields: &RelatedFields) -> String { - let name = field.name(); +fn format_selection_field( + field: &SelectionField, + name: &str, + related_fields: &RelatedFields, +) -> String { let arguments = format_selection_field_arguments(field); let selection_set = format_selection_set(field.selection_set(), related_fields); diff --git a/src/core/ir/mod.rs b/src/core/ir/mod.rs index 71e7748573..4540424848 100644 --- a/src/core/ir/mod.rs +++ b/src/core/ir/mod.rs @@ -21,10 +21,10 @@ pub use resolver_context_like::{ /// resolver i.e. fields that don't have their own resolver and are resolved by /// the ancestor #[derive(Debug, Default, Clone)] -pub struct RelatedFields(pub HashMap); +pub struct RelatedFields(pub HashMap); impl Deref for RelatedFields { - type Target = HashMap; + type Target = HashMap; fn deref(&self) -> &Self::Target { &self.0 From 794a0dea0dd30efa181d89f14e2a082732f323e0 Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Wed, 9 Oct 2024 17:13:03 +0100 Subject: [PATCH 2/8] add integration test and correct for a field using directive --- package-lock.json | 28 +++++ package.json | 5 + src/core/blueprint/operators/graphql.rs | 32 ++--- tests/execution/graphql-conformance-018.md | 129 +++++++++++++++++++++ 4 files changed, 179 insertions(+), 15 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tests/execution/graphql-conformance-018.md diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..cb27dc4f9e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "tailcall", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "prettier": "3.3.3" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..a32393d7dc --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "prettier": "3.3.3" + } +} diff --git a/src/core/blueprint/operators/graphql.rs b/src/core/blueprint/operators/graphql.rs index 272e7375c5..eb38e126ca 100644 --- a/src/core/blueprint/operators/graphql.rs +++ b/src/core/blueprint/operators/graphql.rs @@ -24,22 +24,24 @@ fn create_related_fields( if let Some(type_) = config.find_type(type_name) { for (name, field) in &type_.fields { - if field.modify.is_some() { - map.insert( - field.modify.clone().unwrap().name.unwrap(), - ( + if !field.has_resolver() { + if field.modify.is_some() { + map.insert( + field.modify.clone().unwrap().name.unwrap(), + ( + name.clone(), + create_related_fields(config, field.type_of.name(), visited), + ), + ); + } else { + map.insert( name.clone(), - create_related_fields(config, field.type_of.name(), visited), - ), - ); - } else if !field.has_resolver() { - map.insert( - name.clone(), - ( - name.clone(), - create_related_fields(config, field.type_of.name(), visited), - ), - ); + ( + name.clone(), + create_related_fields(config, field.type_of.name(), visited), + ), + ); + } } } } else if let Some(union_) = config.find_union(type_name) { diff --git a/tests/execution/graphql-conformance-018.md b/tests/execution/graphql-conformance-018.md new file mode 100644 index 0000000000..71adeec857 --- /dev/null +++ b/tests/execution/graphql-conformance-018.md @@ -0,0 +1,129 @@ + +# Basic queries with modify field check + +```graphql @config +schema + @server(port: 8001, queryValidation: false, hostname: "0.0.0.0") + @upstream(baseURL: "http://upstream/graphql", httpCache: 42) { + query: Query +} + +type Query { + user(id: ID!): User! @graphQL(name: "user", args: [{key: "id", value: "{{.args.id}}"}]) +} + +type User { + id: ID! + name: String! @modify(name: "newName") + city: String +} +``` + +```yml @mock +- request: + method: POST + url: http://upstream/graphql + textBody: '{ "query": "query { user(id: 4) { city newName } }" }' + expectedHits: 1 + response: + status: 200 + body: + data: + user: + city: Globe + newName: Tailcall +- request: + method: POST + url: http://upstream/graphql + textBody: '{ "query": "query { user(id: 4) { city newName id } }" }' + expectedHits: 1 + response: + status: 200 + body: + data: + user: + city: Globe + newName: Tailcall + id: 4 +- request: + method: POST + url: http://upstream/graphql + textBody: '{ "query": "query { user(id: 4) { id newName city } }" }' + expectedHits: 1 + response: + status: 200 + body: + data: + user: + id: 4 + newName: Tailcall + city: Globe +``` + +```yml @test +# Positive: basic 1 +- method: POST + url: http://localhost:8080/graphql + body: + query: | + { + user(id: 4) { + city + newName + } + } +# Positive: basic 2 +- method: POST + url: http://localhost:8080/graphql + body: + query: | + query { + user(id: 4) { + city + newName + id + } + } +# Positive: basic 2 re ordered +- method: POST + url: http://localhost:8080/graphql + body: + query: | + query { + user(id: 4) { + id + newName + city + } + } +# Negative: without selection +- method: POST + url: http://localhost:8080/graphql + body: + query: | + query { + user(id: 4) +# Negative: non existent fields +- method: POST + url: http://localhost:8080/graphql + body: + query: | + query { + user(id: 4) { + id + email_address + } + +# Negative: missing input +- method: POST + url: http://localhost:8080/graphql + body: + query: | + query { + user { + id + newName + city + } + } +``` From 885908d26504170df2d1ff85463ccf0fd8a20fcf Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Wed, 9 Oct 2024 17:16:45 +0100 Subject: [PATCH 3/8] remove unecessary files --- package-lock.json | 28 ---------------------------- package.json | 5 ----- 2 files changed, 33 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index cb27dc4f9e..0000000000 --- a/package-lock.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "tailcall", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "devDependencies": { - "prettier": "3.3.3" - } - }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index a32393d7dc..0000000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "devDependencies": { - "prettier": "3.3.3" - } -} From 84297d8db596df1a07d62967494d672e763fcda9 Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Thu, 10 Oct 2024 11:07:12 +0100 Subject: [PATCH 4/8] update integration test file --- tests/execution/graphql-conformance-018.md | 88 +--------------------- 1 file changed, 4 insertions(+), 84 deletions(-) diff --git a/tests/execution/graphql-conformance-018.md b/tests/execution/graphql-conformance-018.md index 71adeec857..27077b9067 100644 --- a/tests/execution/graphql-conformance-018.md +++ b/tests/execution/graphql-conformance-018.md @@ -14,7 +14,7 @@ type Query { type User { id: ID! - name: String! @modify(name: "newName") + name: String! city: String } ``` @@ -23,7 +23,7 @@ type User { - request: method: POST url: http://upstream/graphql - textBody: '{ "query": "query { user(id: 4) { city newName } }" }' + textBody: '{ "query": "query { user(id: 4) { city name } }" }' expectedHits: 1 response: status: 200 @@ -32,98 +32,18 @@ type User { user: city: Globe newName: Tailcall -- request: - method: POST - url: http://upstream/graphql - textBody: '{ "query": "query { user(id: 4) { city newName id } }" }' - expectedHits: 1 - response: - status: 200 - body: - data: - user: - city: Globe - newName: Tailcall - id: 4 -- request: - method: POST - url: http://upstream/graphql - textBody: '{ "query": "query { user(id: 4) { id newName city } }" }' - expectedHits: 1 - response: - status: 200 - body: - data: - user: - id: 4 - newName: Tailcall - city: Globe ``` ```yml @test # Positive: basic 1 - method: POST - url: http://localhost:8080/graphql + url: http://localhost:8001/graphql body: query: | { user(id: 4) { - city - newName - } - } -# Positive: basic 2 -- method: POST - url: http://localhost:8080/graphql - body: - query: | - query { - user(id: 4) { - city - newName - id - } - } -# Positive: basic 2 re ordered -- method: POST - url: http://localhost:8080/graphql - body: - query: | - query { - user(id: 4) { - id - newName - city - } - } -# Negative: without selection -- method: POST - url: http://localhost:8080/graphql - body: - query: | - query { - user(id: 4) -# Negative: non existent fields -- method: POST - url: http://localhost:8080/graphql - body: - query: | - query { - user(id: 4) { - id - email_address - } - -# Negative: missing input -- method: POST - url: http://localhost:8080/graphql - body: - query: | - query { - user { - id newName - city + email } } ``` From c9eeb16bbf1498466592a555288b31c954e766c6 Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Thu, 10 Oct 2024 14:54:09 +0100 Subject: [PATCH 5/8] fix integration test graphql-conformance-018.md --- tests/execution/graphql-conformance-018.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/execution/graphql-conformance-018.md b/tests/execution/graphql-conformance-018.md index 27077b9067..0427635cbe 100644 --- a/tests/execution/graphql-conformance-018.md +++ b/tests/execution/graphql-conformance-018.md @@ -1,5 +1,4 @@ - -# Basic queries with modify field check +# Basic queries with field modify check ```graphql @config schema @@ -14,7 +13,7 @@ type Query { type User { id: ID! - name: String! + name: String! @modify(name: "newName") city: String } ``` @@ -23,7 +22,7 @@ type User { - request: method: POST url: http://upstream/graphql - textBody: '{ "query": "query { user(id: 4) { city name } }" }' + textBody: '{ "query": "query { user(id: 4) { city name } }" }' expectedHits: 1 response: status: 200 @@ -31,19 +30,20 @@ type User { data: user: city: Globe - newName: Tailcall + name: Tailcall + ``` ```yml @test -# Positive: basic 1 - method: POST - url: http://localhost:8001/graphql + url: http://localhost:8080/graphql body: query: | - { + query getUser { user(id: 4) { + city newName - email } } + ``` From e77a3952b6bb9de88abba95c5351b4a51b5f0ba6 Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Thu, 10 Oct 2024 17:15:12 +0100 Subject: [PATCH 6/8] improve code and add snapshots --- src/core/blueprint/operators/graphql.rs | 18 ++++--- .../graphql-conformance-018.md_0.snap | 18 +++++++ .../graphql-conformance-018.md_client.snap | 53 +++++++++++++++++++ .../graphql-conformance-018.md_merged.snap | 19 +++++++ 4 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 tests/core/snapshots/graphql-conformance-018.md_0.snap create mode 100644 tests/core/snapshots/graphql-conformance-018.md_client.snap create mode 100644 tests/core/snapshots/graphql-conformance-018.md_merged.snap diff --git a/src/core/blueprint/operators/graphql.rs b/src/core/blueprint/operators/graphql.rs index eb38e126ca..80c99147c1 100644 --- a/src/core/blueprint/operators/graphql.rs +++ b/src/core/blueprint/operators/graphql.rs @@ -25,14 +25,16 @@ fn create_related_fields( if let Some(type_) = config.find_type(type_name) { for (name, field) in &type_.fields { if !field.has_resolver() { - if field.modify.is_some() { - map.insert( - field.modify.clone().unwrap().name.unwrap(), - ( - name.clone(), - create_related_fields(config, field.type_of.name(), visited), - ), - ); + if let Some(modify) = &field.modify { + if let Some(modified_name) = &modify.name { + map.insert( + modified_name.clone(), + ( + name.clone(), + create_related_fields(config, field.type_of.name(), visited), + ), + ); + } } else { map.insert( name.clone(), diff --git a/tests/core/snapshots/graphql-conformance-018.md_0.snap b/tests/core/snapshots/graphql-conformance-018.md_0.snap new file mode 100644 index 0000000000..67b166b416 --- /dev/null +++ b/tests/core/snapshots/graphql-conformance-018.md_0.snap @@ -0,0 +1,18 @@ +--- +source: tests/core/spec.rs +expression: response +--- +{ + "status": 200, + "headers": { + "content-type": "application/json" + }, + "body": { + "data": { + "user": { + "city": "Globe", + "newName": "Tailcall" + } + } + } +} diff --git a/tests/core/snapshots/graphql-conformance-018.md_client.snap b/tests/core/snapshots/graphql-conformance-018.md_client.snap new file mode 100644 index 0000000000..534243acd4 --- /dev/null +++ b/tests/core/snapshots/graphql-conformance-018.md_client.snap @@ -0,0 +1,53 @@ +--- +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 + +scalar PhoneNumber + +type Query { + user(id: ID!): User! +} + +scalar UInt128 + +scalar UInt16 + +scalar UInt32 + +scalar UInt64 + +scalar UInt8 + +scalar Url + +type User { + city: String + id: ID! + newName: String! +} + +schema { + query: Query +} diff --git a/tests/core/snapshots/graphql-conformance-018.md_merged.snap b/tests/core/snapshots/graphql-conformance-018.md_merged.snap new file mode 100644 index 0000000000..6dad406ac9 --- /dev/null +++ b/tests/core/snapshots/graphql-conformance-018.md_merged.snap @@ -0,0 +1,19 @@ +--- +source: tests/core/spec.rs +expression: formatter +--- +schema + @server(hostname: "0.0.0.0", port: 8001, queryValidation: false) + @upstream(baseURL: "http://upstream/graphql", httpCache: 42) { + query: Query +} + +type Query { + user(id: ID!): User! @graphQL(args: [{key: "id", value: "{{.args.id}}"}], name: "user") +} + +type User { + city: String + id: ID! + name: String! @modify(name: "newName") +} From 3d2fbafd9b99d0497132c775debce77393db18a6 Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Fri, 11 Oct 2024 13:55:00 +0100 Subject: [PATCH 7/8] fix linting --- tests/execution/graphql-conformance-018.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/execution/graphql-conformance-018.md b/tests/execution/graphql-conformance-018.md index 0427635cbe..f5ea02a66f 100644 --- a/tests/execution/graphql-conformance-018.md +++ b/tests/execution/graphql-conformance-018.md @@ -31,7 +31,6 @@ type User { user: city: Globe name: Tailcall - ``` ```yml @test @@ -45,5 +44,4 @@ type User { newName } } - ``` From 81ee4e665ce3a61bc6885b4033017924f33c2db9 Mon Sep 17 00:00:00 2001 From: Heikel Bouzayene Date: Sat, 12 Oct 2024 15:50:28 +0100 Subject: [PATCH 8/8] fix tests --- .../graphql-conformance-018.md_client.snap | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/tests/core/snapshots/graphql-conformance-018.md_client.snap b/tests/core/snapshots/graphql-conformance-018.md_client.snap index 534243acd4..21e04a64ac 100644 --- a/tests/core/snapshots/graphql-conformance-018.md_client.snap +++ b/tests/core/snapshots/graphql-conformance-018.md_client.snap @@ -2,46 +2,10 @@ 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 - -scalar PhoneNumber - type Query { user(id: ID!): User! } -scalar UInt128 - -scalar UInt16 - -scalar UInt32 - -scalar UInt64 - -scalar UInt8 - -scalar Url - type User { city: String id: ID!