Skip to content

Commit

Permalink
wip: feat: allow scalar kinds to have base type
Browse files Browse the repository at this point in the history
[no ci]

Signed-off-by: Justin Chadwell <[email protected]>
  • Loading branch information
jedevc committed Apr 23, 2024
1 parent 0e76110 commit c6a99ae
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 77 deletions.
13 changes: 6 additions & 7 deletions cmd/codegen/generator/go/templates/module_types.go
Expand Up @@ -140,16 +140,15 @@ func (spec *parsedPrimitiveType) TypeDefCode() (*Statement, error) {
default:
return nil, fmt.Errorf("unsupported basic type: %+v", spec.goType)
}
def := Qual("dag", "TypeDef").Call().Dot("WithKind").Call(
kind,
)
var def *Statement
if spec.alias == "" {
def = Qual("dag", "TypeDef").Call().Dot("WithKind").Call(kind)
} else {
def = Qual("dag", "TypeDef").Call().Dot("WithScalar").Call(kind, Lit(spec.alias))
}
if spec.isPtr {
def = def.Dot("WithOptional").Call(Lit(true))
}
if spec.alias != "" {
// XXX: should replace WithKind
def = def.Dot("WithScalar").Call(Lit(spec.alias))
}
return def, nil
}

Expand Down
36 changes: 30 additions & 6 deletions cmd/dagger/flags.go
Expand Up @@ -616,15 +616,27 @@ func (r *modFunctionArg) AddFlag(flags *pflag.FlagSet, dag *dagger.Client) (any,
return flags.Bool(name, val, usage), nil

case dagger.ScalarKind:
scalarName := r.TypeDef.AsScalar.Name
scalar := r.TypeDef.AsScalar
scalarName := scalar.Name

if val := GetCustomFlagValue(scalarName); val != nil {
flags.Var(val, name, usage)
return val, nil
}

val, _ := getDefaultValue[string](r)
return flags.String(name, val, usage), nil
switch scalar.Kind {
case dagger.StringKind:
val, _ := getDefaultValue[string](r)
return flags.String(name, val, usage), nil
case dagger.IntegerKind:
val, _ := getDefaultValue[int](r)
return flags.Int(name, val, usage), nil
case dagger.BooleanKind:
val, _ := getDefaultValue[bool](r)
return flags.Bool(name, val, usage), nil
}

return nil, fmt.Errorf("unsupported scalar kind %q for flag: %s", scalar.Kind, name)

case dagger.ObjectKind:
objName := r.TypeDef.AsObject.Name
Expand Down Expand Up @@ -665,15 +677,27 @@ func (r *modFunctionArg) AddFlag(flags *pflag.FlagSet, dag *dagger.Client) (any,
return flags.BoolSlice(name, val, usage), nil

case dagger.ScalarKind:
scalarName := r.TypeDef.AsScalar.Name
scalar := r.TypeDef.AsScalar
scalarName := scalar.Name

if val := GetCustomFlagValueSlice(scalarName); val != nil {
flags.Var(val, name, usage)
return val, nil
}

val, _ := getDefaultValue[[]string](r)
return flags.StringSlice(name, val, usage), nil
switch scalar.Kind {
case dagger.StringKind:
val, _ := getDefaultValue[[]string](r)
return flags.StringSlice(name, val, usage), nil
case dagger.IntegerKind:
val, _ := getDefaultValue[[]int](r)
return flags.IntSlice(name, val, usage), nil
case dagger.BooleanKind:
val, _ := getDefaultValue[[]bool](r)
return flags.BoolSlice(name, val, usage), nil
}

return nil, fmt.Errorf("unsupported scalar kind %q for flag: %s", scalar.Kind, name)

case dagger.ObjectKind:
objName := elementType.AsObject.Name
Expand Down
3 changes: 3 additions & 0 deletions cmd/dagger/module.go
Expand Up @@ -768,6 +768,7 @@ fragment TypeDefRefParts on TypeDef {
}
asScalar {
name
kind
}
}
Expand Down Expand Up @@ -814,6 +815,7 @@ query TypeDefs {
}
asScalar {
name
kind
}
asInterface {
name
Expand Down Expand Up @@ -1101,6 +1103,7 @@ func (o *modInterface) GetFunction(name string) (*modFunction, error) {

type modScalar struct {
Name string
Kind dagger.TypeDefKind
}

type modInput struct {
Expand Down
16 changes: 12 additions & 4 deletions core/module.go
Expand Up @@ -229,10 +229,18 @@ func (mod *Module) Install(ctx context.Context, dag *dagql.Server) error {

slog.ExtraDebug("installing scalar", "name", mod.Name(), "scalar", scalarDef.Name)

s := dagql.NewScalar(scalarDef.Name, scalarDef.Description)
dag.InstallScalar(s)

return nil
var sc dagql.ScalarType
switch scalarDef.Kind {
case TypeDefKindString:
sc = dagql.NewScalar[dagql.String](scalarDef.Name, dagql.String(""))
case TypeDefKindInteger:
sc = dagql.NewScalar[dagql.Int](scalarDef.Name, dagql.Int(0))
case TypeDefKindBoolean:
sc = dagql.NewScalar[dagql.Boolean](scalarDef.Name, dagql.Boolean(false))
default:
return fmt.Errorf("unsupported type kind: %s", scalarDef.Kind)
}
dag.InstallScalar(sc)
}

return nil
Expand Down
3 changes: 2 additions & 1 deletion core/schema/coremod.go
Expand Up @@ -298,8 +298,9 @@ func introspectionRefToTypeDef(introspectionType *introspection.TypeRef, nonNull
case string(introspection.ScalarBoolean):
typeDef.Kind = core.TypeDefKindBoolean
default:
// assume that all core scalars are strings
typeDef.Kind = core.TypeDefKindScalar
typeDef.AsScalar = dagql.NonNull(core.NewScalarTypeDef(introspectionType.Name, ""))
typeDef.AsScalar = dagql.NonNull(core.NewScalarTypeDef(core.TypeDefKindString, introspectionType.Name, ""))
}

return typeDef, true, nil
Expand Down
3 changes: 2 additions & 1 deletion core/schema/module.go
Expand Up @@ -317,13 +317,14 @@ func (s *moduleSchema) typeDefWithKind(ctx context.Context, def *core.TypeDef, a
}

func (s *moduleSchema) typeDefWithScalar(ctx context.Context, def *core.TypeDef, args struct {
Kind core.TypeDefKind
Name string
Description string `default:""`
}) (*core.TypeDef, error) {
if args.Name == "" {
return nil, fmt.Errorf("scalar type def must have a name")
}
return def.WithScalar(args.Name, args.Description), nil
return def.WithScalar(args.Kind, args.Name, args.Description), nil
}

func (s *moduleSchema) typeDefWithListOf(ctx context.Context, def *core.TypeDef, args struct {
Expand Down
38 changes: 28 additions & 10 deletions core/typedef.go
Expand Up @@ -332,8 +332,16 @@ func (typeDef *TypeDef) ToTyped() dagql.Typed {
case "Platform":
typed = Platform{}
default:
// typed = dagql.String("")
typed = dagql.NewScalar(typeDef.AsScalar.Value.Name, "")
switch typeDef.AsScalar.Value.Kind {
case TypeDefKindString:
typed = dagql.NewScalar[dagql.String](typeDef.AsScalar.Value.Name, dagql.String(""))
case TypeDefKindInteger:
typed = dagql.NewScalar[dagql.Int](typeDef.AsScalar.Value.Name, dagql.Int(0))
case TypeDefKindBoolean:
typed = dagql.NewScalar[dagql.Boolean](typeDef.AsScalar.Value.Name, dagql.Boolean(false))
default:
panic(fmt.Sprintf("unknown scalar type kind: %s", typeDef.AsScalar.Value.Kind))
}
}
case TypeDefKindList:
typed = dagql.DynamicArrayOutput{Elem: typeDef.AsList.Value.ElementTypeDef.ToTyped()}
Expand Down Expand Up @@ -368,8 +376,16 @@ func (typeDef *TypeDef) ToInput() dagql.Input {
case "Platform":
typed = Platform{}
default:
// typed = dagql.String("")
typed = dagql.NewScalar(typeDef.AsScalar.Value.Name, "")
switch typeDef.AsScalar.Value.Kind {
case TypeDefKindString:
typed = dagql.NewScalar[dagql.String](typeDef.AsScalar.Value.Name, dagql.String(""))
case TypeDefKindInteger:
typed = dagql.NewScalar[dagql.Int](typeDef.AsScalar.Value.Name, dagql.Int(0))
case TypeDefKindBoolean:
typed = dagql.NewScalar[dagql.Boolean](typeDef.AsScalar.Value.Name, dagql.Boolean(false))
default:
panic(fmt.Sprintf("unknown scalar type kind: %s", typeDef.AsScalar.Value.Kind))
}
}
case TypeDefKindList:
typed = dagql.DynamicArrayInput{
Expand Down Expand Up @@ -409,9 +425,9 @@ func (typeDef *TypeDef) WithKind(kind TypeDefKind) *TypeDef {
return typeDef
}

func (typeDef *TypeDef) WithScalar(name string, desc string) *TypeDef {
func (typeDef *TypeDef) WithScalar(kind TypeDefKind, name string, desc string) *TypeDef {
typeDef = typeDef.WithKind(TypeDefKindScalar)
typeDef.AsScalar = dagql.NonNull(NewScalarTypeDef(name, desc))
typeDef.AsScalar = dagql.NonNull(NewScalarTypeDef(kind, name, desc))
return typeDef
}

Expand Down Expand Up @@ -749,19 +765,21 @@ func (iface *InterfaceTypeDef) IsSubtypeOf(otherIface *InterfaceTypeDef) bool {
}

type ScalarTypeDef struct {
Name string `field:"true" doc:"XXX"`
Description string `field:"true" doc:"A doc string for the argument, if any."`
Name string `field:"true" doc:"XXX"`
Kind TypeDefKind `field:"true" doc:"The kind of type this is (e.g. primitive, list, object)."`
Description string `field:"true" doc:"A doc string for the argument, if any."`

OriginalName string

// SourceModuleName is currently only set when returning the TypeDef from the Scalars field on Module
SourceModuleName string `field:"true" doc:"If this ScalarTypeDef is associated with a Module, the name of the module. Unset otherwise."`
}

func NewScalarTypeDef(name, description string) *ScalarTypeDef {
func NewScalarTypeDef(kind TypeDefKind, name, description string) *ScalarTypeDef {
return &ScalarTypeDef{
Name: strcase.ToCamel(name),
OriginalName: name,
Kind: kind,
Description: description,
}
}
Expand Down Expand Up @@ -877,7 +895,7 @@ var (
`A graphql input type, used only when representing the core API via TypeDefs.`,
)
TypeDefKindScalar = TypeDefKinds.Register("SCALAR_KIND",
"A scalar value.") // XXX: more docs
"A scalar type.") // XXX: more docs
TypeDefKindVoid = TypeDefKinds.Register("VOID_KIND",
"A special kind used to signify that no value is returned.",
`This is used for functions that have no return value. The outer TypeDef
Expand Down
79 changes: 31 additions & 48 deletions dagql/types.go
Expand Up @@ -471,87 +471,70 @@ func (s String) SetField(v reflect.Value) error {
}
}

type ScalarValue interface {
ScalarType
Input
}

// Scalar is a GraphQL scalar.
type Scalar struct {
Name string
// XXX: could be a generic? like enum
Value string
type Scalar[T ScalarValue] struct {
Name string
Value T
}

func NewScalar(name, val string) Scalar {
return Scalar{name, val}
func NewScalar[T ScalarValue](name string, val T) Scalar[T] {
return Scalar[T]{name, val}
}

var _ Typed = Scalar{}
var _ Typed = Scalar[ScalarValue]{}

func (s Scalar) Type() *ast.Type {
func (s Scalar[T]) Type() *ast.Type {
return &ast.Type{
NamedType: s.Name,
NonNull: true,
}
}

var _ ScalarType = Scalar{}
var _ ScalarValue = Scalar[ScalarValue]{}

func (s Scalar) TypeName() string {
func (s Scalar[T]) TypeName() string {
return s.Name
}

func (s Scalar) TypeDefinition() *ast.Definition {
func (s Scalar[T]) TypeDefinition() *ast.Definition {
return &ast.Definition{
Kind: ast.Scalar,
Name: s.TypeName(),
Description: "",
Description: "", // XXX: description?
// BuiltIn: true,
}
}

func (s Scalar) DecodeInput(val any) (Input, error) {
switch x := val.(type) {
case string:
return NewScalar(s.Name, x), nil
default:
return nil, fmt.Errorf("cannot create Scalar from %T", x)
func (s Scalar[T]) DecodeInput(val any) (Input, error) {
var empty T
input, err := empty.DecodeInput(val)
if err != nil {
return nil, err
}
return NewScalar[T](s.Name, input.(T)), nil
}

var _ Input = Scalar{}
var _ Input = Scalar[ScalarValue]{}

func (Scalar) Decoder() InputDecoder {
return String("")
func (s Scalar[T]) Decoder() InputDecoder {
return s
}

func (s Scalar) ToLiteral() call.Literal {
return call.NewLiteralString(string(s.Name))
func (s Scalar[T]) ToLiteral() call.Literal {
return s.Value.ToLiteral()
}

func (s Scalar) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Name)
func (s Scalar[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Value)
}

// func (s *Scalar) UnmarshalJSON(p []byte) error {
// var str string
// if err := json.Unmarshal(p, &str); err != nil {
// return err
// }
// *s = String(str)
// return nil
// }

func (s Scalar) String() string {
return string(s.Value)
}

var _ Setter = Scalar{}

func (s Scalar) SetField(v reflect.Value) error {
switch v.Interface().(type) {
case string:
v.SetString(s.String())
return nil
default:
return fmt.Errorf("cannot set field of type %T with %T", v.Interface(), s)
}
func (s *Scalar[T]) UnmarshalJSON(p []byte) error {
return json.Unmarshal(p, &s.Value)
}

// ID is a type-checked ID scalar.
Expand Down

0 comments on commit c6a99ae

Please sign in to comment.