diff --git a/cmd/gogmcli/gen/gen.go b/cmd/gogmcli/gen/gen.go index 1af11f2..84ee955 100644 --- a/cmd/gogmcli/gen/gen.go +++ b/cmd/gogmcli/gen/gen.go @@ -26,6 +26,7 @@ import ( "fmt" dsl "github.com/mindstand/go-cypherdsl" "github.com/mindstand/gogm/cmd/gogmcli/util" + "go/format" "html/template" "log" "os" @@ -63,7 +64,7 @@ func Generate(directory string, debug bool) error { if debug { log.Printf("parsing go file [%s]\n", filePath) } - err := parseFile(filePath, &confs, &edges, imps, &packageName) + err := parseFile(filePath, &confs, &edges, imps, &packageName, debug) if err != nil { if debug { log.Printf("failed to parse go file [%s] with error '%s'\n", filePath, err.Error()) @@ -83,6 +84,10 @@ func Generate(directory string, debug bool) error { return err } + if debug { + log.Printf("found [%v] confs and [%v] rels", len(confs), len(edges)) + } + var imports []string for _, imp := range imps { @@ -97,13 +102,24 @@ func Generate(directory string, debug bool) error { relations := make(map[string][]*relConf) + if debug { + log.Println("sorting relationships") + } + // sort out relationships - for _, fields := range confs { + for node, fields := range confs { + if debug { + log.Printf("sorting relationships for node [%s] with [%v] fields", node, len(fields)) + } for _, field := range fields { if field == nil { return errors.New("field can not be nil") } + if debug { + log.Printf("adding relationship [%s] from field [%s]", field.RelationshipName, field.Field) + } + if _, ok := relations[field.RelationshipName]; ok { relations[field.RelationshipName] = append(relations[field.RelationshipName], field) } else { @@ -112,6 +128,10 @@ func Generate(directory string, debug bool) error { } } + if debug { + log.Printf("there are [%v] relations\n", len(relations)) + } + // validate relationships (i.e even number) for name, rel := range relations { if len(rel)%2 != 0 { @@ -140,7 +160,7 @@ func Generate(directory string, debug bool) error { isSpecialEdge = true } - err = parseDirection(rel, rels, tplRel, isSpecialEdge) + err = parseDirection(rel, &rels, tplRel, isSpecialEdge) if err != nil { return err } @@ -149,6 +169,10 @@ func Generate(directory string, debug bool) error { return fmt.Errorf("oposite side not found for node [%s]", rel.NodeName) } + if debug { + log.Printf("adding function to node [%s]", rel.NodeName) + } + if _, ok := funcs[rel.NodeName]; ok { funcs[rel.NodeName] = append(funcs[rel.NodeName], tplRel) } else { @@ -187,12 +211,20 @@ func Generate(directory string, debug bool) error { return err } + // format generated code + formatted, err := format.Source(buf.Bytes()) + if err != nil { + return err + } + + // create the file f, err := os.Create(path.Join(directory, "linking.go")) if err != nil { return err } - lenBytes, err := f.Write(buf.Bytes()) + // write code to the file + lenBytes, err := f.Write(formatted) if err != nil { return err } @@ -201,6 +233,7 @@ func Generate(directory string, debug bool) error { log.Printf("done after writing [%v] bytes!", lenBytes) } + // close the buffer err = f.Close() if err != nil { return err @@ -212,8 +245,8 @@ func Generate(directory string, debug bool) error { } // parseDirection parses gogm struct tags and writes to a holder struct -func parseDirection(rel *relConf, rels []*relConf, tplRel *tplRelConf, isSpecialEdge bool) error { - for _, lookup := range rels { +func parseDirection(rel *relConf, rels *[]*relConf, tplRel *tplRelConf, isSpecialEdge bool) error { + for _, lookup := range *rels { //check special edge if rel.Type != lookup.NodeName && !isSpecialEdge { continue diff --git a/cmd/gogmcli/gen/parse.go b/cmd/gogmcli/gen/parse.go index 3ab8e4b..5bfb24a 100644 --- a/cmd/gogmcli/gen/parse.go +++ b/cmd/gogmcli/gen/parse.go @@ -41,7 +41,7 @@ type relConf struct { } // parses each file using ast looking for nodes to handle -func parseFile(filePath string, confs *map[string][]*relConf, edges *[]string, imports map[string][]string, packageName *string) error { +func parseFile(filePath string, confs *map[string][]*relConf, edges *[]string, imports map[string][]string, packageName *string, debug bool) error { fset := token.NewFileSet() node, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments) if err != nil { @@ -52,6 +52,7 @@ func parseFile(filePath string, confs *map[string][]*relConf, edges *[]string, i *packageName = node.Name.Name if node.Scope.Objects != nil && len(node.Scope.Objects) != 0 { for label, config := range node.Scope.Objects { + log.Println("checking ", label) tSpec, ok := config.Decl.(*ast.TypeSpec) if !ok { continue @@ -78,6 +79,10 @@ func parseFile(filePath string, confs *map[string][]*relConf, edges *[]string, i return err } + if debug { + log.Printf("node [%s] is edge [%v]", label, isEdge) + } + // if its not an edge, parse it as a gogm struct if !isEdge { (*confs)[label] = []*relConf{} @@ -166,7 +171,7 @@ func parseGogmEdge(node *ast.File, label string) (bool, error) { } } //check if its an edge node - return !GetStartNode || !GetStartNodeType || !SetStartNode || !GetEndNode || !GetEndNodeType || !SetEndNode, nil + return GetStartNode && GetStartNodeType && SetStartNode && GetEndNode && GetEndNodeType && SetEndNode, nil } // parseGogmNode generates configuration for GoGM struct diff --git a/cmd/gogmcli/gen/templ.go b/cmd/gogmcli/gen/templ.go index dd158df..6a1610c 100644 --- a/cmd/gogmcli/gen/templ.go +++ b/cmd/gogmcli/gen/templ.go @@ -21,7 +21,8 @@ package gen //expect .StructName .OtherStructName .StructField .OtherStructField .StructFieldIsMany .OtherStructFieldIsMany var linkSpec = ` -{{ define "linkSpec" }} +{{ define "linkSpec" }}// LinkTo{{ .OtherStructName }}OnField{{.StructField}} links {{ .StructName }} to {{ .OtherStructName }} on the fields {{ .StructName }}.{{ .StructField }} and {{ .OtherStructName }}.{{ .OtherStructField }}. +// note this uses the special edge {{ .SpecialEdgeType }} func(l *{{ .StructName }}) LinkTo{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}, edge *{{.SpecialEdgeType}}) error { if target == nil { return errors.New("start and end can not be nil") @@ -71,7 +72,8 @@ func(l *{{ .StructName }}) LinkTo{{ .OtherStructName }}OnField{{.StructField}}(t ` var singleLink = ` -{{ define "linkSingle" }}func(l *{{ .StructName }}) LinkTo{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}) error { +{{ define "linkSingle" }}//LinkTo{{ .OtherStructName }}OnField{{.StructField}} links {{ .StructName }} to {{ .OtherStructName }} on the fields {{ .StructName }}.{{ .StructField }} and {{ .OtherStructName }}.{{ .OtherStructField }} +func(l *{{ .StructName }}) LinkTo{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}) error { if target == nil { return errors.New("start and end can not be nil") } @@ -97,7 +99,7 @@ var singleLink = ` ` var linkMany = ` -{{ define "linkMany" }} +{{ define "linkMany" }}// LinkTo{{ .OtherStructName }}OnField{{.StructField}} links {{ .StructName }} to {{ .OtherStructName }} on the fields {{ .StructName }}.{{ .StructField }} and {{ .OtherStructName }}.{{ .OtherStructField }} func(l *{{ .StructName }}) LinkTo{{ .OtherStructName }}OnField{{.StructField}}(targets ...*{{ .OtherStructName }}) error { if targets == nil { return errors.New("start and end can not be nil") @@ -127,7 +129,8 @@ func(l *{{ .StructName }}) LinkTo{{ .OtherStructName }}OnField{{.StructField}}(t ` var unlinkSingle = ` -{{ define "unlinkSingle" }}func(l *{{ .StructName }}) UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}) error { +{{ define "unlinkSingle" }}//UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}} unlinks {{ .StructName }} from {{ .OtherStructName }} on the fields {{ .StructName }}.{{ .StructField }} and {{ .OtherStructName }}.{{ .OtherStructField }} +func(l *{{ .StructName }}) UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}) error { if target == nil { return errors.New("start and end can not be nil") } @@ -163,7 +166,8 @@ var unlinkSingle = ` ` var unlinkMulti = ` -{{ define "unlinkMulti" }}func(l *{{ .StructName }}) UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}}(targets ...*{{ .OtherStructName }}) error { +{{ define "unlinkMulti" }}//UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}} unlinks {{ .StructName }} from {{ .OtherStructName }} on the fields {{ .StructName }}.{{ .StructField }} and {{ .OtherStructName }}.{{ .OtherStructField }} +func(l *{{ .StructName }}) UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}}(targets ...*{{ .OtherStructName }}) error { if targets == nil { return errors.New("start and end can not be nil") } @@ -202,7 +206,9 @@ var unlinkMulti = ` ` var unlinkSpec = ` -{{ define "unlinkSpec" }}func(l *{{ .StructName }}) UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}) error { +{{ define "unlinkSpec" }}// UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}} unlinks {{ .StructName }} from {{ .OtherStructName }} on the fields {{ .StructName }}.{{ .StructField }} and {{ .OtherStructName }}.{{ .OtherStructField }}. +// also note this uses the special edge {{ .SpecialEdgeType }} +func(l *{{ .StructName }}) UnlinkFrom{{ .OtherStructName }}OnField{{.StructField}}(target *{{ .OtherStructName }}) error { if target == nil { return errors.New("start and end can not be nil") } @@ -254,7 +260,7 @@ var unlinkSpec = ` ` var masterTpl = ` -{{ define "linkFile" }}// code generated by gogm; DO NOT EDIT +{{ define "linkFile" }}// Code generated by GoGM v1.0.1. DO NOT EDIT package {{ .PackageName }} import ( diff --git a/cmd/gogmcli/gogm.go b/cmd/gogmcli/gogm.go index d7f6e2e..6bbfb01 100644 --- a/cmd/gogmcli/gogm.go +++ b/cmd/gogmcli/gogm.go @@ -34,7 +34,7 @@ func main() { app := &cli.App{ Name: "gogmcli", HelpName: "gogmcli", - Version: "1.0.0", + Version: "1.0.1", Usage: "used for neo4j operations from gogm schema", Description: "cli for generating and executing migrations with gogm", EnableBashCompletion: true, diff --git a/testing_/linking.go b/testing_/linking.go index 945e8d7..c6ca06a 100644 --- a/testing_/linking.go +++ b/testing_/linking.go @@ -1,89 +1,11 @@ -// Copyright (c) 2019 MindStand Technologies, Inc -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -// code generated by gogm; DO NOT EDIT +// Code generated by GoGM v1.0.1. DO NOT EDIT package testing_ import ( "errors" ) -func (l *ExampleObject) LinkToExampleObject2OnFieldSpecial(target *ExampleObject2, edge *SpecialEdge) error { - if target == nil { - return errors.New("start and end can not be nil") - } - - if edge == nil { - return errors.New("edge can not be nil") - } - - err := edge.SetStartNode(l) - if err != nil { - return err - } - - err = edge.SetEndNode(target) - if err != nil { - return err - } - - l.Special = edge - - if target.Special == nil { - target.Special = make([]*SpecialEdge, 1, 1) - target.Special[0] = edge - } else { - target.Special = append(target.Special, edge) - } - - return nil -} - -func (l *ExampleObject) UnlinkFromExampleObject2OnFieldSpecial(target *ExampleObject2) error { - if target == nil { - return errors.New("start and end can not be nil") - } - - l.Special = nil - - if target.Special != nil { - for i, unlinkTarget := range target.Special { - - obj := unlinkTarget.GetStartNode() - - checkObj, ok := obj.(*ExampleObject) - if !ok { - return errors.New("unable to cast unlinkTarget to [ExampleObject]") - } - if checkObj.UUID == l.UUID { - a := &target.Special - (*a)[i] = (*a)[len(*a)-1] - (*a)[len(*a)-1] = nil - *a = (*a)[:len(*a)-1] - break - } - } - } - - return nil -} - +// LinkToExampleObjectOnFieldChildren links ExampleObject to ExampleObject on the fields ExampleObject.Children and ExampleObject.Parents func (l *ExampleObject) LinkToExampleObjectOnFieldChildren(targets ...*ExampleObject) error { if targets == nil { return errors.New("start and end can not be nil") @@ -104,6 +26,7 @@ func (l *ExampleObject) LinkToExampleObjectOnFieldChildren(targets ...*ExampleOb return nil } +//UnlinkFromExampleObjectOnFieldChildren unlinks ExampleObject from ExampleObject on the fields ExampleObject.Children and ExampleObject.Parents func (l *ExampleObject) UnlinkFromExampleObjectOnFieldChildren(targets ...*ExampleObject) error { if targets == nil { return errors.New("start and end can not be nil") @@ -128,6 +51,8 @@ func (l *ExampleObject) UnlinkFromExampleObjectOnFieldChildren(targets ...*Examp return nil } + +//LinkToExampleObjectOnFieldParents links ExampleObject to ExampleObject on the fields ExampleObject.Parents and ExampleObject.Children func (l *ExampleObject) LinkToExampleObjectOnFieldParents(target *ExampleObject) error { if target == nil { return errors.New("start and end can not be nil") @@ -145,6 +70,7 @@ func (l *ExampleObject) LinkToExampleObjectOnFieldParents(target *ExampleObject) return nil } +//UnlinkFromExampleObjectOnFieldParents unlinks ExampleObject from ExampleObject on the fields ExampleObject.Parents and ExampleObject.Children func (l *ExampleObject) UnlinkFromExampleObjectOnFieldParents(target *ExampleObject) error { if target == nil { return errors.New("start and end can not be nil") @@ -167,7 +93,9 @@ func (l *ExampleObject) UnlinkFromExampleObjectOnFieldParents(target *ExampleObj return nil } -func (l *ExampleObject2) LinkToExampleObjectOnFieldSpecial(target *ExampleObject, edge *SpecialEdge) error { +// LinkToExampleObject2OnFieldSpecial links ExampleObject to ExampleObject2 on the fields ExampleObject.Special and ExampleObject2.Special. +// note this uses the special edge SpecialEdge +func (l *ExampleObject) LinkToExampleObject2OnFieldSpecial(target *ExampleObject2, edge *SpecialEdge) error { if target == nil { return errors.New("start and end can not be nil") } @@ -176,44 +104,48 @@ func (l *ExampleObject2) LinkToExampleObjectOnFieldSpecial(target *ExampleObject return errors.New("edge can not be nil") } - err := edge.SetStartNode(target) + err := edge.SetStartNode(l) if err != nil { return err } - err = edge.SetEndNode(l) + err = edge.SetEndNode(target) if err != nil { return err } - if l.Special == nil { - l.Special = make([]*SpecialEdge, 1, 1) - l.Special[0] = edge + l.Special = edge + + if target.Special == nil { + target.Special = make([]*SpecialEdge, 1, 1) + target.Special[0] = edge } else { - l.Special = append(l.Special, edge) + target.Special = append(target.Special, edge) } - target.Special = edge - return nil } -func (l *ExampleObject2) UnlinkFromExampleObjectOnFieldSpecial(target *ExampleObject) error { +// UnlinkFromExampleObject2OnFieldSpecial unlinks ExampleObject from ExampleObject2 on the fields ExampleObject.Special and ExampleObject2.Special. +// also note this uses the special edge SpecialEdge +func (l *ExampleObject) UnlinkFromExampleObject2OnFieldSpecial(target *ExampleObject2) error { if target == nil { return errors.New("start and end can not be nil") } - if l.Special != nil { - for i, unlinkTarget := range l.Special { + l.Special = nil - obj := unlinkTarget.GetEndNode() + if target.Special != nil { + for i, unlinkTarget := range target.Special { + + obj := unlinkTarget.GetStartNode() checkObj, ok := obj.(*ExampleObject) if !ok { return errors.New("unable to cast unlinkTarget to [ExampleObject]") } - if checkObj.UUID == target.UUID { - a := &l.Special + if checkObj.UUID == l.UUID { + a := &target.Special (*a)[i] = (*a)[len(*a)-1] (*a)[len(*a)-1] = nil *a = (*a)[:len(*a)-1] @@ -222,11 +154,10 @@ func (l *ExampleObject2) UnlinkFromExampleObjectOnFieldSpecial(target *ExampleOb } } - target.Special = nil - return nil } +// LinkToExampleObject2OnFieldChildren2 links ExampleObject2 to ExampleObject2 on the fields ExampleObject2.Children2 and ExampleObject2.Parents2 func (l *ExampleObject2) LinkToExampleObject2OnFieldChildren2(targets ...*ExampleObject2) error { if targets == nil { return errors.New("start and end can not be nil") @@ -247,6 +178,7 @@ func (l *ExampleObject2) LinkToExampleObject2OnFieldChildren2(targets ...*Exampl return nil } +//UnlinkFromExampleObject2OnFieldChildren2 unlinks ExampleObject2 from ExampleObject2 on the fields ExampleObject2.Children2 and ExampleObject2.Parents2 func (l *ExampleObject2) UnlinkFromExampleObject2OnFieldChildren2(targets ...*ExampleObject2) error { if targets == nil { return errors.New("start and end can not be nil") @@ -271,6 +203,8 @@ func (l *ExampleObject2) UnlinkFromExampleObject2OnFieldChildren2(targets ...*Ex return nil } + +//LinkToExampleObject2OnFieldParents2 links ExampleObject2 to ExampleObject2 on the fields ExampleObject2.Parents2 and ExampleObject2.Children2 func (l *ExampleObject2) LinkToExampleObject2OnFieldParents2(target *ExampleObject2) error { if target == nil { return errors.New("start and end can not be nil") @@ -288,6 +222,7 @@ func (l *ExampleObject2) LinkToExampleObject2OnFieldParents2(target *ExampleObje return nil } +//UnlinkFromExampleObject2OnFieldParents2 unlinks ExampleObject2 from ExampleObject2 on the fields ExampleObject2.Parents2 and ExampleObject2.Children2 func (l *ExampleObject2) UnlinkFromExampleObject2OnFieldParents2(target *ExampleObject2) error { if target == nil { return errors.New("start and end can not be nil") @@ -309,3 +244,67 @@ func (l *ExampleObject2) UnlinkFromExampleObject2OnFieldParents2(target *Example return nil } + +// LinkToExampleObjectOnFieldSpecial links ExampleObject2 to ExampleObject on the fields ExampleObject2.Special and ExampleObject.Special. +// note this uses the special edge SpecialEdge +func (l *ExampleObject2) LinkToExampleObjectOnFieldSpecial(target *ExampleObject, edge *SpecialEdge) error { + if target == nil { + return errors.New("start and end can not be nil") + } + + if edge == nil { + return errors.New("edge can not be nil") + } + + err := edge.SetStartNode(target) + if err != nil { + return err + } + + err = edge.SetEndNode(l) + if err != nil { + return err + } + + if l.Special == nil { + l.Special = make([]*SpecialEdge, 1, 1) + l.Special[0] = edge + } else { + l.Special = append(l.Special, edge) + } + + target.Special = edge + + return nil +} + +// UnlinkFromExampleObjectOnFieldSpecial unlinks ExampleObject2 from ExampleObject on the fields ExampleObject2.Special and ExampleObject.Special. +// also note this uses the special edge SpecialEdge +func (l *ExampleObject2) UnlinkFromExampleObjectOnFieldSpecial(target *ExampleObject) error { + if target == nil { + return errors.New("start and end can not be nil") + } + + if l.Special != nil { + for i, unlinkTarget := range l.Special { + + obj := unlinkTarget.GetEndNode() + + checkObj, ok := obj.(*ExampleObject) + if !ok { + return errors.New("unable to cast unlinkTarget to [ExampleObject]") + } + if checkObj.UUID == target.UUID { + a := &l.Special + (*a)[i] = (*a)[len(*a)-1] + (*a)[len(*a)-1] = nil + *a = (*a)[:len(*a)-1] + break + } + } + } + + target.Special = nil + + return nil +}