Comments (32)
Let me think about how do I implement this.π
from async-graphql.
I can't do that right now. I can't get the GraphQLType
for InfoObject
.
Adding a flatten
attribute is the simplest solution I can think of right now.π
from async-graphql.
Can you give me an example?π
from async-graphql.
Imagine something like this:
#[async_trait]
#[TraitObject] // or something similar
pub trait Info {
async fn get_info(&self) -> InfoObject;
#[field]
async fn uptime(&self) -> String {
self.get_info().uptime()
}
#[field]
async fn name(&self) -> String {
self.get_info().name()
}
}
pub struct MyInfo;
impl Info for MyInfo {
async fn get_info(&self) -> InfoObject {
InfoObject::new();
}
}
#[Object]
impl MyInfo {
#[field]
async fn additional_field(&self) -> &str {
"This will also be available"
}
}
pub struct QueryRoot;
impl QueryRoot {
async fn info(&self) -> MyInfo {
MyInfo::{}
}
}
Which allows you run queries like this:
query {
info {
uptime
name
additionalField
}
}
This example is quite silly but I think it reflects the idea of what I am trying to accomplish.
from async-graphql.
Maybe you could even do something like:
impl QueryRoot {
async fn info(&self) -> Box<dyn Info> {
MyInfo::{}
}
}
from async-graphql.
I think returning trait objects will not work because of introspection queries though.
from async-graphql.
To help you better understand my concrete needs: I have a bunch of services which each needs to provide a query of the same type but fetching that data depends on the implementation of the individual service. So if the above was possible, I could extract the trait to a shared crate and implement it for every service giving me consistent results and clean code. I could implement something like this with existing tools but not as clean and idiomatic. I would need to have a shared struct as an Object and have it store a Box of my shared trait.
from async-graphql.
I fully understand your purpose.π
from async-graphql.
Add the property flatten
to #[field]
, flatten the contents of this field into the container it is defined in. How about this?
trait InfoObject {
async fn uptime(&self);
async fn name(&self) -> String;
}
struct GQLInfoObject(Box<dyn InfoObject>);
#[Object]
impl GQLInfoObject {
#[field]
async fn uptime(&self) -> String {
self.0.uptime()
}
#[field]
async fn name(&self) -> String {
self.0.name()
}
}
#[Object]
impl MyInfo {
#[field(flatten)] // <<<--------------------------------
async fn info(&self) -> GQLInfoObject {
GQLInfoObject(self.get_info_object())
}
#[field]
async fn additional_field(&self) -> &str {
"This will also be available"
}
}
pub struct QueryRoot;
impl QueryRoot {
async fn info(&self) -> MyInfo {
unimplemented!()
}
}
query {
info {
uptime
name
additionalField
}
}
from async-graphql.
I think this could work. What happens on nested fields? I guess flatten reduces by one level?
from async-graphql.
Right, the behavior is the same as in the serde.
from async-graphql.
Would something like this also work?
trait InfoObject {
async fn uptime(&self);
async fn name(&self) -> String;
}
#[Interface(
field(name="name", type="String"),
field(name="uptime", type="String"),
)]
struct GQLInfoObject(Box<dyn InfoObject>);
from async-graphql.
I think being able to do something like in your example would be awesome. What about SimpleObject? Would it work there as well?
#[SimpleObject]
struct MyObj {
#[field(flatten)]
pub info: Box<dyn InfoObject>
}
from async-graphql.
Yes, it can also do. π
But the trait object should be wrapped around a GraphQL Object.
#[SimpleObject]
struct MyObj {
#[field(flatten)]
pub info: MyObject(Box<dyn InfoObject>),
}
from async-graphql.
Got it!
from async-graphql.
I am adding it now.π
from async-graphql.
Flatten doesn't work. There are some other problems. I'll think of another way.
from async-graphql.
Why don't you try macros? I didn't find a good solution.π
from async-graphql.
Donβt worry Iβll find a solution to my problem. I just thought it would be something nice to have.
from async-graphql.
Well, procedural macros have some limitations, and many ideas are impossible to implement.π
from async-graphql.
What about having a compose attribute on Object where you pass in the name and getter of the fields you want to resolve where the getter is defined on an implemented trait.
from async-graphql.
Something like Interface
, right?
from async-graphql.
trait MyTrait {
fn test(&self) -> &str {
"it works"
}
}
#[Object(
compose(
field(name="test", getter="test"),
),
)]
struct MyStruct;
Yes a little bit like Interface.
from async-graphql.
Like this:
trait Info {
async fn name(&self) -> String;
}
#[Object(
field(name = "name", type = "String")
)]
impl Query {
}
{
name
}
from async-graphql.
That's a good idea, and it can be implemented! I'll do it right now.π
from async-graphql.
What happens when two implemented traits have the same method. I would need to specify a fully qualified path to the method which is not a nice field name. π Maybe we should have a "method" attribute and an optional "rename" attribute
from async-graphql.
trait InfoA {
async fn name(&self) -> String;
async fn uptime(&self) -> i32;
}
trait InfoB {
async fn name(&self) -> String;
}
#[Object(
field(method = "InfoA::name", type = "String", rename = "name_a"),
field(method = "InfoB::name", type = "String", rename = "name_b"),
field(method = "uptime", type = "i32")
)]
impl Query {
}
{
nameA
nameB
uptime
}
from async-graphql.
And maybe as a next step we can have an optional "getter" attribute. This would enable us to use traits already defined or from other crates:
trait Info {
async fn info(&self) -> SomeType; // SomeType implements ToString
}
#[Object(
field(method = "info", type = "String", getter = "std::string::ToString")
)]
impl Query {
}
from async-graphql.
I suddenly feel like this thing doesn't make any sense.π
trait Info {
async fn name(&self) -> String;
}
impl Query {
#[field]
async fn name(&self) -> String {
<Self as Info>::name()
}
}
It's just one line of code, and it's only written once.
from async-graphql.
Well maybe your are right and we are chasing our tail π. What we really want is this:
#[Object]
trait Info {
#[field]
async fn name(&self) -> &str {
"it works"
}
}
struct MyInfo;
impl Info for MyInfo{}
impl Query {
fn info(&self) -> MyInfo {
MyInfo
}
}
{
info {
name
}
}
from async-graphql.
There's no way to do that.π
from async-graphql.
I know. π. So to summarise: All solutions are either impossible to implement or trivial. The best idea is a "flatten" attribute which is also not possible as of now but maybe in the future. So I close this issue and open a new one as a feature request for "flatten".
from async-graphql.
Related Issues (20)
- Get mutable referenece to the global data defined in the `Context` or `Schema` HOT 1
- Confusing `unused_mut` warning in `#[Object]` HOT 8
- How to handle both directions of one-to-many relation in federated graph
- Question: How to get server to send ping messages on subscriptions? HOT 2
- Parsing multiple operations in a file HOT 1
- Non nullable variables should allow default values HOT 3
- Object with single skipped field but with ComplexObject HOT 2
- As using proxy type
- Using flatten inside an impl with no other fields causes a compile error
- Subscription with MPSC receiver in context data
- Reduce clippy noise from #[Object] macro HOT 2
- Guard trait lifetime HOT 1
- Using generics with both SimpleObject and InputObject as field in output type fails HOT 1
- Subscription Authentication
- Stack overflow after upgrade to 7.0.2 HOT 9
- Does async-graphql validate responses?
- Error reading data from ExtensionContext after upgrade to 7.0.3 HOT 1
- Create a general error formateer
- Allow flatten on arguments HOT 1
- External fields not getting generated in SDL
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from async-graphql.