Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: union as input/output type #2011

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ use std::fmt::{self, Display};
use std::num::NonZeroU64;

use anyhow::Result;
use async_graphql::parser::types::ServiceDocument;
use derive_setters::Setters;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::telemetry::Telemetry;
use super::{telemetry::Telemetry, ConfigModule};
use super::{KeyValue, Link, Server, Upstream};
use crate::core::config::from_document::from_document;
use crate::core::config::source::Source;
Expand Down Expand Up @@ -635,13 +634,8 @@ impl Config {
}
}

pub fn to_document(&self) -> ServiceDocument {
self.clone().into()
}

pub fn to_sdl(&self) -> String {
let doc = self.to_document();
crate::core::document::print(doc)
ConfigModule::from(self.clone()).to_sdl()
}

pub fn query(mut self, query: &str) -> Self {
Expand Down
36 changes: 24 additions & 12 deletions src/core/config/config_module.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeSet, HashMap, HashSet};
use std::ops::Deref;
use std::sync::Arc;

Expand All @@ -7,7 +7,7 @@ use jsonwebtoken::jwk::JwkSet;
use prost_reflect::prost_types::{FileDescriptorProto, FileDescriptorSet};
use rustls_pki_types::{CertificateDer, PrivateKeyDer};

use crate::core::config::Config;
use crate::core::config::{Config, Union};
use crate::core::macros::MergeRight;
use crate::core::merge_right::MergeRight;
use crate::core::proto_reader::ProtoMetadata;
Expand Down Expand Up @@ -119,6 +119,10 @@ fn insert_resolution(
}

