#Custom structure in Dagger function arguments?

1 messages · Page 1 of 1 (latest)

fierce swift
#

Hi, is it possible to pass structure as argument of Dagger functions?
An example:

package main

type MyModule struct{}

type Config struct {
    A string
    B string
}

func (m *MyModule) A(config *Config) string {
    return config.A
}

func (m *MyModule) B(config *Config) string {
    return config.B
}

The error I currently have is Error: unsupported object type "MyModuleConfig" for flag: config when calling one of the function.

indigo sky
#

Yes, but you must do chaining.

this is the relevant part of the docs that shows an example: https://docs.dagger.io/manuals/developer/go/580472/custom-types/ and https://docs.dagger.io/manuals/developer/go/528510/chaining

A Dagger Module can have multiple object types defined. It's important to understand that they are only accessible through chaining, starting from a function in the main object.

Dagger Functions can return custom objects, which in turn can define new functions. This allows for "chaining" of functions in the same style as the core Dagger API.

fierce swift
#

Ok I see. And can I define chaining functions to construct each structure in the file in a nested way?
For instance, does it work to define all fields of the following structures?:

type MyModule struct{}

type Config struct {
    A      string
    SubCfg []SubConfig
}

type SubConfig struct {
    B string
    C string
}
dapper quartz
#

I think we plan on supporting input types in the future, which would allow custom structs. @upbeat lodge, @foggy belfry or @echo dune can probably share more details there

indigo yoke
# fierce swift Ok I see. And can I define chaining functions to construct each structure in the...

👋 you can keep your original example but change the A and B functions to use chaining instead of setters. i.e:

package main

type Lala struct {
    Config *Config
}

type Config struct {
    A string
    B string
}

func New() *Lala {
    return &Lala{&Config{}}
}

func (m *Lala) WithA(a string) (*Lala, error) {
    m.Config.A = a
    return m, nil
}

func (m *Lala) WithB(config *Config) (*Lala, error) {
    m.Config.B = config.B
    return m, nil
}

and then you can call it like:
dagger call with-a --a foo config a

fierce swift
#

Ok I see with my first example.
In my second example (that is not related to the first one), I don't see with chaining how I can populate SubCfg elements of Config using chaining. Having methods like WithSubCfg or AddSubCfg would not work since their argument would be a SubConfig type.

dapper quartz
#

In my experience, anything highly structured like this, is most likely to come from parsing an existing config file. In which case you don't need to individuall pass the struct as an argument, you can just pass the (json-encoded, yaml-encoded, etc.) file

fierce swift
#

The idea was actually to not manage the encoding before but let the Dagger module validates the structure and generates the YAML file

dapper quartz
fierce swift
#

From what I understand, in the Markdown linter, it's the output that is a custom type ([]Check) with all the information. In my case, it's on the input side I'd like to pass a more complex structure.

indigo yoke
# fierce swift Ok I see with my first example. In my second example (that is not related to the...

You can still use chaining here also, the thing is that Dagger doesn't support sending custom types via arguments yet as we need to design what the CLI ux will be. But you can do something like:

type Lala struct {
    Config *Config
}

type Config struct {
    A         string
    B         string
    SubConfig *SubConfig
}
type SubConfig struct {
    C string
}

func New() *Lala {
    return &Lala{&Config{SubConfig: &SubConfig{}}}
}

func (m *Lala) WithA(a string) (*Lala, error) {
    m.Config.A = a
    return m, nil
}

func (m *Lala) WithSubConfigC(c string) (*Lala, error) {
    m.Config.SubConfig.C = c
    return m, nil
}
#

we're aware it's limiting not being able to send custom types, but that's definitely in our radar to support soon. IIRC there's an issue for that (searching)

fierce swift
indigo yoke
fierce swift
#

Ok I see that the question around this feature is not that simple and not yet implemented.
My idea was to avoid passing a json-encoded string to the module and pass a more complex structure to avoid some templating and/or uncontrolled JSON input to the module (to have a clear API of the configuration of the module).

dapper quartz
indigo yoke
dapper quartz
#

And @indigo yoke & @indigo sky did a good job at summarizing possible workarounds (which are very solid, well supported, not just hacks)

dapper quartz
indigo yoke
upbeat lodge
#

I think we've avoided supporting input types because it leads to duplication between input and output. What we've been doing is that types declared in a module are automatically added an ID, so outside the module it needs to be created via dag, and the SDK uses the ID internally. Inside the module, you can instantiate directly and dagger transparently translates to ID as well.