Coder Social home page Coder Social logo

Comments (32)

sunli829 avatar sunli829 commented on April 28, 2024 1

Let me think about how do I implement this.πŸ˜†

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024 1

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.

sunli829 avatar sunli829 commented on April 28, 2024

Can you give me an example?πŸ˜„

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

Maybe you could even do something like:

impl QueryRoot {
    async fn info(&self) -> Box<dyn Info> {
        MyInfo::{}
    } 
}

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

I think returning trait objects will not work because of introspection queries though.

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

sunli829 avatar sunli829 commented on April 28, 2024

I fully understand your purpose.😁

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

I think this could work. What happens on nested fields? I guess flatten reduces by one level?

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

Right, the behavior is the same as in the serde.

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

sunli829 avatar sunli829 commented on April 28, 2024

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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

Got it!

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

I am adding it now.😁

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

Flatten doesn't work. There are some other problems. I'll think of another way.☹️

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

Why don't you try macros? I didn't find a good solution.πŸ˜•

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

Don’t worry I’ll find a solution to my problem. I just thought it would be something nice to have.

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

Well, procedural macros have some limitations, and many ideas are impossible to implement.😠

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

sunli829 avatar sunli829 commented on April 28, 2024

Something like Interface, right?

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024
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.

sunli829 avatar sunli829 commented on April 28, 2024

Like this:

trait Info {
   async fn name(&self) -> String;
}

#[Object(
    field(name = "name", type = "String")
)]
impl Query {
}
{
    name
}

from async-graphql.

sunli829 avatar sunli829 commented on April 28, 2024

That's a good idea, and it can be implemented! I'll do it right now.😁

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024
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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

sunli829 avatar sunli829 commented on April 28, 2024

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.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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.

sunli829 avatar sunli829 commented on April 28, 2024

There's no way to do that.πŸ˜‚

from async-graphql.

nicolaiunrein avatar nicolaiunrein commented on April 28, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.