Skip to content

Commit

Permalink
generate interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
vektah committed Feb 28, 2018
1 parent e47d503 commit acc45bf
Show file tree
Hide file tree
Showing 15 changed files with 132 additions and 71 deletions.
2 changes: 1 addition & 1 deletion codegen/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Build struct {
type ModelBuild struct {
PackageName string
Imports Imports
Models Objects
Models []Model
}

// Create a list of models that need to be generated
Expand Down
2 changes: 1 addition & 1 deletion codegen/input_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func buildInputs(namedTypes NamedTypes, s *schema.Schema, prog *loader.Program,
}

func buildInput(types NamedTypes, typ *schema.InputObject) *Object {
obj := &Object{NamedType: types[typ.TypeName()], Input: true}
obj := &Object{NamedType: types[typ.TypeName()]}

for _, field := range typ.Values {
obj.Fields = append(obj.Fields, Field{
Expand Down
48 changes: 30 additions & 18 deletions codegen/interface_build.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package codegen

import (
"fmt"
"sort"
"strings"

Expand All @@ -11,24 +12,10 @@ func buildInterfaces(types NamedTypes, s *schema.Schema) []*Interface {
var interfaces []*Interface
for _, typ := range s.Types {
switch typ := typ.(type) {

case *schema.Union:
i := &Interface{NamedType: types[typ.TypeName()]}

for _, implementor := range typ.PossibleTypes {
i.Implementors = append(i.Implementors, types[implementor.TypeName()])
}

interfaces = append(interfaces, i)

case *schema.Interface:
i := &Interface{NamedType: types[typ.TypeName()]}

for _, implementor := range typ.PossibleTypes {
i.Implementors = append(i.Implementors, types[implementor.TypeName()])
}

interfaces = append(interfaces, i)
case *schema.Union, *schema.Interface:
interfaces = append(interfaces, buildInterface(types, typ))
default:
continue
}
}

Expand All @@ -38,3 +25,28 @@ func buildInterfaces(types NamedTypes, s *schema.Schema) []*Interface {

return interfaces
}

func buildInterface(types NamedTypes, typ schema.NamedType) *Interface {
switch typ := typ.(type) {

case *schema.Union:
i := &Interface{NamedType: types[typ.TypeName()]}

for _, implementor := range typ.PossibleTypes {
i.Implementors = append(i.Implementors, types[implementor.TypeName()])
}

return i

case *schema.Interface:
i := &Interface{NamedType: types[typ.TypeName()]}

for _, implementor := range typ.PossibleTypes {
i.Implementors = append(i.Implementors, types[implementor.TypeName()])
}

return i
default:
panic(fmt.Errorf("unknown interface %#v", typ))
}
}
15 changes: 15 additions & 0 deletions codegen/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package codegen

type Model struct {
*NamedType

Fields []ModelField
}

type ModelField struct {
*Type

GoVarName string
GoFKName string
GoFKType string
}
79 changes: 55 additions & 24 deletions codegen/models_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,34 @@ import (
"github.com/vektah/gqlgen/neelance/schema"
)

func buildModels(types NamedTypes, s *schema.Schema) Objects {
var models Objects
func buildModels(types NamedTypes, s *schema.Schema) []Model {
var models []Model

for _, typ := range s.Types {
var model *Object
var model Model
switch typ := typ.(type) {
case *schema.Object:
model = buildObject(types, typ, s)

obj := buildObject(types, typ, s)
if obj.Root || obj.GoType != "" {
continue
}
model = obj2Model(obj)
case *schema.InputObject:
model = buildInput(types, typ)
}

if model == nil || model.Root || model.GoType != "" {
obj := buildInput(types, typ)
if obj.GoType != "" {
continue
}
model = obj2Model(obj)
case *schema.Interface, *schema.Union:
intf := buildInterface(types, typ)
if intf.GoType != "" {
continue
}
model = int2Model(intf)
default:
continue
}

bindGenerated(types, model)

models = append(models, model)
}

Expand All @@ -36,23 +45,45 @@ func buildModels(types NamedTypes, s *schema.Schema) Objects {
return models
}

func bindGenerated(types NamedTypes, object *Object) {
object.GoType = ucFirst(object.GQLType)
object.Marshaler = &Ref{GoType: object.GoType}
func obj2Model(obj *Object) Model {
model := Model{
NamedType: obj.NamedType,
Fields: []ModelField{},
}

model.GoType = ucFirst(obj.GQLType)
model.Marshaler = &Ref{GoType: obj.GoType}

for i := range object.Fields {
field := &object.Fields[i]
for i := range obj.Fields {
field := &obj.Fields[i]
mf := ModelField{Type: field.Type}

if field.IsScalar {
field.GoVarName = ucFirst(field.GQLName)
if field.GoVarName == "Id" {
field.GoVarName = "ID"
if mf.IsScalar {
mf.GoVarName = ucFirst(field.GQLName)
if mf.GoVarName == "Id" {
mf.GoVarName = "ID"
}
} else if object.Input {
field.GoVarName = ucFirst(field.GQLName)
} else if mf.IsInput {
mf.GoVarName = ucFirst(field.GQLName)
} else {
field.GoFKName = ucFirst(field.GQLName) + "ID"
field.GoFKType = "int" // todo: use schema to determine type of id?
mf.GoFKName = ucFirst(field.GQLName) + "ID"
mf.GoFKType = "int" // todo: use schema to determine type of id?
}

model.Fields = append(model.Fields, mf)
}

return model
}

func int2Model(obj *Interface) Model {
model := Model{
NamedType: obj.NamedType,
Fields: []ModelField{},
}

model.GoType = ucFirst(obj.GQLType)
model.Marshaler = &Ref{GoType: obj.GoType}

return model
}
3 changes: 0 additions & 3 deletions codegen/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ type Object struct {
Root bool
DisableConcurrency bool
Stream bool
Input bool
}

type Field struct {
Expand All @@ -26,8 +25,6 @@ type Field struct {
GQLName string // The name of the field in graphql
GoMethodName string // The name of the method in go, if any
GoVarName string // The name of the var in go, if any
GoFKName string // The name of the FK used when generating models
GoFKType string // The type of the FK used when generating models
Args []FieldArgument // A list of arguments to be passed to this field
NoErr bool // If this is bound to a go method, does that method have an error as the second argument
Object *Object // A link back to the parent object
Expand Down
2 changes: 1 addition & 1 deletion codegen/templates/data.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 12 additions & 8 deletions codegen/templates/models.gotpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import (
)

{{ range $model := .Models }}
type {{.GoType}} struct {
{{- range $field := .Fields }}
{{- if $field.GoVarName }}
{{ $field.GoVarName }} {{$field.Signature}}
{{- else }}
{{ $field.GoFKName }} {{$field.GoFKType}}
{{- if .IsInterface }}
type {{.GoType}} interface {}
{{- else }}
type {{.GoType}} struct {
{{- range $field := .Fields }}
{{- if $field.GoVarName }}
{{ $field.GoVarName }} {{$field.Signature}}
{{- else }}
{{ $field.GoFKName }} {{$field.GoFKType}}
{{- end }}
{{- end }}
{{- end }}
}
}
{{- end }}
{{- end}}
1 change: 1 addition & 0 deletions codegen/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type NamedType struct {
Ref
IsScalar bool
IsInterface bool
IsInput bool
GQLType string // Name of the graphql type
Marshaler *Ref // If this type has an external marshaler this will be set
}
Expand Down
2 changes: 2 additions & 0 deletions codegen/type_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ func namedTypeFromSchema(schemaType schema.NamedType) *NamedType {
return &NamedType{GQLType: val.TypeName(), IsScalar: true}
case *schema.Interface, *schema.Union:
return &NamedType{GQLType: val.TypeName(), IsInterface: true}
case *schema.InputObject:
return &NamedType{GQLType: val.TypeName(), IsInput: true}
default:
return &NamedType{GQLType: val.TypeName()}
}
Expand Down
Loading

0 comments on commit acc45bf

Please sign in to comment.