From 4c4b5bacc42ed2308d9245486240e85447a2e9dc Mon Sep 17 00:00:00 2001 From: Kiryl Mialeshka <8974488+meskill@users.noreply.github.com> Date: Mon, 6 May 2024 13:52:37 +0200 Subject: [PATCH] refactor(config): remove explicit interface flag (#1872) --- generated/.tailcallrc.schema.json | 4 -- src/blueprint/definitions.rs | 2 +- src/config/config.rs | 23 ++++++---- src/config/config_module.rs | 12 +++++- src/config/from_document.rs | 9 ---- src/config/into_document.rs | 2 +- .../test-interface-from-json.md_client.snap | 32 ++++++++++++++ .../test-interface-from-json.md_merged.snap | 20 +++++++++ tests/execution/test-interface-from-json.md | 42 +++++++++++++++++++ 9 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 tests/core/snapshots/test-interface-from-json.md_client.snap create mode 100644 tests/core/snapshots/test-interface-from-json.md_merged.snap create mode 100644 tests/execution/test-interface-from-json.md diff --git a/generated/.tailcallrc.schema.json b/generated/.tailcallrc.schema.json index ac9632287f..5357369acd 100644 --- a/generated/.tailcallrc.schema.json +++ b/generated/.tailcallrc.schema.json @@ -1247,10 +1247,6 @@ }, "uniqueItems": true }, - "interface": { - "description": "Flag to indicate if the type is an interface.", - "type": "boolean" - }, "protected": { "description": "Marks field as protected by auth providers", "default": null, diff --git a/src/blueprint/definitions.rs b/src/blueprint/definitions.rs index ef6127e323..fe5126b2dc 100644 --- a/src/blueprint/definitions.rs +++ b/src/blueprint/definitions.rs @@ -542,7 +542,7 @@ pub fn to_definitions<'a>() -> TryFold<'a, ConfigModule, Vec, String Definition::Object(object_type_definition) => { if config_module.input_types.contains(name) { to_input_object_type_definition(object_type_definition).trace(name) - } else if type_.interface { + } else if config_module.interface_types.contains(name) { to_interface_type_definition(object_type_definition).trace(name) } else { Valid::succeed(definition) diff --git a/src/config/config.rs b/src/config/config.rs index fe4e31d2f1..0188a2b06e 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -92,10 +92,6 @@ pub struct Type { pub doc: Option, #[serde(default, skip_serializing_if = "is_default")] /// - /// Flag to indicate if the type is an interface. - pub interface: bool, - #[serde(default, skip_serializing_if = "is_default")] - /// /// Interfaces that the type implements. pub implements: BTreeSet, #[serde(rename = "enum", default, skip_serializing_if = "is_default")] @@ -731,9 +727,8 @@ impl Config { } for (type_name, type_of) in self.types.iter() { - if (type_of.interface || !type_of.fields.is_empty()) && !input_types.contains(type_name) - { - for (_, field) in type_of.fields.iter() { + if !input_types.contains(type_name) { + for field in type_of.fields.values() { types.insert(field.type_of.clone()); } } @@ -742,11 +737,23 @@ impl Config { types } + /// Returns a list of all the types that are used as interface + pub fn interface_types(&self) -> HashSet { + let mut types = HashSet::new(); + + for ty in self.types.values() { + for interface in ty.implements.iter() { + types.insert(interface.clone()); + } + } + + types + } + /// Returns a list of all the arguments in the configuration fn arguments(&self) -> Vec<(&String, &Arg)> { self.types .iter() - .filter(|(_, value)| !value.interface) .flat_map(|(_, type_of)| type_of.fields.iter()) .flat_map(|(_, field)| field.args.iter()) .collect::>() diff --git a/src/config/config_module.rs b/src/config/config_module.rs index 8e75dadf0c..f7299f2260 100644 --- a/src/config/config_module.rs +++ b/src/config/config_module.rs @@ -21,6 +21,7 @@ pub struct ConfigModule { pub extensions: Extensions, pub input_types: HashSet, pub output_types: HashSet, + pub interface_types: HashSet, } #[derive(Clone, Debug, Default)] @@ -202,8 +203,15 @@ impl From for ConfigModule { fn from(config: Config) -> Self { let input_types = config.input_types(); let output_types = config.output_types(); - - ConfigModule { config, input_types, output_types, ..Default::default() } + let interface_types = config.interface_types(); + + ConfigModule { + config, + input_types, + output_types, + interface_types, + ..Default::default() + } } } diff --git a/src/config/from_document.rs b/src/config/from_document.rs index ab87b20cbd..1068b65855 100644 --- a/src/config/from_document.rs +++ b/src/config/from_document.rs @@ -210,7 +210,6 @@ where { let fields = object.fields(); let implements = object.implements(); - let interface = object.is_interface(); Cache::from_directives(directives.iter()) .fuse(to_fields(fields)) @@ -224,7 +223,6 @@ where fields, added_fields, doc, - interface, implements, cache, protected, @@ -451,7 +449,6 @@ impl Fieldlike for InputValueDefinition { trait ObjectLike { fn fields(&self) -> &Vec>; fn implements(&self) -> &Vec>; - fn is_interface(&self) -> bool; } impl ObjectLike for ObjectType { fn fields(&self) -> &Vec> { @@ -460,9 +457,6 @@ impl ObjectLike for ObjectType { fn implements(&self) -> &Vec> { &self.implements } - fn is_interface(&self) -> bool { - false - } } impl ObjectLike for InterfaceType { fn fields(&self) -> &Vec> { @@ -471,7 +465,4 @@ impl ObjectLike for InterfaceType { fn implements(&self) -> &Vec> { &self.implements } - fn is_interface(&self) -> bool { - true - } } diff --git a/src/config/into_document.rs b/src/config/into_document.rs index 7a782130a6..99792a426c 100644 --- a/src/config/into_document.rs +++ b/src/config/into_document.rs @@ -54,7 +54,7 @@ fn config_document(config: &ConfigModule) -> ServiceDocument { }; definitions.push(TypeSystemDefinition::Schema(pos(schema_definition))); for (type_name, type_def) in config.types.iter() { - let kind = if type_def.interface { + let kind = if config.interface_types.contains(type_name) { TypeKind::Interface(InterfaceType { implements: type_def .implements diff --git a/tests/core/snapshots/test-interface-from-json.md_client.snap b/tests/core/snapshots/test-interface-from-json.md_client.snap new file mode 100644 index 0000000000..c62d23aa48 --- /dev/null +++ b/tests/core/snapshots/test-interface-from-json.md_client.snap @@ -0,0 +1,32 @@ +--- +source: tests/core/spec.rs +expression: client +--- +type B implements IA { + a: String + b: String +} + +scalar Date + +scalar Email + +scalar Empty + +interface IA { + a: String +} + +scalar JSON + +scalar PhoneNumber + +type Query { + bar: B +} + +scalar Url + +schema { + query: Query +} diff --git a/tests/core/snapshots/test-interface-from-json.md_merged.snap b/tests/core/snapshots/test-interface-from-json.md_merged.snap new file mode 100644 index 0000000000..f21cd0c870 --- /dev/null +++ b/tests/core/snapshots/test-interface-from-json.md_merged.snap @@ -0,0 +1,20 @@ +--- +source: tests/core/spec.rs +expression: merged +--- +schema @server @upstream(baseURL: "http://jsonplaceholder.typicode.com") { + query: Query +} + +interface IA { + a: String +} + +type B implements IA { + a: String + b: String +} + +type Query { + bar: B @http(path: "/posts") +} diff --git a/tests/execution/test-interface-from-json.md b/tests/execution/test-interface-from-json.md new file mode 100644 index 0000000000..6ffb5f9c92 --- /dev/null +++ b/tests/execution/test-interface-from-json.md @@ -0,0 +1,42 @@ +# Interfaces defined in json + +```json @server +{ + "upstream": { + "baseURL": "http://jsonplaceholder.typicode.com" + }, + "schema": { + "query": "Query" + }, + "types": { + "IA": { + "fields": { + "a": { + "type": "String" + } + } + }, + "B": { + "implements": ["IA"], + "fields": { + "a": { + "type": "String" + }, + "b": { + "type": "String" + } + } + }, + "Query": { + "fields": { + "bar": { + "type": "B", + "http": { + "path": "/posts" + } + } + } + } + } +} +```