99designs / gqlgen

go generate based graphql server library
https://gqlgen.com
MIT License
9.98k stars 1.17k forks source link

exec plan failed: required package was not loaded #420

Closed LeonB closed 5 years ago

LeonB commented 6 years ago

I have a custom scalar:

models:
  Duration:
    model: bitbucket.org/tim_online/mews-graphql/scalars.Duration
package scalars

import (
    "errors"
    "io"
    "strconv"

    "github.com/99designs/gqlgen/graphql"
    "github.com/senseyeio/duration"
)

func MarshalDuration(d duration.Duration) graphql.Marshaler {
    return graphql.WriterFunc(func(w io.Writer) {
        io.WriteString(w, strconv.Quote(d.String()))
    })
}

func UnmarshalDuration(v interface{}) (duration.Duration, error) {
    if tmpStr, ok := v.(string); ok {
        return duration.ParseISO8601(tmpStr)
    }
    return duration.Duration{}, errors.New("duration should be a ISO8601 formatted string")
}

When running gqlgen I get this error: exec plan failed: required package was not loaded: github.com/senseyeio/duration.Duration

So it looks like it throws an error somewhere in Config.buildObjects(). Building the scalars package works:

go build ./scalars
mathewbyrne commented 6 years ago

It looks like you have 2 separate definitions for Duration?

    model: bitbucket.org/tim_online/mews-graphql/scalars.Duration

and

"github.com/senseyeio/duration"

Are they supposed to be the same implementation?

LeonB commented 6 years ago

@mathewbyrne mews-graphql/scalars.Duration is the marshalling wrapper for Duration:

func MarshalDuration(d duration.Duration) graphql.Marshaler {
    return graphql.WriterFunc(func(w io.Writer) {
        io.WriteString(w, strconv.Quote(d.String()))
    })
}

func UnmarshalDuration(v interface{}) (duration.Duration, error) {
    if tmpStr, ok := v.(string); ok {
        return duration.ParseISO8601(tmpStr)
    }
    return duration.Duration{}, errors.New("duration should be a ISO8601 formatted string")
}
LeonB commented 6 years ago

If I change the marshalling wrapper:

package scalars

import (
    "errors"
    "io"
    "strconv"

    "github.com/99designs/gqlgen/graphql"
    "github.com/senseyeio/duration"
)

func MarshalDuration(d duration.Duration) graphql.Marshaler {
    return graphql.WriterFunc(func(w io.Writer) {
        io.WriteString(w, strconv.Quote(d.String()))
    })
}

func UnmarshalDuration(v interface{}) (duration.Duration, error) {
    if tmpStr, ok := v.(string); ok {
        return duration.ParseISO8601(tmpStr)
    }
    return duration.Duration{}, errors.New("duration should be a ISO8601 formatted string")
}

to:

package scalars

import (
    "fmt"
    "io"

    dur "github.com/senseyeio/duration"
)

type Duration struct {
    dur.Duration
}

// UnmarshalGQL implements the graphql.Marshaler interface
func (d *Duration) UnmarshalGQL(v interface{}) error {
    input, ok := v.(string)
    if !ok {
        return fmt.Errorf("input must be a string")
    }

    d2, err := dur.ParseISO8601(input)
    if err == nil {
        *d = Duration{d2}
    }
    return err
}

// MarshalGQL implements the graphql.Marshaler interface
func (d Duration) MarshalGQL(w io.Writer) {
    w.Write([]byte(d.String()))
}

I get no errors.

LeonB commented 6 years ago

I've created a minimal testcase here: https://github.com/omniboost/gqlgen-test

$ gorunpkg github.com/99designs/gqlgen -v
exec plan failed: required package was not loaded: golang.org/x/text/language.Region
LeonB commented 6 years ago

This fixes it:

    progLoader := newLoader(namedTypes, true)
    progLoader.Import("golang.org/x/text/language")

So I believe what happens: if you're using the Marshalling wrapper methods the external struct (language.Region) is a top level type and gets added to the list of importchecks but it isn't loaded.

LeonB commented 6 years ago

Ah, I think this is the solution:

models:
  CountryCode:
    # model: bitbucket.org/tim_online/mews-graphql/scalars.CountryCode
    model: golang.org/x/text/language.Region
LeonB commented 5 years ago

Looks like it was my fault :(

When I changed type CountryCode to scalar CountryCode in my schema.graphql it worked.

rwrz commented 1 year ago

2800

in case anyone wants a duration implementation.