Skip to content

Commit

Permalink
Merge pull request #21 from mindstand/embedded_structs
Browse files Browse the repository at this point in the history
Embedded structs #5
  • Loading branch information
nikitawootten authored Nov 13, 2019
2 parents 8834955 + a17732a commit b6e0bf4
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 59 deletions.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ Ex.
type TdString string

type MyNeo4jObject struct {
Id int64 `gogm:"name=id"` //required to have an int64 id field
UUID string `gogm:"pk;name=uuid"` //required to have uuid string field marked as pk
// provides required node fields
gogm.BaseNode

Field string `gogm:"name=field"`
Props map[string]interface{} `gogm:"properties;name=props"` //note that this would show up as `props.<key>` in neo4j
IgnoreMe bool `gogm="-"`
Expand All @@ -68,8 +69,9 @@ type tdInt int

//structs for the example (can also be found in decoder_test.go)
type VertexA struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
// provides required node fields
gogm.BaseNode

TestField string `gogm:"name=test_field"`
TestTypeDefString tdString `gogm:"name=test_type_def_string"`
TestTypeDefInt tdInt `gogm:"name=test_type_def_int"`
Expand All @@ -81,8 +83,9 @@ type VertexA struct {
}

type VertexB struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
// provides required node fields
gogm.BaseNode

TestField string `gogm:"name=test_field"`
TestTime time.Time `gogm:"time;name=test_time"`

Expand All @@ -95,8 +98,9 @@ type VertexB struct {
}

type EdgeC struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
// provides required node fields
gogm.BaseNode

Start *VertexA
End *VertexB
Test string `gogm:"name=test"`
Expand Down Expand Up @@ -157,11 +161,12 @@ func main(){
```

## Inspiration
Inspiration came from the Java OGM implementation by Neo4j. We studied their implementation to use as a good basis for ours in go! So, thanks Neo4j!
Inspiration came from the Java OGM implementation by Neo4j.

## Road Map
- Support for embedded structs (refer to issue #5)
- More validation (refer to issues #2, #8)
- Schema Migration
- Generation CLI for link functions
- Errors overhaul using go 1.13 error wrapping
- TLS Support
- Documentation (obviously)
Expand Down
88 changes: 55 additions & 33 deletions decoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,13 @@ type tdString string
type tdInt int

type f struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
embedTest
Parents []*f `gogm:"direction=outgoing;relationship=test"`
Children []*f `gogm:"direction=incoming;relationship=test"`
}

type a struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
embedTest
TestField string `gogm:"name=test_field"`
TestTypeDefString tdString `gogm:"name=test_type_def_string"`
TestTypeDefInt tdInt `gogm:"name=test_type_def_int"`
Expand All @@ -178,8 +176,7 @@ type a struct {
}

type b struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
embedTest
TestField string `gogm:"name=test_field"`
TestTime time.Time `gogm:"time;name=test_time"`
Single *a `gogm:"direction=outgoing;relationship=test_rel"`
Expand All @@ -190,8 +187,7 @@ type b struct {
}

type c struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
embedTest
Start *a
End *b
Test string `gogm:"name=test"`
Expand Down Expand Up @@ -288,18 +284,24 @@ func TestDecoder(t *testing.T) {
}

f0 := f{
Id: 0,
UUID: "0",
embedTest: embedTest{
Id: 0,
UUID: "0",
},
}

f1 := f{
Id: 1,
UUID: "1",
embedTest: embedTest{
Id: 1,
UUID: "1",
},
}

f2 := f{
Id: 2,
UUID: "2",
embedTest: embedTest{
Id: 2,
UUID: "2",
},
}

f0.Parents = []*f{&f1}
Expand Down Expand Up @@ -364,18 +366,22 @@ func TestDecoder(t *testing.T) {
var readin a

comp := &a{
embedTest: embedTest{
Id: 1,
UUID: "dasdfasd",
},
TestField: "test",
Id: 1,
TestTypeDefInt: 600,
TestTypeDefString: "TDs",
UUID: "dasdfasd",
}

comp22 := &b{
embedTest: embedTest{
Id: 2,
UUID: "dasdfas",
},
TestField: "test",
UUID: "dasdfas",
TestTime: fTime,
Id: 2,
}

comp.SingleA = comp22
Expand Down Expand Up @@ -449,21 +455,27 @@ func TestDecoder(t *testing.T) {
var readin2 a

comp2 := &a{
embedTest: embedTest{
Id: 1,
UUID: "dasdfasd",
},
TestField: "test",
Id: 1,
UUID: "dasdfasd",
}

b2 := &b{
embedTest: embedTest{
Id: 2,
UUID: "dasdfas",
},
TestField: "test",
UUID: "dasdfas",
TestTime: fTime,
Id: 2,
}

c1 := &c{
UUID: "asdfasdafsd",
Id: 420,
embedTest: embedTest{
Id: 34,
UUID: "asdfasdafsd",
},
Start: comp2,
End: b2,
Test: "testing",
Expand Down Expand Up @@ -517,14 +529,18 @@ func TestDecoder(t *testing.T) {
var readin3 a

comp3 := a{
embedTest: embedTest{
Id: 1,
UUID: "dasdfasd",
},
TestField: "test",
Id: 1,
UUID: "dasdfasd",
MultiA: []*b{
{
TestField: "test",
UUID: "dasdfas",
Id: 2,
embedTest: embedTest{
Id: 2,
UUID: "dasdfas",
},
TestTime: fTime,
},
},
Expand Down Expand Up @@ -581,19 +597,25 @@ func TestDecoder(t *testing.T) {

comp4 := &a{
TestField: "test",
Id: 1,
UUID: "dasdfasd",
embedTest: embedTest{
Id: 1,
UUID: "dasdfasd",
},
}

b3 := &b{
TestField: "test",
UUID: "dasdfas",
embedTest: embedTest{
Id: 2,
UUID: "dasdfas",
},
TestTime: fTime,
Id: 2,
}

c4 := c{
UUID: "asdfasdafsd",
embedTest: embedTest{
UUID: "asdfasdafsd",
},
Start: comp4,
End: b3,
Test: "testing",
Expand Down
28 changes: 25 additions & 3 deletions decorator.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,14 @@ func getStructDecoratorConfig(i interface{}, mappedRelations *relationConfigs) (

toReturn.Fields = map[string]decoratorConfig{}

//iterate through fields and get their configuration
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fields := getFields(t)

if fields == nil || len(fields) == 0 {
return nil, errors.New("failed to parse fields")
}

//iterate through fields and get their configuration
for _, field := range fields {
tag := field.Tag.Get(decoratorName)

if tag != "" {
Expand Down Expand Up @@ -458,3 +462,21 @@ func getStructDecoratorConfig(i interface{}, mappedRelations *relationConfigs) (

return toReturn, nil
}

func getFields(val reflect.Type) []*reflect.StructField {
var fields []*reflect.StructField
if val.Kind() == reflect.Ptr {
return getFields(val.Elem())
}

for i := 0; i < val.NumField(); i++ {
tempField := val.Field(i)
if tempField.Anonymous && tempField.Type.Kind() == reflect.Struct{
fields = append(fields, getFields(tempField.Type)...)
} else {
fields = append(fields, &tempField)
}
}

return fields
}
6 changes: 5 additions & 1 deletion decorator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,13 @@ func TestNewDecoratorConfig(t *testing.T) {

//structs with decorators for testing

type validStruct struct {
type embedTest struct {
Id int64 `gogm:"name=id"`
UUID string `gogm:"pk;name=uuid"`
}

type validStruct struct {
embedTest
IndexField string `gogm:"index;name=index_field"`
UniqueField int `gogm:"unique;name=unique_field"`
OneToOne *validStruct `gogm:"relationship=one2one;direction=incoming"`
Expand Down
6 changes: 6 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package gogm

type BaseNode struct {
Id int64 `json:"-" gogm:"name=id"`
UUID string `json:"uuid" gogm:"pk;name=uuid"`
}
6 changes: 4 additions & 2 deletions delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ func TestDelete(t *testing.T) {
defer driverPool.Reclaim(conn)

del := a{
Id: 0,
UUID: "5334ee8c-6231-40fd-83e5-16c8016ccde6",
embedTest: embedTest{
Id: 0,
UUID: "5334ee8c-6231-40fd-83e5-16c8016ccde6",
},
}

err = deleteNode(conn, &del)
Expand Down
Loading

0 comments on commit b6e0bf4

Please sign in to comment.