Skip to content

Commit

Permalink
feat(2560): merge unknows types (#2567)
Browse files Browse the repository at this point in the history
  • Loading branch information
laststylebender14 committed Aug 28, 2024
1 parent 751e9a6 commit aa669c4
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 9 deletions.
1 change: 0 additions & 1 deletion src/cli/generator/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ pub struct PresetConfig {
pub tree_shake: Option<bool>,
pub unwrap_single_field_types: Option<bool>,
}

#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(transparent)]
pub struct Location<A>(
Expand Down
32 changes: 31 additions & 1 deletion src/core/config/transformer/merge_types/similarity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::pair_map::PairMap;
use super::pair_set::PairSet;
use crate::core::config::{Config, Type};
use crate::core::scalar::Scalar;
use crate::core::valid::{Valid, Validator};

/// Given Two types,it tells similarity between two types based on a specified
Expand Down Expand Up @@ -63,7 +64,11 @@ impl<'a> Similarity<'a> {
if config.is_scalar(&field_1_type_of) && config.is_scalar(&field_2_type_of) {
// if field type_of is scalar and they don't match then we can't merge
// types.
if field_1_type_of == field_2_type_of {
let json_scalar = Scalar::JSON.to_string();
if field_1_type_of == field_2_type_of
|| field_1_type_of == json_scalar
|| field_2_type_of == json_scalar
{
if field_1.list == field_2.list {
same_field_count += 1;
} else {
Expand Down Expand Up @@ -513,4 +518,29 @@ mod test {
// Assert that merging incompatible list and non-list fields fails
assert!(result.is_err())
}

#[test]
fn test_unknown_types_similarity() {
let sdl = r#"
type A {
primarySubcategoryId: String
}
type B {
primarySubcategoryId: JSON
}
"#;
let config = Config::from_sdl(sdl).to_result().unwrap();

let mut similarity = Similarity::new(&config);

let result = similarity
.similarity(
("B", config.types.get("B").unwrap()),
("A", config.types.get("A").unwrap()),
0.9,
)
.to_result()
.unwrap();
assert!(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
source: src/core/config/transformer/merge_types/type_merger.rs
expression: config.to_sdl()
---
schema @server @upstream {
query: Query
}

type M1 {
id: Int
name: JSON
}

type Query {
bar: M1
foo: M1
}
59 changes: 56 additions & 3 deletions src/core/config/transformer/merge_types/type_merger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use super::mergeable_types::MergeableTypes;
use super::similarity::Similarity;
use crate::core::config::{Config, Type};
use crate::core::merge_right::MergeRight;
use crate::core::scalar::Scalar;
use crate::core::transform::Transform;
use crate::core::valid::{Valid, Validator};

Expand Down Expand Up @@ -57,7 +58,6 @@ impl TypeMerger {

if let Some(type_info_2) = config.types.get(type_name_2) {
let threshold = mergeable_types.get_threshold(type_name_1, type_name_2);

visited_types.insert(type_name_1.clone());
let is_similar = stat_gen
.similarity(
Expand All @@ -66,6 +66,7 @@ impl TypeMerger {
threshold,
)
.to_result();

if let Ok(similar) = is_similar {
if similar {
visited_types.insert(type_name_2.clone());
Expand Down Expand Up @@ -187,8 +188,34 @@ impl TypeMerger {
}
}

fn merge_type(type_: &Type, merge_into: Type) -> Type {
merge_into.merge_right(type_.clone())
fn merge_type(type_: &Type, mut merge_into: Type) -> Type {
// Merge the simple fields using `merge_right`.
merge_into.added_fields = merge_into
.added_fields
.merge_right(type_.added_fields.clone());
merge_into.implements = merge_into.implements.merge_right(type_.implements.clone());
merge_into.cache = merge_into.cache.merge_right(type_.cache.clone());
merge_into.protected = merge_into.protected.merge_right(type_.protected.clone());
merge_into.doc = merge_into.doc.merge_right(type_.doc.clone());

// Handle field output type merging correctly.
type_.fields.iter().for_each(|(key, new_field)| {
merge_into
.fields
.entry(key.to_owned())
.and_modify(|existing_field| {
let mut merged_field = existing_field.clone().merge_right(new_field.clone());
if existing_field.type_of == Scalar::JSON.to_string()
|| new_field.type_of == Scalar::JSON.to_string()
{
merged_field.type_of = Scalar::JSON.to_string();
}
*existing_field = merged_field;
})
.or_insert_with(|| new_field.to_owned());
});

merge_into
}

impl Transform for TypeMerger {
Expand Down Expand Up @@ -379,4 +406,30 @@ mod test {
let config = TypeMerger::default().transform(config).to_result().unwrap();
insta::assert_snapshot!(config.to_sdl());
}

#[test]
fn test_merge_to_supertype() {
let sdl = r#"
schema {
query: Query
}
type Bar {
id: Int
name: JSON
}
type Foo {
id: Int
name: String
}
type Query {
foo: Foo
bar: Bar
}
"#;

let config = Config::from_sdl(sdl).to_result().unwrap();
let config = TypeMerger::default().transform(config).to_result().unwrap();
insta::assert_snapshot!(config.to_sdl());
}
}
2 changes: 1 addition & 1 deletion tailcall-fixtures/fixtures/generator/simple-json.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
}
],
"preset": {
"mergeType": 1,
"mergeType": 1.0,
"consolidateURL": 0.5
},
"output": {
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/fixtures/generator/gen_deezer.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
}
],
"preset": {
"mergeType": 1,
"mergeType": 1.0,
"consolidateURL": 0.5,
"treeShake": true,
"inferTypeNames": true
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/fixtures/generator/gen_json_proto_mix_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
}
],
"preset": {
"mergeType": 1,
"mergeType": 1.0,
"consolidateURL": 0.5,
"inferTypeNames": true,
"treeShake": true
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/fixtures/generator/gen_jsonplaceholder.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
}
],
"preset": {
"mergeType": 1,
"mergeType": 1.0,
"consolidateURL": 0.5,
"treeShake": true,
"inferTypeNames": true
Expand Down

2 comments on commit aa669c4

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

running 269 tests
test run_execution_spec::add-field-index-list.md ... ok
test run_execution_spec::add-field-many-list.md ... ok
test run_execution_spec::add-field-many.md ... ok
test run_execution_spec::add-field-modify.md ... ok
test run_execution_spec::add-field-with-modify.md ... ok
test run_execution_spec::add-field-with-composition.md ... ok
test run_execution_spec::add-field.md ... ok
test run_execution_spec::apollo-tracing.md ... ok
test run_execution_spec::async-cache-disabled.md ... ok
test run_execution_spec::async-cache-enable-multiple-resolvers.md ... ok
test run_execution_spec::async-cache-global.md ... ok
test run_execution_spec::async-cache-enabled.md ... ok
test run_execution_spec::async-cache-inflight-request.md ... ok
test run_execution_spec::auth-protected-without-auth.md ... ok
test run_execution_spec::auth-jwt.md ... ok
test run_execution_spec::auth-basic.md ... ok
test run_execution_spec::batching-disabled.md ... ok
test run_execution_spec::batching-default.md ... ok
test run_execution_spec::auth.md ... ok
test run_execution_spec::batching-group-by-default.md ... ok
test run_execution_spec::batching-group-by-optional-key.md ... ok
test run_execution_spec::batching-group-by.md ... ok
test run_execution_spec::batching-post.md ... ok
test run_execution_spec::batching.md ... ok
test run_execution_spec::cache-control.md ... ok
test run_execution_spec::call-graphql-datasource.md ... ok
test run_execution_spec::caching-collision.md ... ok
test run_execution_spec::caching.md ... ok
test run_execution_spec::call-multiple-steps-piping.md ... ok
test run_execution_spec::call-mutation.md ... ok
test run_execution_spec::call-operator.md ... ok
test run_execution_spec::cors-allow-cred-true.md ... ok
test run_execution_spec::cors-invalid-expose-headers.md ... ok
test run_execution_spec::cors-invalid-headers.md ... ok
test run_execution_spec::cors-invalid-methods.md ... ok
test run_execution_spec::cors-invalid-origins.md ... ok
test run_execution_spec::cors-allow-cred-false.md ... ok
test run_execution_spec::cors-allow-cred-vary.md ... ok
test run_execution_spec::custom-headers.md ... ok
test run_execution_spec::dedupe_batch_query_execution.md ... ok
test run_execution_spec::default-value-arg.md ... ok
test run_execution_spec::experimental-headers-error.md ... ok
test run_execution_spec::default-value-config.md ... ok
test run_execution_spec::env-value.md ... ok
test run_execution_spec::graphql-conformance-002.md ... ok
test run_execution_spec::experimental-headers.md ... ok
test run_execution_spec::graphql-conformance-004.md ... ok
test run_execution_spec::graphql-conformance-005.md ... ok
test run_execution_spec::graphql-conformance-006.md ... ok
test run_execution_spec::graphql-conformance-007.md ... ok
test run_execution_spec::graphql-conformance-008.md ... ok
test run_execution_spec::graphql-conformance-009.md ... ok
test run_execution_spec::graphql-conformance-003.md ... ok
test run_execution_spec::graphql-conformance-001.md ... ok
test run_execution_spec::graphql-conformance-011.md ... ok
test run_execution_spec::graphql-conformance-012.md ... ok
test run_execution_spec::graphql-conformance-010.md ... ok
test run_execution_spec::graphql-conformance-014.md ... ok
test run_execution_spec::graphql-conformance-016.md ... ok
test run_execution_spec::graphql-conformance-017.md ... ok
test run_execution_spec::graphql-conformance-015.md ... ok
test run_execution_spec::graphql-conformance-013.md ... FAILED
test run_execution_spec::graphql-conformance-http-001.md ... ok
test run_execution_spec::graphql-conformance-http-002.md ... ok
test run_execution_spec::graphql-conformance-http-003.md ... ok
test run_execution_spec::graphql-conformance-http-004.md ... ok
test run_execution_spec::graphql-conformance-http-007.md ... ok
test run_execution_spec::graphql-conformance-http-008.md ... ok
test run_execution_spec::graphql-conformance-http-009.md ... ok
test run_execution_spec::graphql-conformance-http-005.md ... ok
test run_execution_spec::graphql-conformance-http-011.md ... ok
test run_execution_spec::graphql-conformance-http-006.md ... ok
test run_execution_spec::graphql-conformance-http-010.md ... ok
test run_execution_spec::graphql-conformance-http-012.md ... ok
test run_execution_spec::graphql-conformance-http-013.md ... FAILED
test run_execution_spec::graphql-conformance-http-016.md ... ok
test run_execution_spec::graphql-conformance-http-017.md ... ok
test run_execution_spec::graphql-conformance-http-014.md ... ok
test run_execution_spec::graphql-conformance-http-015.md ... ok
test run_execution_spec::graphql-dataloader-batch-request.md ... ok
test run_execution_spec::graphql-dataloader-no-batch-request.md ... ok
test run_execution_spec::graphql-datasource-errors.md ... ok
test run_execution_spec::graphql-datasource-mutation.md ... ok
test run_execution_spec::graphql-datasource-no-args.md ... ok
test run_execution_spec::graphql-datasource-query-directives.md ... ok
test run_execution_spec::graphql-datasource-with-args.md ... ok
test run_execution_spec::graphql-datasource-with-empty-enum.md ... ok
test run_execution_spec::graphql-datasource-with-mandatory-enum.md ... ok
test run_execution_spec::graphql-nested-datasource.md ... ok
test run_execution_spec::grpc-batch.md ... ok
test run_execution_spec::grpc-error.md ... ok
test run_execution_spec::grpc-json.md ... ok
test run_execution_spec::grpc-map.md ... ok
test run_execution_spec::grpc-oneof.md ... FAILED
test run_execution_spec::grpc-override-url-from-upstream.md ... ok
test run_execution_spec::grpc-proto-with-same-package.md ... ok
test run_execution_spec::grpc-reflection.md ... ok
test run_execution_spec::grpc-simple.md ... ok
test run_execution_spec::https.md ... ok
test run_execution_spec::grpc-url-from-upstream.md ... ok
test run_execution_spec::inline-field.md ... ok
test run_execution_spec::inline-index-list.md ... ok
test run_execution_spec::input-type-protected-error.md ... ok
test run_execution_spec::io-cache.md ... ok
test run_execution_spec::inline-many-list.md ... ok
test run_execution_spec::inline-many.md ... ok
test run_execution_spec::js-directive.md ... ok
test run_execution_spec::modified-field.md ... ok
test run_execution_spec::mutation-put.md ... ok
test run_execution_spec::mutation.md ... ok
test run_execution_spec::jsonplaceholder-call-post.md ... ok
test run_execution_spec::n-plus-one-list.md ... ok
test run_execution_spec::n-plus-one.md ... ok
test run_execution_spec::nested-objects.md ... ok
test run_execution_spec::nested-recursive-types.md ... ok
test run_execution_spec::nesting-level3.md ... ok
test run_execution_spec::nullable-arg-query.md ... ok
test run_execution_spec::omit-index-list.md ... ok
test run_execution_spec::predefined-scalar.md ... ok
test run_execution_spec::omit-resolved-by-parent.md ... ok
test run_execution_spec::recursive-types-no-resolver.md ... ok
test run_execution_spec::recursive-types-json.md ... ok
test run_execution_spec::omit-many.md ... ok
test run_execution_spec::ref-other-nested.md ... ok
test run_execution_spec::recursive-types.md ... ok
test run_execution_spec::ref-other.md ... ok
test run_execution_spec::related-fields-recursive.md ... ok
test run_execution_spec::rename-field.md ... ok
test run_execution_spec::request-to-upstream-batching.md ... ok
test run_execution_spec::resolve-with-headers.md ... ok
test run_execution_spec::resolve-with-vars.md ... ok
test run_execution_spec::resolved-by-parent.md ... ok
test run_execution_spec::rest-api-post.md ... ok
test run_execution_spec::rest-api-error.md ... ok
test run_execution_spec::rest-api.md ... ok
test run_execution_spec::showcase.md ... ok
test run_execution_spec::test-add-field-error.md ... ok
test run_execution_spec::simple-graphql.md ... ok
test run_execution_spec::simple-query.md ... ok
test run_execution_spec::test-add-field-list.md ... ok
test run_execution_spec::test-all-blueprint-errors.md ... ok
test run_execution_spec::test-batch-operator-post.md ... ok
test run_execution_spec::test-add-field.md ... ok
test run_execution_spec::test-add-link-to-empty-config.md ... ok
test run_execution_spec::test-call-operator-errors.md ... ok
test run_execution_spec::test-conflict-allowed-headers.md ... ok
test run_execution_spec::test-conflict-vars.md ... ok
test run_execution_spec::test-cache.md ... ok
test run_execution_spec::test-batching-group-by.md ... ok
test run_execution_spec::test-dbl-usage-many.md ... ok
test run_execution_spec::test-custom-scalar.md ... ok
test run_execution_spec::test-directives-undef-null-fields.md ... ok
test run_execution_spec::test-duplicated-link.md ... ok
test run_execution_spec::test-empty-link.md ... ok
test run_execution_spec::test-custom-types.md ... ok
test run_execution_spec::test-enable-jit.md ... ok
test run_execution_spec::test-description-many.md ... ok
test run_execution_spec::test-enum-default.md ... ok
test run_execution_spec::test-enum-empty.md ... ok
test run_execution_spec::test-enum-aliases.md ... ok
test run_execution_spec::test-enum-merge.md ... ok
test run_execution_spec::test-expr-error.md ... ok
test run_execution_spec::test-enum-description.md ... ok
test run_execution_spec::test-expr-with-add-field.md ... ok
test run_execution_spec::test-expr-with-inline.md ... ok
test run_execution_spec::test-expr-scalar-as-string.md ... ok
test run_execution_spec::test-enum.md ... ok
test run_execution_spec::test-field-already-implemented-from-Interface.md ... ok
test run_execution_spec::test-expr-with-mustache.md ... ok
test run_execution_spec::test-graphqlsource-no-base-url.md ... ok
test run_execution_spec::test-graphql-with-add-field.md ... ok
test run_execution_spec::test-groupby-without-batching.md ... ok
test run_execution_spec::test-grpc-group-by.md ... ok
test run_execution_spec::test-grpc-invalid-method-format.md ... ok
test run_execution_spec::test-grpc-invalid-proto-id.md ... ok
test run_execution_spec::test-grpc-missing-fields.md ... ok
test run_execution_spec::test-grpc-nested-data.md ... ok
test run_execution_spec::test-grpc-nested-optional.md ... ok
test run_execution_spec::test-grpc-optional.md ... ok
test run_execution_spec::test-grpc-proto-path.md ... ok
test run_execution_spec::test-grpc-service-method.md ... ok
test run_execution_spec::test-grpc-service.md ... ok
test run_execution_spec::test-expr.md ... ok
test run_execution_spec::test-hostname-faliure.md ... ok
test run_execution_spec::test-graphqlsource.md ... ok
test run_execution_spec::test-grpc.md ... ok
test run_execution_spec::test-http-baseurl.md ... ok
test run_execution_spec::test-http-batchKey.md ... ok
test run_execution_spec::test-http-with-add-field.md ... ok
test run_execution_spec::test-http-with-inline.md ... ok
test run_execution_spec::test-http-headers.md ... ok
test run_execution_spec::test-http-with-mustache-expr.md ... ok
test run_execution_spec::test-inline-error.md ... ok
test run_execution_spec::test-http-tmpl.md ... ok
test run_execution_spec::test-http.md ... ok
test run_execution_spec::test-inline-list.md ... ok
test run_execution_spec::test-inline.md ... ok
test run_execution_spec::test-input-out.md ... ok
test run_execution_spec::test-input-documentation.md ... ok
test run_execution_spec::test-input-with-arg-out.md ... ok
test run_execution_spec::test-interface-from-json.md ... ok
test run_execution_spec::test-invalid-query-in-http.md ... ok
test run_execution_spec::test-invalid-server.md ... ok
test run_execution_spec::test-js-multi-onRequest-handlers.md ... ok
test run_execution_spec::test-js-multiple-scripts.md ... ok
test run_execution_spec::test-interface-result.md ... ok
test run_execution_spec::test-interface.md ... ok
test run_execution_spec::test-lack-resolver.md ... ok
test run_execution_spec::test-js-request-response-2.md ... ok
test run_execution_spec::test-js-request-response.md ... ok
test run_execution_spec::test-merge-batch.md ... ok
test run_execution_spec::test-list-args.md ... ok
test run_execution_spec::test-merge-nested.md ... ok
test run_execution_spec::test-merge-query.md ... ok
test run_execution_spec::test-merge-union.md ... ok
test run_execution_spec::test-missing-argument-on-all-resolvers.md ... ok
test run_execution_spec::test-missing-mutation-resolver.md ... ok
test run_execution_spec::test-missing-query-resolver.md ... ok
test run_execution_spec::test-missing-root-types.md ... ok
test run_execution_spec::test-missing-schema-query.md ... ok
test run_execution_spec::test-merge-right-with-link-config.md ... ok
test run_execution_spec::test-merge-server-sdl.md ... ok
test run_execution_spec::test-multiple-config-types.md ... ok
test run_execution_spec::test-multiple-resolvable-directives-on-field.md ... ok
test run_execution_spec::test-modify.md ... ok
test run_execution_spec::test-multi-interface.md ... ok
test run_execution_spec::test-nested-input.md ... ok
test run_execution_spec::test-no-base-url.md ... ok
test run_execution_spec::test-nested-link.md ... ok
test run_execution_spec::test-nested-value.md ... ok
test run_execution_spec::test-null-in-array.md ... ok
test run_execution_spec::test-null-in-object.md ... ok
test run_execution_spec::test-omit-list.md ... ok
test run_execution_spec::test-optional-key-skip-empty.md ... ok
test run_execution_spec::test-omit.md ... ok
test run_execution_spec::test-params-as-body.md ... ok
test run_execution_spec::test-query-documentation.md ... ok
test run_execution_spec::test-query.md ... ok
test run_execution_spec::test-response-header-merge.md ... ok
test run_execution_spec::test-response-header-value.md ... ok
test run_execution_spec::test-response-headers-multi.md ... ok
test run_execution_spec::test-response-headers-name.md ... ok
test run_execution_spec::test-ref-other.md ... ok
test run_execution_spec::test-required-fields.md ... FAILED
test run_execution_spec::test-scalars-builtin.md ... ok
test run_execution_spec::test-scalars-integers.md ... ok
test run_execution_spec::test-server-base-types.md ... ok
test run_execution_spec::test-scalars-validation.md ... ok
test run_execution_spec::test-set-cookie-headers.md ... ok
test run_execution_spec::test-server-vars.md ... ok
test run_execution_spec::test-undefined-query.md ... ok
test run_execution_spec::test-static-value.md ... ok
test run_execution_spec::test-union-many-types.md ... ok
test run_execution_spec::test-union-same-types.md ... ok
test run_execution_spec::test-scalars.md ... ok
test run_execution_spec::test-union-ambiguous.md ... ok
test run_execution_spec::test-upstream-headers.md ... ok
test run_execution_spec::undeclared-type-no-base-url.md ... ok
test run_execution_spec::undeclared-type.md ... ok
test run_execution_spec::test-union.md ... FAILED
test run_execution_spec::test-upstream.md ... ok
test run_execution_spec::upstream-batching.md ... ok
test run_execution_spec::upstream-fail-request.md ... ok
test run_execution_spec::with-args-url.md ... ok
test run_execution_spec::with-args.md ... ok
test run_execution_spec::with-nesting.md ... ok
test run_execution_spec::yaml-nested-unions.md ... ok
test run_execution_spec::yaml-union-in-type.md ... ok
test run_execution_spec::yaml-union.md ... ok

failures:

---- run_execution_spec::graphql-conformance-013.md ----
test panicked: snapshot assertion for 'graphql-conformance-013.md_0' failed in line 202

---- run_execution_spec::graphql-conformance-http-013.md ----
test panicked: snapshot assertion for 'graphql-conformance-http-013.md_0' failed in line 202

---- run_execution_spec::grpc-oneof.md ----
test panicked: snapshot assertion for 'grpc-oneof.md_0' failed in line 202

---- run_execution_spec::test-required-fields.md ----
test panicked: snapshot assertion for 'test-required-fields.md_8' failed in line 202

---- run_execution_spec::test-union.md ----
test panicked: snapshot assertion for 'test-union.md_5' failed in line 202

failures:
run_execution_spec::graphql-conformance-013.md
run_execution_spec::graphql-conformance-http-013.md
run_execution_spec::grpc-oneof.md
run_execution_spec::test-required-fields.md
run_execution_spec::test-union.md

test result: FAILED. 264 passed; 5 failed; 0 ignored; 0 measured; 0 filtered out; finished in 13.85s

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running 30s test @ http://localhost:8000/graphql

4 threads and 100 connections

Thread Stats Avg Stdev Max +/- Stdev
Latency 6.82ms 3.39ms 124.19ms 77.11%
Req/Sec 3.73k 206.23 4.16k 91.42%

445067 requests in 30.01s, 2.23GB read

Requests/sec: 14832.52

Transfer/sec: 76.13MB

Please sign in to comment.