Skip to content

Commit

Permalink
Expose database in summary
Browse files Browse the repository at this point in the history
  • Loading branch information
fbiville committed Jul 6, 2021
1 parent 55c00c1 commit 137583e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 51 deletions.
1 change: 1 addition & 0 deletions neo4j/db/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,5 @@ type Summary struct {
Plan *Plan
ProfiledPlan *ProfiledPlan
Notifications []Notification
Database string
}
1 change: 1 addition & 0 deletions neo4j/internal/bolt/hydrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (s *success) summary() *db.Summary {
Plan: s.plan,
ProfiledPlan: s.profile,
Notifications: s.notifications,
Database: s.db,
}
}

Expand Down
23 changes: 23 additions & 0 deletions neo4j/resultsummary.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ type ResultSummary interface {
ResultAvailableAfter() time.Duration
// ResultConsumedAfter returns the time it took the server to consume the result.
ResultConsumedAfter() time.Duration
// Database returns information about the database where the result is obtained from
Database() DatabaseInfo
}

// Counters contains statistics about the changes made to the database made as part
Expand Down Expand Up @@ -108,6 +110,11 @@ type ServerInfo interface {
ProtocolVersion() db.ProtocolVersion
}

// DatabaseInfo contains basic information of the database the query result has been obtained from.
type DatabaseInfo interface {
Name() string
}

// Plan describes the actual plan that the database planner produced and used (or will use) to execute your statement.
// This can be extremely helpful in understanding what a statement is doing, and how to optimize it. For more details,
// see the Neo4j Manual. The plan for the statement is a tree of plans - each sub-tree containing zero or more child
Expand Down Expand Up @@ -295,6 +302,22 @@ func (s *resultSummary) Plan() Plan {
return &plan{plan: s.sum.Plan}
}

func (s *resultSummary) Database() DatabaseInfo {
database := s.sum.Database
if database == "" {
return nil
}
return &databaseInfo{name: database}
}

type databaseInfo struct {
name string
}

func (d *databaseInfo) Name() string {
return d.name
}

type plan struct {
plan *db.Plan
}
Expand Down
76 changes: 25 additions & 51 deletions neo4j/test-integration/dbserver/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,34 +23,8 @@ import (
"fmt"
"regexp"
"strconv"

"github.com/neo4j/neo4j-go-driver/v4/neo4j"
)

var (
// V340 identifies server version 3.4.0
V340 = VersionOf("3.4.0")
// V350 identifies server version 3.5.0
V350 = VersionOf("3.5.0")
)

func versionOfDriver(driver neo4j.Driver) Version {
session := driver.NewSession(neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead})
defer session.Close()

result, err := session.Run("RETURN 1", nil)
if err != nil {
panic(err)
}

summary, err := result.Consume()
if err != nil {
panic(err)
}

return VersionOf(summary.Server().Version())
}

