#Confused about returning an array of a custom data type

1 messages · Page 1 of 1 (latest)

novel vigil
#

If I have the two modules mod1 and mod2, where mod2 uses mod1 (example source below). The mod1 module has a Results function which just returns a slice of a custom Result struct, which just contains data (a Name). The mod2 module calls this function and returns just the Names.

I understand that calling Result requires a context to generate the list of results, but once that is returned I'm finding I'm a little confused as to why

  1. Result.Name is function (not a field), and
  2. calling Result.Name requires itself a context

Does this mean that this requires executing a query for each result to obtain just the Names? I suppose my expectation was that once the slice is returned the fields would be also available immediately.

mod1/main.go

package main

type Mod1 struct{}

type Result struct {
    Name string
}

func (m *Mod1) Results() []Result {
    return []Result{
        {Name: "bob"},
        {Name: "foo"},
        {Name: "bar"},
    }
}

mod2/main.go

package main

import "context"

type Mod2 struct{}

func (m *Mod2) Names(ctx context.Context) ([]string, error) {
    results, err := dag.Mod1().Results(ctx)
    if err != nil {
        return nil, err
    }

    names := make([]string, len(results))
    for i, r := range results {
        name, err := r.Name(ctx) // Why does this need a context?
        if err != nil {
            return nil, err
        }
        names[i] = name
    }
    return names, nil
}
#

Confused about returning an array of a custom data type

dreamy fossil
# novel vigil If I have the two modules `mod1` and `mod2`, where `mod2` uses `mod1` (example s...

Yeah that's the way you should retrieve the data type.

It requires a context because the value is resolved by calling the object itself.
There's no such concept of field in dagger, everything is a function and what we usually name a field in GraphQL is simply a function that takes no parameter and return a single scalar.

If you have a more complex data type with multiple fields, what you can do to get all values in a single call is to write a custom GraphQLquery

{
  mod1 {
    results {
       name
    }
  }
}
func x(ctx context.Context) {
  type Result struct {
    Mod1 struct { Result struct { Name []string }}
  }

  var res Result

  err := dag.GraphqlClient().MakeRequest(ctx, &graphql.Request {
    Query: yourQuery // Can be pass with a go embedding or inlined
  }, &res)
  
  ...
}

This is not ideal since you do not benefit from the type completion but we do that in our codebase too for complex query.

Not that this will not impact performances, both solutions (either loop or gql query) are calling the same functions underneath.

novel vigil
#

Ah, that makes sense. So, it's not like the calling Result.Name for each element will require a round-trip. In this case, it's just that the field needs to be resolved from it's GraphQL representation?

dreamy fossil
#

Exactly

novel vigil
#

Thanks for clearing that up.

Just wanted to say, this help section has been invaluable. The quick responses which are provided and excellent detail. It's really made using Dagger a great experience. Thank you!

dreamy fossil