Merge pull request #1029 from raptros/add-overrides-directive
define override directive on fields
This commit is contained in:
commit
7b1c711f44
|
@ -155,6 +155,8 @@ pub struct SimpleObjectField {
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub inaccessible: bool,
|
pub inaccessible: bool,
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
|
pub override_from: Option<String>,
|
||||||
|
#[darling(default)]
|
||||||
pub guard: Option<SpannedValue<String>>,
|
pub guard: Option<SpannedValue<String>>,
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub visible: Option<Visible>,
|
pub visible: Option<Visible>,
|
||||||
|
@ -291,6 +293,7 @@ pub struct ObjectField {
|
||||||
pub requires: Option<String>,
|
pub requires: Option<String>,
|
||||||
pub shareable: bool,
|
pub shareable: bool,
|
||||||
pub inaccessible: bool,
|
pub inaccessible: bool,
|
||||||
|
pub override_from: Option<String>,
|
||||||
pub guard: Option<SpannedValue<String>>,
|
pub guard: Option<SpannedValue<String>>,
|
||||||
pub visible: Option<Visible>,
|
pub visible: Option<Visible>,
|
||||||
pub complexity: Option<ComplexityType>,
|
pub complexity: Option<ComplexityType>,
|
||||||
|
@ -524,6 +527,8 @@ pub struct InterfaceField {
|
||||||
pub inaccessible: bool,
|
pub inaccessible: bool,
|
||||||
#[darling(default)]
|
#[darling(default)]
|
||||||
pub shareable: bool,
|
pub shareable: bool,
|
||||||
|
#[darling(default)]
|
||||||
|
pub override_from: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromVariant)]
|
#[derive(FromVariant)]
|
||||||
|
@ -808,6 +813,7 @@ pub struct ComplexObjectField {
|
||||||
pub requires: Option<String>,
|
pub requires: Option<String>,
|
||||||
pub shareable: bool,
|
pub shareable: bool,
|
||||||
pub inaccessible: bool,
|
pub inaccessible: bool,
|
||||||
|
pub override_from: Option<String>,
|
||||||
pub guard: Option<SpannedValue<String>>,
|
pub guard: Option<SpannedValue<String>>,
|
||||||
pub visible: Option<Visible>,
|
pub visible: Option<Visible>,
|
||||||
pub complexity: Option<ComplexityType>,
|
pub complexity: Option<ComplexityType>,
|
||||||
|
|
|
@ -173,6 +173,10 @@ pub fn generate(
|
||||||
let field_deprecation = gen_deprecation(&method_args.deprecation, &crate_name);
|
let field_deprecation = gen_deprecation(&method_args.deprecation, &crate_name);
|
||||||
let external = method_args.external;
|
let external = method_args.external;
|
||||||
let shareable = method_args.shareable;
|
let shareable = method_args.shareable;
|
||||||
|
let override_from = match &method_args.override_from {
|
||||||
|
Some(from) => quote! { ::std::option::Option::Some(#from) },
|
||||||
|
None => quote! { ::std::option::Option::None },
|
||||||
|
};
|
||||||
let inaccessible = method_args.inaccessible;
|
let inaccessible = method_args.inaccessible;
|
||||||
let requires = match &method_args.requires {
|
let requires = match &method_args.requires {
|
||||||
Some(requires) => quote! { ::std::option::Option::Some(#requires) },
|
Some(requires) => quote! { ::std::option::Option::Some(#requires) },
|
||||||
|
@ -371,6 +375,7 @@ pub fn generate(
|
||||||
requires: #requires,
|
requires: #requires,
|
||||||
shareable: #shareable,
|
shareable: #shareable,
|
||||||
inaccessible: #inaccessible,
|
inaccessible: #inaccessible,
|
||||||
|
override_from: #override_from,
|
||||||
visible: #visible,
|
visible: #visible,
|
||||||
compute_complexity: #complexity,
|
compute_complexity: #complexity,
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -140,6 +140,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
||||||
visible,
|
visible,
|
||||||
shareable,
|
shareable,
|
||||||
inaccessible,
|
inaccessible,
|
||||||
|
override_from,
|
||||||
} in &interface_args.fields
|
} in &interface_args.fields
|
||||||
{
|
{
|
||||||
let (name, method_name) = if let Some(method) = method {
|
let (name, method_name) = if let Some(method) = method {
|
||||||
|
@ -170,6 +171,10 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
||||||
Some(provides) => quote! { ::std::option::Option::Some(#provides) },
|
Some(provides) => quote! { ::std::option::Option::Some(#provides) },
|
||||||
None => quote! { ::std::option::Option::None },
|
None => quote! { ::std::option::Option::None },
|
||||||
};
|
};
|
||||||
|
let override_from = match &override_from {
|
||||||
|
Some(from) => quote! { ::std::option::Option::Some(#from) },
|
||||||
|
None => quote! { ::std::option::Option::None },
|
||||||
|
};
|
||||||
|
|
||||||
decl_params.push(quote! { ctx: &'ctx #crate_name::Context<'ctx> });
|
decl_params.push(quote! { ctx: &'ctx #crate_name::Context<'ctx> });
|
||||||
use_params.push(quote! { ctx });
|
use_params.push(quote! { ctx });
|
||||||
|
@ -281,6 +286,7 @@ pub fn generate(interface_args: &args::Interface) -> GeneratorResult<TokenStream
|
||||||
requires: #requires,
|
requires: #requires,
|
||||||
shareable: #shareable,
|
shareable: #shareable,
|
||||||
inaccessible: #inaccessible,
|
inaccessible: #inaccessible,
|
||||||
|
override_from: #override_from,
|
||||||
visible: #visible,
|
visible: #visible,
|
||||||
compute_complexity: ::std::option::Option::None,
|
compute_complexity: ::std::option::Option::None,
|
||||||
});
|
});
|
||||||
|
|
|
@ -319,6 +319,10 @@ pub fn generate(
|
||||||
let external = method_args.external;
|
let external = method_args.external;
|
||||||
let shareable = method_args.shareable;
|
let shareable = method_args.shareable;
|
||||||
let inaccessible = method_args.inaccessible;
|
let inaccessible = method_args.inaccessible;
|
||||||
|
let override_from = match &method_args.override_from {
|
||||||
|
Some(from) => quote! { ::std::option::Option::Some(#from) },
|
||||||
|
None => quote! { ::std::option::Option::None },
|
||||||
|
};
|
||||||
let requires = match &method_args.requires {
|
let requires = match &method_args.requires {
|
||||||
Some(requires) => quote! { ::std::option::Option::Some(#requires) },
|
Some(requires) => quote! { ::std::option::Option::Some(#requires) },
|
||||||
None => quote! { ::std::option::Option::None },
|
None => quote! { ::std::option::Option::None },
|
||||||
|
@ -515,6 +519,7 @@ pub fn generate(
|
||||||
requires: #requires,
|
requires: #requires,
|
||||||
shareable: #shareable,
|
shareable: #shareable,
|
||||||
inaccessible: #inaccessible,
|
inaccessible: #inaccessible,
|
||||||
|
override_from: #override_from,
|
||||||
visible: #visible,
|
visible: #visible,
|
||||||
compute_complexity: #complexity,
|
compute_complexity: #complexity,
|
||||||
});
|
});
|
||||||
|
|
|
@ -131,6 +131,10 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
||||||
let external = field.external;
|
let external = field.external;
|
||||||
let shareable = field.shareable;
|
let shareable = field.shareable;
|
||||||
let inaccessible = field.inaccessible;
|
let inaccessible = field.inaccessible;
|
||||||
|
let override_from = match &field.override_from {
|
||||||
|
Some(from) => quote! { ::std::option::Option::Some(#from) },
|
||||||
|
None => quote! { ::std::option::Option::None },
|
||||||
|
};
|
||||||
let requires = match &field.requires {
|
let requires = match &field.requires {
|
||||||
Some(requires) => quote! { ::std::option::Option::Some(#requires) },
|
Some(requires) => quote! { ::std::option::Option::Some(#requires) },
|
||||||
None => quote! { ::std::option::Option::None },
|
None => quote! { ::std::option::Option::None },
|
||||||
|
@ -180,6 +184,7 @@ pub fn generate(object_args: &args::SimpleObject) -> GeneratorResult<TokenStream
|
||||||
requires: #requires,
|
requires: #requires,
|
||||||
shareable: #shareable,
|
shareable: #shareable,
|
||||||
inaccessible: #inaccessible,
|
inaccessible: #inaccessible,
|
||||||
|
override_from: #override_from,
|
||||||
visible: #visible,
|
visible: #visible,
|
||||||
compute_complexity: ::std::option::Option::None,
|
compute_complexity: ::std::option::Option::None,
|
||||||
});
|
});
|
||||||
|
|
|
@ -269,6 +269,7 @@ pub fn generate(
|
||||||
requires: ::std::option::Option::None,
|
requires: ::std::option::Option::None,
|
||||||
provides: ::std::option::Option::None,
|
provides: ::std::option::Option::None,
|
||||||
shareable: false,
|
shareable: false,
|
||||||
|
override_from: ::std::option::Option::None,
|
||||||
visible: #visible,
|
visible: #visible,
|
||||||
inaccessible: false,
|
inaccessible: false,
|
||||||
compute_complexity: #complexity,
|
compute_complexity: #complexity,
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
- The `inaccessible` directive is used to indicate that a location in the schema cannot be queried at the supergraph level, but can still be queried at the subgraph level.
|
- The `inaccessible` directive is used to indicate that a location in the schema cannot be queried at the supergraph level, but can still be queried at the subgraph level.
|
||||||
|
|
||||||
|
- The `override` directive is used to indicate that a field is now to be resolved by the current subgraph instead of the named subgraph.
|
||||||
|
|
||||||
## Entity lookup function
|
## Entity lookup function
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
|
|
@ -33,6 +33,7 @@ some simple fields, and use the `ComplexObject` macro to define some other field
|
||||||
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
||||||
| shareable | Indicate that a field is allowed to be resolved by multiple subgraphs | bool | Y |
|
| shareable | Indicate that a field is allowed to be resolved by multiple subgraphs | bool | Y |
|
||||||
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
||||||
|
| override_from | Mark the field as overriding a field currently present on another subgraph. It is used to migrate fields between subgraphs. | string | Y |
|
||||||
| guard | Field of guard *[See also the Book](https://async-graphql.github.io/async-graphql/en/field_guard.html)* | string | Y |
|
| guard | Field of guard *[See also the Book](https://async-graphql.github.io/async-graphql/en/field_guard.html)* | string | Y |
|
||||||
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
||||||
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||||
|
|
|
@ -17,21 +17,22 @@ Define a GraphQL interface
|
||||||
|
|
||||||
# Field attributes
|
# Field attributes
|
||||||
|
|
||||||
| Attribute | description | Type | Optional |
|
| Attribute | description | Type | Optional |
|
||||||
|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------|----------|
|
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------|----------|
|
||||||
| name | Field name | string | N |
|
| name | Field name | string | N |
|
||||||
| type | Field type | string | N |
|
| type | Field type | string | N |
|
||||||
| method | Rust resolver method name. If specified, `name` will not be camelCased in schema definition | string | Y |
|
| method | Rust resolver method name. If specified, `name` will not be camelCased in schema definition | string | Y |
|
||||||
| desc | Field description | string | Y |
|
| desc | Field description | string | Y |
|
||||||
| deprecation | Field deprecated | bool | Y |
|
| deprecation | Field deprecated | bool | Y |
|
||||||
| deprecation | Field deprecation reason | string | Y |
|
| deprecation | Field deprecation reason | string | Y |
|
||||||
| arg | Field arguments | InterfaceFieldArgument | Y |
|
| arg | Field arguments | InterfaceFieldArgument | Y |
|
||||||
| external | Mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. | bool | Y |
|
| external | Mark a field as owned by another service. This allows service A to use fields from service B while also knowing at runtime the types of that field. | bool | Y |
|
||||||
| provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
| provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
||||||
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
||||||
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
| override_from | Mark the field as overriding a field currently present on another subgraph. It is used to migrate fields between subgraphs. | string | Y |
|
||||||
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
||||||
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||||
|
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
||||||
|
|
||||||
# Field argument attributes
|
# Field argument attributes
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ All methods are converted to camelCase.
|
||||||
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
||||||
| shareable | Indicate that a field is allowed to be resolved by multiple subgraphs | bool | Y |
|
| shareable | Indicate that a field is allowed to be resolved by multiple subgraphs | bool | Y |
|
||||||
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
||||||
|
| override_from | Mark the field as overriding a field currently present on another subgraph. It is used to migrate fields between subgraphs. | string | Y |
|
||||||
| guard | Field of guard *[See also the Book](https://async-graphql.github.io/async-graphql/en/field_guard.html)* | string | Y |
|
| guard | Field of guard *[See also the Book](https://async-graphql.github.io/async-graphql/en/field_guard.html)* | string | Y |
|
||||||
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
||||||
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||||
|
|
|
@ -36,8 +36,8 @@ Similar to `Object`, but defined on a structure that automatically generates get
|
||||||
| provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
| provides | Annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the gateway. | string | Y |
|
||||||
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
| requires | Annotate the required input fieldset from a base type for a resolver. It is used to develop a query plan where the required fields may not be needed by the client, but the service may need additional information from other services. | string | Y |
|
||||||
| shareable | Indicate that a field is allowed to be resolved by multiple subgraphs | bool | Y |
|
| shareable | Indicate that a field is allowed to be resolved by multiple subgraphs | bool | Y |
|
||||||
|
|
||||||
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
| inaccessible | Indicate that a field is not accessible from a supergraph when using Apollo Federation | bool | Y |
|
||||||
|
| override_from | Mark the field as overriding a field currently present on another subgraph. It is used to migrate fields between subgraphs. | string | Y |
|
||||||
| guard | Field of guard *[See also the Book](https://async-graphql.github.io/async-graphql/en/field_guard.html)* | string | Y |
|
| guard | Field of guard *[See also the Book](https://async-graphql.github.io/async-graphql/en/field_guard.html)* | string | Y |
|
||||||
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
| visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
||||||
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
| visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||||
|
|
|
@ -180,6 +180,9 @@ impl Registry {
|
||||||
if field.inaccessible {
|
if field.inaccessible {
|
||||||
write!(sdl, " @inaccessible").ok();
|
write!(sdl, " @inaccessible").ok();
|
||||||
}
|
}
|
||||||
|
if let Some(from) = field.override_from {
|
||||||
|
write!(sdl, " @override(from: \"{}\")", from).ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln!(sdl).ok();
|
writeln!(sdl).ok();
|
||||||
|
|
|
@ -169,6 +169,7 @@ pub struct MetaField {
|
||||||
pub visible: Option<MetaVisibleFn>,
|
pub visible: Option<MetaVisibleFn>,
|
||||||
pub shareable: bool,
|
pub shareable: bool,
|
||||||
pub inaccessible: bool,
|
pub inaccessible: bool,
|
||||||
|
pub override_from: Option<&'static str>,
|
||||||
pub compute_complexity: Option<ComplexityType>,
|
pub compute_complexity: Option<ComplexityType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,6 +635,7 @@ impl Registry {
|
||||||
provides: None,
|
provides: None,
|
||||||
shareable: false,
|
shareable: false,
|
||||||
inaccessible: false,
|
inaccessible: false,
|
||||||
|
override_from: None,
|
||||||
visible: None,
|
visible: None,
|
||||||
compute_complexity: None,
|
compute_complexity: None,
|
||||||
},
|
},
|
||||||
|
@ -684,6 +686,7 @@ impl Registry {
|
||||||
shareable: false,
|
shareable: false,
|
||||||
visible: None,
|
visible: None,
|
||||||
inaccessible: false,
|
inaccessible: false,
|
||||||
|
override_from: None,
|
||||||
compute_complexity: None,
|
compute_complexity: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -716,6 +719,7 @@ impl Registry {
|
||||||
shareable: false,
|
shareable: false,
|
||||||
visible: None,
|
visible: None,
|
||||||
inaccessible: false,
|
inaccessible: false,
|
||||||
|
override_from: None,
|
||||||
compute_complexity: None,
|
compute_complexity: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -135,6 +135,7 @@ impl<T: ObjectType> OutputType for QueryRoot<T> {
|
||||||
inaccessible: false,
|
inaccessible: false,
|
||||||
visible: None,
|
visible: None,
|
||||||
compute_complexity: None,
|
compute_complexity: None,
|
||||||
|
override_from: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -167,6 +168,7 @@ impl<T: ObjectType> OutputType for QueryRoot<T> {
|
||||||
provides: None,
|
provides: None,
|
||||||
shareable: false,
|
shareable: false,
|
||||||
inaccessible: false,
|
inaccessible: false,
|
||||||
|
override_from: None,
|
||||||
visible: None,
|
visible: None,
|
||||||
compute_complexity: None,
|
compute_complexity: None,
|
||||||
},
|
},
|
||||||
|
|
|
@ -328,6 +328,32 @@ pub async fn test_entity_shareable() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn test_field_override_directive() {
|
||||||
|
#[derive(SimpleObject)]
|
||||||
|
struct MyObjFieldOverride {
|
||||||
|
#[graphql(override_from = "AnotherSubgraph")]
|
||||||
|
field_override_a: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Query;
|
||||||
|
|
||||||
|
#[Object(extends)]
|
||||||
|
impl Query {
|
||||||
|
#[graphql(entity)]
|
||||||
|
async fn find_obj_field_override(&self, _id: i32) -> MyObjFieldOverride {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let schema_sdl = Schema::new(Query, EmptyMutation, EmptySubscription)
|
||||||
|
.sdl_with_options(SDLExportOptions::new().federation());
|
||||||
|
assert_eq!(
|
||||||
|
schema_sdl.contains("fieldOverrideA: Int! @override(from: \"AnotherSubgraph\")"),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
pub async fn test_entity_inaccessible() {
|
pub async fn test_entity_inaccessible() {
|
||||||
struct MyCustomObjInaccessible;
|
struct MyCustomObjInaccessible;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user