const (
versionPattern = "(Neo4j/)?(\\d+)\\.(\\d+)(?:\\.)?(\\d*)(\\.|-|\\+)?([0-9A-Za-z-.]*)?"
versionInDev = "Neo4j/dev"
Expand All @@ -67,11 +41,33 @@ type Version struct {
}

var (
noVersion Version = Version{-1, -1, -1}
inDevVersion Version = Version{0, 0, 0}
defaultVersion Version = Version{3, 0, 0}
noVersion = Version{-1, -1, -1}
inDevVersion = Version{0, 0, 0}
defaultVersion = Version{3, 0, 0}
)

func VersionOf(server string) Version {
if server == "" {
return defaultVersion
} else {
if versionMatcher == nil {
versionMatcher = regexp.MustCompile(versionPattern)
}
matches := versionMatcher.FindStringSubmatch(server)
if matches != nil {
major, _ := strconv.Atoi(matches[2])
minor, _ := strconv.Atoi(matches[3])
patch, _ := strconv.Atoi(matches[4])

return Version{major, minor, patch}
} else if server == versionInDev {
return inDevVersion
}
}

return noVersion
}

func compareInt(num1 int, num2 int) int {
if num1 == num2 {
return 0
Expand All @@ -96,28 +92,6 @@ func compareVersions(version1 Version, version2 Version) int {
return comp
}

func VersionOf(server string) Version {
if server == "" {
return defaultVersion
} else {
if versionMatcher == nil {
versionMatcher = regexp.MustCompile(versionPattern)
}
matches := versionMatcher.FindStringSubmatch(server)
if matches != nil {
major, _ := strconv.Atoi(matches[2])
minor, _ := strconv.Atoi(matches[3])
patch, _ := strconv.Atoi(matches[4])

return Version{major, minor, patch}
} else if server == versionInDev {
return inDevVersion
}
}

return noVersion
}

func (version Version) String() string {
return fmt.Sprintf("%d.%d.%d", version.major, version.minor, version.patch)
}
Expand Down
107 changes: 107 additions & 0 deletions neo4j/test-integration/summary_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package test_integration

import (
"fmt"
"github.com/neo4j/neo4j-go-driver/v4/neo4j"
"github.com/neo4j/neo4j-go-driver/v4/neo4j/test-integration/dbserver"
"io"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Result Summary", func() {

const extraDatabase = "extra"

var server dbserver.DbServer
var driver neo4j.Driver
var bookmark string
noParams := map[string]interface{}{}

BeforeEach(func() {
server = dbserver.GetDbServer()
driver = server.Driver()
Expect(driver).NotTo(BeNil())
})

Context("from single-tenant Neo4j servers", func() {
BeforeEach(func() {
if isMultiTenant(server) {
Skip(`Multi-tenant servers are covered in other tests`)
}
})

It("does not include any database information", func() {
session := driver.NewSession(neo4j.SessionConfig{Bookmarks: []string{bookmark}})
defer assertCloses(session)
result, err := session.Run("RETURN 42", noParams)
Expect(err).NotTo(HaveOccurred())

summary, err := result.Consume()
Expect(err).NotTo(HaveOccurred())
if server.Version.GreaterThanOrEqual(V4) {
Expect(summary.Database().Name()).To(Equal("neo4j"))
} else {
Expect(summary.Database()).To(BeNil())
}
})
})

Context("from multi-tenant Neo4j servers", func() {
BeforeEach(func() {
if !isMultiTenant(server) {
Skip("Multi-tenancy is a Neo4j 4+ feature")
}
})

BeforeEach(func() {
session := driver.NewSession(neo4j.SessionConfig{DatabaseName: "system"})
defer assertCloses(session)
_, err := session.Run(fmt.Sprintf("CREATE DATABASE %s", extraDatabase), map[string]interface{}{})
Expect(err).NotTo(HaveOccurred())
bookmark = session.LastBookmark()
})

AfterEach(func() {
session := driver.NewSession(neo4j.SessionConfig{DatabaseName: "system", Bookmarks: []string{bookmark}})
defer assertCloses(session)
_, err := session.Run(fmt.Sprintf("DROP DATABASE %s", extraDatabase), map[string]interface{}{})
Expect(err).NotTo(HaveOccurred())
bookmark = ""
})

It("includes the default database information", func() {
session := driver.NewSession(neo4j.SessionConfig{Bookmarks: []string{bookmark}})
defer assertCloses(session)
result, err := session.Run("RETURN 42", noParams)
Expect(err).NotTo(HaveOccurred())

summary, err := result.Consume()
Expect(err).NotTo(HaveOccurred())
Expect(summary.Database().Name()).To(Equal("neo4j"))
})

It("includes the database information, based on session configuration", func() {
session := driver.NewSession(neo4j.SessionConfig{DatabaseName: extraDatabase, Bookmarks: []string{bookmark}})
defer assertCloses(session)
result, err := session.Run("RETURN 42", noParams)
Expect(err).NotTo(HaveOccurred())

summary, err := result.Consume()
Expect(err).NotTo(HaveOccurred())
Expect(summary.Database().Name()).To(Equal(extraDatabase))
})
})


})

func isMultiTenant(server dbserver.DbServer) bool {
return server.Version.GreaterThanOrEqual(V4) && server.IsEnterprise
}

func assertCloses(closer io.Closer) {
err := closer.Close()
Expect(err).NotTo(HaveOccurred())
}

0 comments on commit 137583e

Please sign in to comment.