From 7f300f0ee44f1e76438dfb9288e2d1f9bb0e4dfb Mon Sep 17 00:00:00 2001 From: Eric Solender Date: Mon, 7 Sep 2020 15:34:46 -0400 Subject: [PATCH 1/3] fix serialization error and updated mock --- integration_test.go | 39 +++++++++++++++++++++++++++ mocks/ISession.go | 30 +++++---------------- model.go | 64 +++++++++++++++++++++++++++++++++++++++++++++ session.go | 24 ++++++++++++++++- 4 files changed, 133 insertions(+), 24 deletions(-) diff --git a/integration_test.go b/integration_test.go index ce236c3..637c3d9 100644 --- a/integration_test.go +++ b/integration_test.go @@ -20,11 +20,50 @@ package gogm import ( + uuid2 "github.com/google/uuid" "github.com/stretchr/testify/require" "testing" "time" ) +func TestRawQuery(t *testing.T) { + if testing.Short() { + t.Skip() + return + } + + req := require.New(t) + + conf := Config{ + Username: "neo4j", + Password: "password", + Host: "0.0.0.0", + IsCluster: false, + Port: 7687, + PoolSize: 15, + IndexStrategy: IGNORE_INDEX, + } + + req.Nil(Init(&conf, &a{}, &b{}, &c{})) + + sess, err := NewSession(false) + req.Nil(err) + + uuid := uuid2.New().String() + + req.Nil(sess.Save(&a{ + BaseNode: BaseNode{ + UUID: uuid, + }, + })) + + raw, err := sess.QueryRaw("match (n) where n.uuid=$uuid return n", map[string]interface{}{ + "uuid": uuid, + }) + req.Nil(err) + req.NotEmpty(raw) +} + func TestIntegration(t *testing.T) { if testing.Short() { t.Skip() diff --git a/mocks/ISession.go b/mocks/ISession.go index 3ba510c..9f9f794 100644 --- a/mocks/ISession.go +++ b/mocks/ISession.go @@ -1,29 +1,13 @@ -// Copyright (c) 2020 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 mockery v1.0.0. DO NOT EDIT. +// Code generated by mockery v2.2.1. DO NOT EDIT. package mocks -import go_cypherdsl "github.com/mindstand/go-cypherdsl" -import gogm "github.com/mindstand/gogm" -import mock "github.com/stretchr/testify/mock" +import ( + go_cypherdsl "github.com/mindstand/go-cypherdsl" + gogm "github.com/mindstand/gogm" + + mock "github.com/stretchr/testify/mock" +) // ISession is an autogenerated mock type for the ISession type type ISession struct { diff --git a/model.go b/model.go index 73cfa4f..ad07ff4 100644 --- a/model.go +++ b/model.go @@ -19,6 +19,8 @@ package gogm +import "github.com/neo4j/neo4j-go-driver/neo4j" + // specifies how edges are loaded type neoEdgeConfig struct { Id int64 @@ -33,3 +35,65 @@ type neoEdgeConfig struct { Type string } + +type NodeWrap struct { + Id int64 `json:"id"` + Labels []string `json:"labels"` + Props map[string]interface{} `json:"props"` +} + +func newNodeWrap(node neo4j.Node) *NodeWrap { + return &NodeWrap{ + Id: node.Id(), + Labels: node.Labels(), + Props: node.Props(), + } +} + +type PathWrap struct { + Nodes []*NodeWrap `json:"nodes"` + RelNodes []*RelationshipWrap `json:"rel_nodes"` +} + +func newPathWrap(path neo4j.Path) *PathWrap { + pw := new(PathWrap) + nodes := path.Nodes() + if nodes != nil && len(nodes) != 0 { + nds := make([]*NodeWrap, len(nodes), cap(nodes)) + for i, n := range nodes { + nds[i] = newNodeWrap(n) + } + + pw.Nodes = nds + } + + rels := path.Relationships() + if rels != nil && len(rels) != 0 { + newRels := make([]*RelationshipWrap, len(rels), cap(rels)) + for i, rel := range rels { + newRels[i] = newRelationshipWrap(rel) + } + + pw.RelNodes = newRels + } + + return pw +} + +type RelationshipWrap struct { + Id int64 `json:"id"` + StartId int64 `json:"start_id"` + EndId int64 `json:"end_id"` + Type string `json:"type"` + Props map[string]interface{} `json:"props"` +} + +func newRelationshipWrap(rel neo4j.Relationship) *RelationshipWrap { + return &RelationshipWrap{ + Id: rel.Id(), + StartId: rel.StartId(), + EndId: rel.EndId(), + Type: rel.Type(), + Props: rel.Props(), + } +} \ No newline at end of file diff --git a/session.go b/session.go index 39b515b..405305d 100644 --- a/session.go +++ b/session.go @@ -478,8 +478,30 @@ func (s *Session) QueryRaw(query string, properties map[string]interface{}) ([][ var result [][]interface{} + // we have to wrap everything because the driver only exposes interfaces which are not serializable for res.Next() { - result = append(result, res.Record().Values()) + valLen := len(res.Record().Values()) + valCap := cap(res.Record().Values()) + if valLen != 0 { + vals := make([]interface{}, valLen, valCap) + for i, val := range res.Record().Values() { + switch val.(type) { + case neo4j.Path: + vals[i] = newPathWrap(val.(neo4j.Path)) + break + case neo4j.Relationship: + vals[i] = newRelationshipWrap(val.(neo4j.Relationship)) + break + case neo4j.Node: + vals[i] = newNodeWrap(val.(neo4j.Node)) + break + default: + vals[i] = val + continue + } + } + result = append(result, vals) + } } return result, nil From 5ac110a419c295656aca5e402447783221285d02 Mon Sep 17 00:00:00 2001 From: Eric Solender Date: Mon, 7 Sep 2020 16:39:56 -0400 Subject: [PATCH 2/3] added comment --- integration_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration_test.go b/integration_test.go index be581c9..be61a3b 100644 --- a/integration_test.go +++ b/integration_test.go @@ -28,6 +28,8 @@ import ( "github.com/stretchr/testify/require" ) +// This test is to make sure retuning raw results from neo4j actually work. This +// proves that the bug causing empty interfaces to be returned has been fixed. func TestRawQuery(t *testing.T) { if testing.Short() { t.Skip() From d63f5dca314859e34def69bce84b7360fbb06287 Mon Sep 17 00:00:00 2001 From: Eric Solender Date: Tue, 8 Sep 2020 12:41:56 -0400 Subject: [PATCH 3/3] added comment --- model.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/model.go b/model.go index 4f569d4..9975be3 100644 --- a/model.go +++ b/model.go @@ -36,6 +36,7 @@ type neoEdgeConfig struct { Type string } +// NodeWrap wraps the neo4j node struct because it is private type NodeWrap struct { Id int64 `json:"id"` Labels []string `json:"labels"` @@ -50,6 +51,7 @@ func newNodeWrap(node neo4j.Node) *NodeWrap { } } +// PathWrap wraps the neo4j path struct because it is private type PathWrap struct { Nodes []*NodeWrap `json:"nodes"` RelNodes []*RelationshipWrap `json:"rel_nodes"` @@ -80,6 +82,7 @@ func newPathWrap(path neo4j.Path) *PathWrap { return pw } +// RelationshipWrap wraps the neo4j relationship struct because it is private type RelationshipWrap struct { Id int64 `json:"id"` StartId int64 `json:"start_id"`