Code Monkey home page Code Monkey logo

Comments (7)

andreyvital avatar andreyvital commented on July 21, 2024

Hey @F21, I never tested it, but it could be done with the current graphql-js implementation? That would be such an interesting feature. A friend of mine ran into the same issue some weeks ago, we had to define the resolve in the parent even without needing all fields, for example:

{
  memory {
    virtual {
      total
      used
      available
    }
  }
}

In memory we have both virtual and swap, but we needed to resolve both virtual and swap data which leads to performance-related issues.

/cc @txgruppi

from graphql.

F21 avatar F21 commented on July 21, 2024

@CentaurWarchief I haven't really had a chance to play with the graphql-js version (only went through the relay tutorial). However, I think the javascript implementation also has this limitation: graphql/graphql-js#154

The current work around is to resolve in the virtual and swap object and set the resolver of memory to be empty:

Resolve: func(p graphql.ResolveParams) (interface{}, error) {
                    return struct{}{}, nil 
                }

from graphql.

txgruppi avatar txgruppi commented on July 21, 2024

Our solution was to create a type for memory and use it in the resolve function.

func NewMemoryData() *MemoryData {
    return &MemoryData{}
}

type MemoryData struct {
    Swap    *SwapData    `json:"swap"`
    Virtual *VirtualData `json:"virtual"`
}
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
    return NewMemoryData(), nil
},

from graphql.

sogko avatar sogko commented on July 21, 2024

This is kinda tricky, because the way the executor works is by evaluating the query top-down.
As part of its pruning process, it would only look at the child if the parent node has something to evaluate.

I think it would be useful if a field that does not have a resolver is allowed to go "deeper", so that the child resolvers can resolve.

Every field actually has a default resolver, which you override by specifying it in the schema you defined.

So if the resolver (regardless if it's default or user-specified) returns a nil value, the executor won't try to see if its child fields has a value.

It is possible to design the executor to try evaluate all child fields even when the parent field evaluates to nil, but that could possibly lead to evaluating every field in the schema for every query.

In addition to that, having the value of resources field to be nil but its own fields to have values are kinda counter-intuitive.
Consider:

type Car struct {
    Name string
    Year int
}
var car *Car
log.Println(car.Year) // <-- panic

@F21 solution of returning an empty anonymous struct at first glance seems hacky but is perfectly valid.
(It returns an empty but non-nil value), equivalent to:

var car Car
log.Println(car.Year) // 0

Can I suggest an alternate solution (which is practically the same as the one posted above), but probably more natural way of writing the schema.

type Memory struct {
    Total float64 `json:"total"`
    Used float64 `json:"used"`
}

type Resources struct {
    Memory *Memory `json:"memory"`
}

func (resources *Resources) GetMemory() *Memory {
    // resource-heavy operation to fetch stats
    return &Memory {
        Total: 1024,
        Used: 100,
    }
}

func main() {
    resourceType := graphql.NewObject(graphql.ObjectConfig{
        Name:        "Resource",
        Description: "Resource utilization information for a type.",
        Fields: graphql.Fields{
            "total": &graphql.Field{
                Type:        graphql.Float,
                Description: "The total available.",
            },
            "used": &graphql.Field{
                Type:        graphql.Float,
                Description: "The amount used.",
            },
        },
    })

    resourcesType := graphql.NewObject(graphql.ObjectConfig{
        Name:        "Resources",
        Description: "Resource utilization information.",
        Fields: graphql.Fields{
            "memory": &graphql.Field{
                Type:        resourceType,
                Description: "Memory utilization information.",
                Resolve: func(p graphql.ResolveParams) (interface{}, error) {
                    // `p.Source` is given by it's parent field `resources`
                    if resources, ok := p.Source.(*Resources); ok {
                        return resources.GetMemory(), nil
                    }
                    return nil, nil
                },
            },
        },
    })
    queryType := graphql.NewObject(graphql.ObjectConfig{
        Name: "Query",
        Fields: graphql.Fields{
            "resources": &graphql.Field{
                Type: resourcesType,
                Resolve: func(p graphql.ResolveParams) (interface{}, error) {
                    // pass `&Resource{}` down to it's child fields, available as `p.Source`
                    return &Resources{}, nil
                },
            },
        },
    })
    ...
}

from graphql.

F21 avatar F21 commented on July 21, 2024

@sogko Thanks for posting the sample code. That really helped!

I think your solution is exactly what I am looking for! 😄

from graphql.

bbuck avatar bbuck commented on July 21, 2024

@sogko Not sure if you meant to do something else but, this bit:

log.Printf(car.Year) 

Panics because car.Year is an int while log.Printfexpects a string. If you change to Println or give it a format string it prints 0 as should be expected. Again, you may have meant something else but I just wanted to point that out.

from graphql.

sogko avatar sogko commented on July 21, 2024

@bbuck hahaha yeah thanks for pointing that out, it should be log.Println(), I just meant to give an example of getting a value of a field from a nil struct, thanks! 👍🏻

from 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.