Skip to content

Commit

Permalink
Add structs
Browse files Browse the repository at this point in the history
Structs are a new feature in firemodel that provide type-safety around
Map aka Object aka Dictionary types.

Resolves #23 and #25
  • Loading branch information
Mickey Reiss committed Oct 2, 2018
1 parent 64254b7 commit a9f5d09
Show file tree
Hide file tree
Showing 17 changed files with 399 additions and 101 deletions.
13 changes: 10 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
type Schema struct {
Models []*SchemaModel
Enums []*SchemaEnum
Structs []*SchemaStruct
Options SchemaOptions
}

Expand All @@ -26,6 +27,12 @@ type SchemaModel struct {
Options SchemaModelOptions
}

type SchemaStruct struct {
Name string
Comment string
Fields []*SchemaField
}

type SchemaOptions map[string]map[string]string

func (options SchemaOptions) Get(key string) map[string]string {
Expand Down Expand Up @@ -125,7 +132,7 @@ type Bytes struct{}
type Reference struct{ T *SchemaModel }
type Array struct{ T SchemaFieldType }
type Map struct{ T SchemaFieldType }
type Model struct{ T *SchemaModel }
type Struct struct{ T *SchemaStruct }
type Enum struct{ T *SchemaEnum }
type URL struct{}
type File struct{}
Expand All @@ -140,13 +147,13 @@ func (t *Bytes) isSchemaTypeName() {}
func (t *Reference) isSchemaTypeName() {}
func (t *Array) isSchemaTypeName() {}
func (t *Map) isSchemaTypeName() {}
func (t *Model) isSchemaTypeName() {}
func (t *Struct) isSchemaTypeName() {}
func (t *Enum) isSchemaTypeName() {}
func (t *URL) isSchemaTypeName() {}
func (t *File) isSchemaTypeName() {}

type SchemaNestedCollection struct {
Name string
Comment string
Type *Model
Type *SchemaModel
}
9 changes: 7 additions & 2 deletions firemodel.example.firemodel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ enum TestDirection {
down,
}

struct TestStruct {
string where;
integer how_much;
}

// A Test is a test model.
model TestModel {
option firestore.path = "users/{user_id}/test_models/{test_model_id}";
Expand All @@ -27,15 +32,15 @@ model TestModel {
geopoint location;
array<string> colors;
array<TestDirection> directions;
array<TestModel> models;
array<TestStruct> models;
array<reference> refs;
array<reference<TestTimestamps>> model_refs;
map meta;
map<string> meta_strs;
TestDirection direction;
File test_file;
URL url;
TestModel nested;
TestStruct nested;
collection<TestModel> nested_collection;
}

Expand Down
10 changes: 10 additions & 0 deletions internal/ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,19 @@ type ASTElement struct {
Model *ASTModel `parser:" 'model' @@"`
Enum *ASTEnum `parser:"| 'enum' @@"`
Option *ASTOption `parser:"| 'option' @@"`
Struct *ASTStruct `parser:"| 'struct' @@"`
}

type ASTModel struct {
Identifier ASTIdentifier `parser:"@Ident"`
Elements []*ASTModelElement `parser:"'{' { @@ } '}'"`
}

type ASTStruct struct {
Identifier ASTIdentifier `parser:"@Ident"`
Elements []*ASTStructElement `parser:"'{' { @@ } '}'"`
}

type ASTIdentifier string

var (
Expand Down Expand Up @@ -100,6 +106,10 @@ func (id ASTIdentifier) IsReserved() bool {
return true
}

type ASTStructElement struct {
Field *ASTField `parser:"@@"`
}

type ASTModelElement struct {
Option *ASTOption `parser:" 'option' @@"`
Field *ASTField `parser:"| @@"`
Expand Down
46 changes: 39 additions & 7 deletions langs/go/go.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ func (m *GoModeler) Model(schema *firemodel.Schema, sourceCoder firemodel.Source
return err
}
}
for _, structType := range schema.Structs {
if err := m.writeStruct(structType, sourceCoder); err != nil {
return err
}
}
for _, enum := range schema.Enums {
if err := m.writeEnum(enum, sourceCoder); err != nil {
return err
Expand Down Expand Up @@ -60,7 +65,10 @@ func (m *GoModeler) writeModel(model *firemodel.SchemaModel, sourceCoder firemod
f.Commentf("Firestore document location: /%s", fmt.Sprintf(format, commentargs...))
}

f.Type().Id(model.Name).StructFunc(m.fields(model))
f.
Type().
Id(model.Name).
StructFunc(m.fields(model.Name, model.Fields, model.Options.GetAutoTimestamp()))

if format, args, err := model.Options.GetFirestorePath(); format != "" {
f.
Expand Down Expand Up @@ -142,18 +150,43 @@ func (m *GoModeler) writeEnum(enum *firemodel.SchemaEnum, sourceCoder firemodel.
return nil
}

func (m *GoModeler) writeStruct(structType *firemodel.SchemaStruct, sourceCoder firemodel.SourceCoder) error {
structName := strcase.ToCamel(structType.Name)
f := jen.NewFile(m.packageName())
f.HeaderComment(fmt.Sprintf("DO NOT EDIT - Code generated by firemodel %s.", version.Version))

if structType.Comment == "" {
f.Commentf("TODO: Add comment to %s", structType.Name)
} else {
f.Comment(structType.Comment)
}
f.Type().Id(structName).StructFunc(m.fields(structName, structType.Fields, false))

w, err := sourceCoder.NewFile(fmt.Sprint(strcase.ToSnake(structType.Name), fileExtension))
if err != nil {
return errors.Wrap(err, "firemodel/go: open source code file")
}

defer w.Close()

if err := f.Render(w); err != nil {
return err
}
return nil
}

func (m *GoModeler) packageName() string {
if m.pkg == "" {
return "firemodel"
}
return m.pkg
}

func (m *GoModeler) fields(model *firemodel.SchemaModel) func(g *jen.Group) {
func (m *GoModeler) fields(structName string, fields []*firemodel.SchemaField, addTimestampFields bool) func(g *jen.Group) {
return func(g *jen.Group) {
for _, field := range model.Fields {
for _, field := range fields {
if field.Comment == "" {
g.Commentf("TODO: Add comment to %s.%s.", model.Name, field.Name)
g.Commentf("TODO: Add comment to %s.%s.", structName, field.Name)
} else {
g.Comment(field.Comment)
}
Expand All @@ -162,8 +195,7 @@ func (m *GoModeler) fields(model *firemodel.SchemaModel) func(g *jen.Group) {
Do(m.goType(field.Type)).
Tag(map[string]string{"firestore": strcase.ToLowerCamel(field.Name)})
}

if model.Options.GetAutoTimestamp() {
if addTimestampFields {
g.Line()
g.Comment("Creation timestamp.")
g.
Expand Down Expand Up @@ -202,7 +234,7 @@ func (m *GoModeler) goType(firetype firemodel.SchemaFieldType) func(s *jen.State
return func(s *jen.Statement) { s.Op("*").Qual("cloud.google.com/go/firestore", "DocumentRef") }
case *firemodel.GeoPoint:
return func(s *jen.Statement) { s.Op("*").Qual("google.golang.org/genproto/googleapis/type/latlng", "LatLng") }
case *firemodel.Model:
case *firemodel.Struct:
return func(s *jen.Statement) { s.Op("*").Id(firetype.T.Name) }
case *firemodel.Array:
if firetype.T != nil {
Expand Down
Loading

0 comments on commit a9f5d09

Please sign in to comment.