impl ConfigModule {
pub fn to_sdl(self) -> String {
crate::core::document::print(self.into())
}

/// This function resolves the ambiguous types by renaming the input and
/// output types. The resolver function should return a Resolution
/// object containing the new input and output types.
Expand Down Expand Up @@ -157,20 +161,28 @@ impl ConfigModule {
let input_name = &resolution.input;
let output_name = &resolution.output;

let og_ty = self.config.types.get(current_name).cloned();

// remove old types
self.config.types.remove(current_name);
self.input_types.remove(current_name);
self.output_types.remove(current_name);

// add new types
if let Some(og_ty) = og_ty {
self.input_types.insert(input_name.clone());
self.output_types.insert(output_name.clone());

if let Some(union_) = self.config.unions.remove(current_name) {
let (input_types, output_types): (BTreeSet<_>, BTreeSet<_>) = union_
.types
.iter()
.flat_map(|type_| resolution_map.get(type_))
.map(|res| (res.input.clone(), res.output.clone()))
.unzip();

self.config
.unions
.insert(input_name.clone(), Union { types: input_types, ..union_.clone() });
self.config
.unions
.insert(output_name.clone(), Union { types: output_types, ..union_ });
} else if let Some(og_ty) = self.config.types.remove(current_name) {
self.config.types.insert(input_name.clone(), og_ty.clone());
self.input_types.insert(input_name.clone());

self.config.types.insert(output_name.clone(), og_ty);
self.output_types.insert(output_name.clone());
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/core/config/into_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,8 @@ fn get_directives(field: &crate::core::config::Field) -> Vec<Positioned<ConstDir
directives.into_iter().flatten().collect()
}

impl From<Config> for ServiceDocument {
fn from(value: Config) -> Self {
config_document(&value.into())
impl From<ConfigModule> for ServiceDocument {
fn from(value: ConfigModule) -> Self {
config_document(&value)
}
}
18 changes: 16 additions & 2 deletions tests/core/snapshots/test-add-link-to-empty-config.md_merged.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
---
source: tests/core/spec.rs
expression: merged
expression: formatter
---
schema @server @upstream @link(src: "link-expr.graphql", type: Config) @link(src: "link-enum.graphql", type: Config) {
schema
@server
@upstream(baseURL: "http://jsonplaceholder.typicode.com")
@link(src: "link-expr.graphql", type: Config)
@link(src: "link-enum.graphql", type: Config) {
query: Query
}

enum Foo {
BAR
BAZ
}

type Query {
foo: Foo @http(path: "/foo")
hello: String @expr(body: "Hello from server")
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
---
source: tests/core/spec.rs
expression: merged
expression: formatter
---
schema @server @upstream(allowedHeaders: ["Authorization"]) @link(src: "stripe-types.graphql", type: Config) {
query: Query
}

type Foo {
bar: String
}

type Query {
foo: Foo @expr(body: {bar: "foo"})
}
30 changes: 28 additions & 2 deletions tests/core/snapshots/test-nested-link.md_merged.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
---
source: tests/core/spec.rs
expression: merged
expression: formatter
---
schema @server @upstream @link(src: "graphql-with-link.graphql", type: Config) {
schema
@server
@upstream(baseURL: "http://jsonplaceholder.typicode.com")
@link(src: "graphql-with-link.graphql", type: Config)
@link(src: "link-enum.graphql", type: Config)
@link(src: "link-enum.graphql", type: Config) {
query: Query
}

enum Foo {
BAR
BAZ
}

type Post {
id: Int!
user: User @graphQL(args: [{key: "id", value: "{{.value.userId}}"}], name: "user")
userId: Int!
}

type Query {
foo: Foo @http(path: "/foo")
post(id: Int!): Post @http(baseURL: "http://jsonplaceholder.typicode.com", path: "/posts/{{.args.id}}")
}

type User {
id: Int
name: String
}
53 changes: 53 additions & 0 deletions tests/core/snapshots/yaml-union.md_client.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
source: tests/core/spec.rs
expression: formatted
---
scalar Date

scalar Email

scalar Empty

scalar JSON

scalar PhoneNumber

type Query {
testVar0(input: T1Input!): U
testVar1(input: T2Input!): U
testVar2(input: T3Input!): U
}

type T1 {
t1: String
}

input T1Input {
t1: String
}

type T2 {
t2: Int
}

input T2Input {
t2: Int
}

type T3 {
t3: Boolean
t33: Float!
}

input T3Input {
t3: Boolean
t33: Float!
}

union U = T1 | T2 | T3

scalar Url

schema {
query: Query
}
41 changes: 41 additions & 0 deletions tests/core/snapshots/yaml-union.md_merged.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
source: tests/core/spec.rs
expression: formatter
---
schema @server @upstream {
query: Query
}

input T1Input {
t1: String
}

input T2Input {
t2: Int
}

input T3Input {
t3: Boolean
t33: Float!
}

union U = T1 | T2 | T3

type Query {
testVar0(input: T1Input!): U @http(baseURL: "http://localhost", path: "/users/{{args.input}}")
testVar1(input: T2Input!): U @http(baseURL: "http://localhost", path: "/users/{{args.input}}")
testVar2(input: T3Input!): U @http(baseURL: "http://localhost", path: "/users/{{args.input}}")
}

type T1 {
t1: String
}

type T2 {
t2: Int
}

type T3 {
t3: Boolean
t33: Float!
}
37 changes: 22 additions & 15 deletions tests/core/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ use colored::Colorize;
use futures_util::future::join_all;
use hyper::{Body, Request};
use serde::{Deserialize, Serialize};
use tailcall::core::async_graphql_hyper::{GraphQLBatchRequest, GraphQLRequest};
use tailcall::core::blueprint::Blueprint;
use tailcall::core::config::reader::ConfigReader;
use tailcall::core::config::{Config, ConfigModule, Source};
use tailcall::core::http::{handle_request, AppContext};
use tailcall::core::merge_right::MergeRight;
use tailcall::core::print_schema::print_schema;
use tailcall::core::valid::{Cause, ValidationError};
use tailcall::core::{
async_graphql_hyper::{GraphQLBatchRequest, GraphQLRequest},
config::Resolution,
};
use tailcall_prettier::Parser;

use super::file::File;
Expand Down Expand Up @@ -220,20 +223,6 @@ async fn test_spec(spec: ExecutionSpec) {
// Parse and validate all server configs + check for identity
let server = check_server_config(spec.clone()).await;

// merged: Run merged specs
let merged = server
.iter()
.fold(Config::default(), |acc, c| acc.merge_right(c.clone()))
.to_sdl();

let formatter = tailcall_prettier::format(merged, &Parser::Gql)
.await
.unwrap();

let snapshot_name = format!("{}_merged", spec.safe_name);

insta::assert_snapshot!(snapshot_name, formatter);

// Resolve all configs
let mut runtime = runtime::create_runtime(mock_http_client.clone(), spec.env.clone(), None);
runtime.file = Arc::new(File::new(spec.clone()));
Expand All @@ -259,6 +248,24 @@ async fn test_spec(spec: ExecutionSpec) {
})
.collect();

// merged: Run merged specs
let merged = server
.iter()
.fold(ConfigModule::default(), |acc, c| acc.merge_right(c.clone()))
.resolve_ambiguous_types(|v| Resolution {
input: format!("{}Input", v),
output: v.to_owned(),
})
.to_sdl();

let formatter = tailcall_prettier::format(merged, &Parser::Gql)
.await
.unwrap();

let snapshot_name = format!("{}_merged", spec.safe_name);

insta::assert_snapshot!(snapshot_name, formatter);

// client: Check if client spec matches snapshot
if server.len() == 1 {
let config = &server[0];
Expand Down
39 changes: 39 additions & 0 deletions tests/execution/yaml-union.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Using Union types in yaml config

```yml @config
schema:
query: Query

types:
T1:
fields:
t1:
type: String
T2:
fields:
t2:
type: Int
T3:
fields:
t3:
type: Boolean
t33:
type: Float
required: true

Query:
fields:
test:
type: U
args:
input:
type: U
required: true
http:
baseURL: http://localhost
path: /users/{{args.input}}

unions:
U:
types: ["T1", "T2", "T3"]
```