Add `Schema::build_with_ignore_name_conflicts` method to specifies a list to ignore type conflict detection.

This commit is contained in:
Sunli 2022-05-24 20:08:35 +08:00
parent e09494ae03
commit d0bb37f419
6 changed files with 92 additions and 6 deletions

View File

@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# [4.0.1] 2022-5-24
- Add `Schema::build_with_ignore_name_conflicts` method to specifies a list to ignore type conflict detection.
# [4.0.0] 2022-5-17
- Implement the `ConnectionNameType` and `EdgeNameType` traits to specify GraphQL type names for `Connection` and `Edge`, which can be automatically generated using `DefaultConnectionName` and `DefaultEdgeName`.

View File

@ -403,6 +403,7 @@ pub struct Registry {
pub introspection_mode: IntrospectionMode,
pub enable_federation: bool,
pub federation_subscription: bool,
pub ignore_name_conflicts: HashSet<String>,
}
impl Registry {
@ -462,7 +463,8 @@ impl Registry {
return;
}
if rust_typename != prev_typename {
if rust_typename != prev_typename && !self.ignore_name_conflicts.contains(name)
{
panic!(
"`{}` and `{}` have the same GraphQL name `{}`",
prev_typename, rust_typename, name,

View File

@ -1,4 +1,9 @@
use std::{any::Any, collections::HashMap, ops::Deref, sync::Arc};
use std::{
any::Any,
collections::{HashMap, HashSet},
ops::Deref,
sync::Arc,
};
use futures_util::stream::{self, Stream, StreamExt};
use indexmap::map::IndexMap;
@ -302,12 +307,32 @@ where
mutation: Mutation,
subscription: Subscription,
) -> SchemaBuilder<Query, Mutation, Subscription> {
Self::build_with_ignore_name_conflicts(query, mutation, subscription, [] as [&str; 0])
}
/// Create a schema builder and specifies a list to ignore type conflict
/// detection.
///
/// NOTE: It is not recommended to use it unless you know what it does.
#[must_use]
pub fn build_with_ignore_name_conflicts<I, T>(
query: Query,
mutation: Mutation,
subscription: Subscription,
ignore_name_conflicts: I,
) -> SchemaBuilder<Query, Mutation, Subscription>
where
I: IntoIterator<Item = T>,
T: Into<String>,
{
SchemaBuilder {
validation_mode: ValidationMode::Strict,
query: QueryRoot { inner: query },
mutation,
subscription,
registry: Self::create_registry(),
registry: Self::create_registry(
ignore_name_conflicts.into_iter().map(Into::into).collect(),
),
data: Default::default(),
complexity: None,
depth: None,
@ -316,7 +341,7 @@ where
}
}
pub(crate) fn create_registry() -> Registry {
pub(crate) fn create_registry(ignore_name_conflicts: HashSet<String>) -> Registry {
let mut registry = Registry {
types: Default::default(),
directives: Default::default(),
@ -335,6 +360,7 @@ where
introspection_mode: IntrospectionMode::Enabled,
enable_federation: false,
federation_subscription: false,
ignore_name_conflicts,
};
registry.add_directive(MetaDirective {

View File

@ -171,7 +171,8 @@ mod tests {
}
fn check_complex(query: &str, expect_complex: usize) {
let registry = Schema::<Query, EmptyMutation, Subscription>::create_registry();
let registry =
Schema::<Query, EmptyMutation, Subscription>::create_registry(Default::default());
let doc = parse_query(query).unwrap();
let mut ctx = VisitorContext::new(&registry, &doc, None);
let mut complex = 0;

View File

@ -76,7 +76,8 @@ mod tests {
}
fn check_depth(query: &str, expect_depth: usize) {
let registry = Schema::<Query, EmptyMutation, EmptySubscription>::create_registry();
let registry =
Schema::<Query, EmptyMutation, EmptySubscription>::create_registry(Default::default());
let doc = parse_query(query).unwrap();
let mut ctx = VisitorContext::new(&registry, &doc, None);
let mut depth = 0;

View File

@ -141,3 +141,55 @@ async fn test_object_process_with_field() {
})
);
}
#[tokio::test]
async fn ignore_name_conflicts() {
#[derive(SimpleObject)]
#[graphql(name = "MyObj")]
struct MyObj {
name: String,
}
#[derive(SimpleObject)]
#[graphql(name = "MyObj")]
struct MyObjRef<'a> {
name: &'a str,
}
struct Query;
#[Object]
impl Query {
async fn obj_owned(&self) -> MyObj {
MyObj {
name: "a".to_string(),
}
}
async fn obj_ref(&self) -> MyObjRef<'_> {
MyObjRef { name: "b" }
}
}
let schema = Schema::build_with_ignore_name_conflicts(
Query,
EmptyMutation,
EmptySubscription,
["MyObj"],
)
.finish();
let query = r#"
{
objOwned { name }
objRef { name }
}
"#;
assert_eq!(
schema.execute(query).await.into_result().unwrap().data,
value!({
"objOwned": { "name": "a" },
"objRef": { "name": "b" },
})
);
}