diff --git a/README.md b/README.md index e2b80b44..a7749116 100644 --- a/README.md +++ b/README.md @@ -337,12 +337,12 @@ boltLogger := neo4j.ConsoleBoltLogger() result, err := neo4j.ExecuteQuery(ctx, driver, query, params, transformer, neo4j.ExecuteQueryWithBoltLogger(boltLogger)) # for the regular session APIs (session.Run, session.BeginTransaction, session.ExecuteRead, session.ExecuteWrite) -session := driver.NewSession(neo4j.SessionConfig{BoltLogger: boltLogger}) +session := driver.NewSession(config.SessionConfig{BoltLogger: boltLogger}) ``` ### Custom Bolt Logger -The `BoltLogger` field of the `neo4j.SessionConfig` struct is defined to be of interface `neo4j/log.BoltLogger` which has the following definition: +The `BoltLogger` field of the `config.SessionConfig` struct is defined to be of interface `neo4j/log.BoltLogger` which has the following definition: ```go type BoltLogger interface { diff --git a/benchmark/main.go b/benchmark/main.go index 62003486..a484c6ab 100644 --- a/benchmark/main.go +++ b/benchmark/main.go @@ -27,11 +27,12 @@ import ( neo4j18 "github.com/neo4j/neo4j-go-driver/neo4j" neo4j "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) func getSetup(driver neo4j.Driver) *neo4j.Node { // Check if setup already built - sess := driver.NewSession(neo4j.SessionConfig{}) + sess := driver.NewSession(config.SessionConfig{}) defer sess.Close() result, err := sess.Run("MATCH (s:Setup) RETURN s", nil) @@ -71,7 +72,7 @@ func getBoolProp(node *neo4j.Node, name string, dflt bool) bool { func buildSetup(driver neo4j.Driver, setup *neo4j.Node) { - sess := driver.NewSession(neo4j.SessionConfig{}) + sess := driver.NewSession(config.SessionConfig{}) defer sess.Close() if !getBoolProp(setup, "iterMxL", false) { @@ -95,7 +96,7 @@ func buildSetup(driver neo4j.Driver, setup *neo4j.Node) { } func iterMxL(driver neo4j.Driver) { - sess := driver.NewSession(neo4j.SessionConfig{}) + sess := driver.NewSession(config.SessionConfig{}) defer sess.Close() result, err := sess.Run("MATCH (n:IterMxL) RETURN n", nil) @@ -153,7 +154,7 @@ func buildParamsLMap() map[string]any { func params(driver neo4j.Driver, m map[string]any, n int) { // Use same session for all of n, not part of measurement - session := driver.NewSession(neo4j.SessionConfig{}) + session := driver.NewSession(config.SessionConfig{}) for i := 0; i < n; i++ { _, err := session.Run("RETURN 0", m) if err != nil { @@ -179,7 +180,7 @@ func params18(driver neo4j18.Driver, m map[string]any, n int) { // Include session creation in measurement func getS(driver neo4j.Driver, n int) { for i := 0; i < n; i++ { - session := driver.NewSession(neo4j.SessionConfig{}) + session := driver.NewSession(config.SessionConfig{}) x, _ := session.ReadTransaction(func(tx neo4j.Transaction) (any, error) { res, err := tx.Run("RETURN $i", map[string]any{"i": i}) if err != nil { diff --git a/neo4j/auth/auth_examples_test.go b/neo4j/auth/auth_examples_test.go index a87838bc..ffccf69b 100644 --- a/neo4j/auth/auth_examples_test.go +++ b/neo4j/auth/auth_examples_test.go @@ -20,10 +20,11 @@ package auth_test import ( "context" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" "os" "time" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" ) func ExampleBasicTokenManager() { diff --git a/neo4j/bookmarks.go b/neo4j/bookmarks/bookmarks.go similarity index 93% rename from neo4j/bookmarks.go rename to neo4j/bookmarks/bookmarks.go index e1224fc4..60d5e459 100644 --- a/neo4j/bookmarks.go +++ b/neo4j/bookmarks/bookmarks.go @@ -15,12 +15,13 @@ * limitations under the License. */ -package neo4j +package bookmarks import ( "context" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" "sync" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" ) // Bookmarks is a holder for server-side bookmarks which are used for causally-chained sessions. @@ -54,14 +55,14 @@ type BookmarkManagerConfig struct { BookmarkConsumer func(ctx context.Context, bookmarks Bookmarks) error } -type bookmarkManager struct { +type DefaultBookmarkManager struct { bookmarks collections.Set[string] supplyBookmarks func(context.Context) (Bookmarks, error) consumeBookmarks func(context.Context, Bookmarks) error mutex sync.RWMutex } -func (b *bookmarkManager) UpdateBookmarks(ctx context.Context, previousBookmarks, newBookmarks Bookmarks) error { +func (b *DefaultBookmarkManager) UpdateBookmarks(ctx context.Context, previousBookmarks, newBookmarks Bookmarks) error { if len(newBookmarks) == 0 { return nil } @@ -77,7 +78,7 @@ func (b *bookmarkManager) UpdateBookmarks(ctx context.Context, previousBookmarks return nil } -func (b *bookmarkManager) GetBookmarks(ctx context.Context) (Bookmarks, error) { +func (b *DefaultBookmarkManager) GetBookmarks(ctx context.Context) (Bookmarks, error) { var extraBookmarks Bookmarks if b.supplyBookmarks != nil { bookmarks, err := b.supplyBookmarks(ctx) @@ -100,7 +101,7 @@ func (b *bookmarkManager) GetBookmarks(ctx context.Context) (Bookmarks, error) { } func NewBookmarkManager(config BookmarkManagerConfig) BookmarkManager { - return &bookmarkManager{ + return &DefaultBookmarkManager{ bookmarks: collections.NewSet(config.InitialBookmarks), supplyBookmarks: config.BookmarkSupplier, consumeBookmarks: config.BookmarkConsumer, @@ -111,7 +112,7 @@ func NewBookmarkManager(config BookmarkManagerConfig) BookmarkManager { // Let s1, s2, s3 be Session interfaces. You can easily causally chain the sessions like so: // ```go // -// s4 := driver.NewSession(neo4j.SessionConfig{ +// s4 := driver.NewSession(config.SessionConfig{ // Bookmarks: neo4j.CombineBookmarks(s1.LastBookmarks(), s2.LastBookmarks(), s3.LastBookmarks()), // }) // diff --git a/neo4j/bookmarks_test.go b/neo4j/bookmarks/bookmarks_test.go similarity index 66% rename from neo4j/bookmarks_test.go rename to neo4j/bookmarks/bookmarks_test.go index b6bec81c..0897d34a 100644 --- a/neo4j/bookmarks_test.go +++ b/neo4j/bookmarks/bookmarks_test.go @@ -1,33 +1,17 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [https://neo4j.com] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package neo4j_test +package bookmarks_test import ( "context" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" "testing" "testing/quick" + + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" ) func TestCombineBookmarks(t *testing.T) { - f := func(slices []neo4j.Bookmarks) bool { - concatenation := neo4j.CombineBookmarks(slices...) + f := func(slices []bm.Bookmarks) bool { + concatenation := bm.CombineBookmarks(slices...) totalLen := 0 for _, s := range slices { totalLen += len(s) @@ -57,8 +41,8 @@ func TestBookmarkManager(outer *testing.T) { outer.Parallel() outer.Run("deduplicates initial bookmarks", func(t *testing.T) { - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - InitialBookmarks: neo4j.Bookmarks{"a", "a", "b"}, + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + InitialBookmarks: bm.Bookmarks{"a", "a", "b"}, }) bookmarks, err := bookmarkManager.GetBookmarks(ctx) @@ -68,7 +52,7 @@ func TestBookmarkManager(outer *testing.T) { }) outer.Run("gets no bookmarks by default", func(t *testing.T) { - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{}) + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{}) getBookmarks := func(db string) bool { bookmarks, err := bookmarkManager.GetBookmarks(ctx) AssertNoError(t, err) @@ -81,11 +65,11 @@ func TestBookmarkManager(outer *testing.T) { }) outer.Run("gets bookmarks along with user-supplied bookmarks", func(t *testing.T) { - expectedBookmarks := neo4j.Bookmarks{"a", "b", "c"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - InitialBookmarks: neo4j.Bookmarks{"a", "b"}, - BookmarkSupplier: func(context.Context) (neo4j.Bookmarks, error) { - return neo4j.Bookmarks{"b", "c"}, nil + expectedBookmarks := bm.Bookmarks{"a", "b", "c"} + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + InitialBookmarks: bm.Bookmarks{"a", "b"}, + BookmarkSupplier: func(context.Context) (bm.Bookmarks, error) { + return bm.Bookmarks{"b", "c"}, nil }, }) @@ -97,14 +81,14 @@ func TestBookmarkManager(outer *testing.T) { outer.Run("user-supplied bookmarks do not alter internal bookmarks", func(t *testing.T) { calls := 0 expectedBookmarks := []string{"a"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - InitialBookmarks: neo4j.Bookmarks{"a"}, - BookmarkSupplier: func(ctx2 context.Context) (neo4j.Bookmarks, error) { + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + InitialBookmarks: bm.Bookmarks{"a"}, + BookmarkSupplier: func(ctx2 context.Context) (bm.Bookmarks, error) { defer func() { calls++ }() if calls == 0 { - return neo4j.Bookmarks{"b"}, nil + return bm.Bookmarks{"b"}, nil } return nil, nil }, @@ -119,8 +103,8 @@ func TestBookmarkManager(outer *testing.T) { outer.Run("returned bookmarks are copies", func(t *testing.T) { expectedBookmarks := []string{"a"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - InitialBookmarks: neo4j.Bookmarks{"a"}, + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + InitialBookmarks: bm.Bookmarks{"a"}, }) bookmarks, err := bookmarkManager.GetBookmarks(ctx) AssertNoError(t, err) @@ -133,8 +117,8 @@ func TestBookmarkManager(outer *testing.T) { }) outer.Run("updates bookmarks", func(t *testing.T) { - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - InitialBookmarks: neo4j.Bookmarks{"a", "b", "c"}, + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + InitialBookmarks: bm.Bookmarks{"a", "b", "c"}, }) err := bookmarkManager.UpdateBookmarks(ctx, []string{"b", "c"}, []string{"d", "a"}) @@ -149,8 +133,8 @@ func TestBookmarkManager(outer *testing.T) { outer.Run("notifies updated bookmarks for new DB", func(t *testing.T) { notifyHookCalled := false expectedBookmarks := []string{"a", "d"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - BookmarkConsumer: func(_ context.Context, bookmarks neo4j.Bookmarks) error { + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + BookmarkConsumer: func(_ context.Context, bookmarks bm.Bookmarks) error { notifyHookCalled = true AssertEqualsInAnyOrder(t, bookmarks, expectedBookmarks) return nil @@ -170,9 +154,9 @@ func TestBookmarkManager(outer *testing.T) { outer.Run("does not notify updated bookmarks when empty", func(t *testing.T) { initialBookmarks := []string{"a", "b"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ InitialBookmarks: initialBookmarks, - BookmarkConsumer: func(_ context.Context, bookmarks neo4j.Bookmarks) error { + BookmarkConsumer: func(_ context.Context, bookmarks bm.Bookmarks) error { t.Error("I must not be called") return nil }, @@ -189,9 +173,9 @@ func TestBookmarkManager(outer *testing.T) { outer.Run("notifies updated bookmarks for existing DB without bookmarks", func(t *testing.T) { notifyHookCalled := false expectedBookmarks := []string{"a", "d"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ InitialBookmarks: nil, - BookmarkConsumer: func(_ context.Context, bookmarks neo4j.Bookmarks) error { + BookmarkConsumer: func(_ context.Context, bookmarks bm.Bookmarks) error { notifyHookCalled = true AssertEqualsInAnyOrder(t, bookmarks, expectedBookmarks) return nil @@ -212,9 +196,9 @@ func TestBookmarkManager(outer *testing.T) { outer.Run("notifies updated bookmarks for existing DB with previous bookmarks", func(t *testing.T) { notifyHookCalled := false expectedBookmarks := []string{"a", "d"} - bookmarkManager := neo4j.NewBookmarkManager(neo4j.BookmarkManagerConfig{ - InitialBookmarks: neo4j.Bookmarks{"a", "b", "c"}, - BookmarkConsumer: func(_ context.Context, bookmarks neo4j.Bookmarks) error { + bookmarkManager := bm.NewBookmarkManager(bm.BookmarkManagerConfig{ + InitialBookmarks: bm.Bookmarks{"a", "b", "c"}, + BookmarkConsumer: func(_ context.Context, bookmarks bm.Bookmarks) error { notifyHookCalled = true AssertEqualsInAnyOrder(t, bookmarks, expectedBookmarks) return nil diff --git a/neo4j/config.go b/neo4j/config.go index 51b3f0c1..2cb6f89b 100644 --- a/neo4j/config.go +++ b/neo4j/config.go @@ -18,16 +18,30 @@ package neo4j import ( - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" "math" "net/url" "time" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" ) // Deprecated: please use config.Config directly. This alias will be removed in 6.0. type Config = config.Config +// Deprecated: please use config.SessionConfig directly. This alias will be removed in 6.0. +type SessionConfig = config.SessionConfig + +// Deprecated: please use config.AccessMode directly. This alias will be removed in 6.0. +type AccessMode = config.AccessMode + +// Deprecated: please use config.TransactionConfig directly. This alias will be removed in 6.0. +type TransactionConfig = config.TransactionConfig + +// Deprecated: please use bookmarks.Bookmarks directly. This alias will be removed in 6.0. +type Bookmarks = bookmarks.Bookmarks + // Deprecated: please use config.ServerAddressResolver directly. This alias will be removed in 6.0. type ServerAddressResolver = config.ServerAddressResolver diff --git a/neo4j/config/driver.go b/neo4j/config/driver.go index 3ca58512..c10eab84 100644 --- a/neo4j/config/driver.go +++ b/neo4j/config/driver.go @@ -20,9 +20,10 @@ package config import ( "crypto/tls" "crypto/x509" + "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" - "time" ) // A Config contains options that can be used to customize certain diff --git a/neo4j/config/session_config.go b/neo4j/config/session_config.go new file mode 100644 index 00000000..7e5668ff --- /dev/null +++ b/neo4j/config/session_config.go @@ -0,0 +1,121 @@ +package config + +import ( + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/auth" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" +) + +// AccessMode defines modes that routing driver decides to which cluster member +// a connection should be opened. +type AuthToken = auth.Token +type AccessMode int + +const ( + // AccessModeWrite tells the driver to use a connection to 'Leader' + AccessModeWrite AccessMode = 0 + // AccessModeRead tells the driver to use a connection to one of the 'Follower' or 'Read Replica'. + AccessModeRead AccessMode = 1 +) + +// SessionConfig is used to configure a new session, its zero value uses safe defaults. +type SessionConfig struct { + // AccessMode used when using Session.Run and explicit transactions. Used to route query + // to read or write servers when running in a cluster. Session.ReadTransaction and Session.WriteTransaction + // does not rely on this mode. + AccessMode AccessMode + // Bookmarks are the initial bookmarks used to ensure that the executing server is at least up + // to date to the point represented by the latest of the provided bookmarks. After running commands + // on the session the bookmark can be retrieved with Session.LastBookmark. All commands executing + // within the same session will automatically use the bookmark from the previous command in the + // session. + Bookmarks bm.Bookmarks + // DatabaseName sets the target database name for the queries executed within the session created with this + // configuration. + // Usage of Cypher clauses like USE is not a replacement for this option. + // Drive​r sends Cypher to the server for processing. + // This option has no explicit value by default, but it is recommended to set one if the target database is known + // in advance. This has the benefit of ensuring a consistent target database name throughout the session in a + // straightforward way and potentially simplifies driver logic as well as reduces network communication resulting + // in better performance. + // When no explicit name is set, the driver behavior depends on the connection URI scheme supplied to the driver on + // instantiation and Bolt protocol version. + // + // Specifically, the following applies: + // + // - for bolt schemes + // queries are dispatched to the server for execution without explicit database name supplied, + // meaning that the target database name for query execution is determined by the server. + // It is important to note that the target database may change (even within the same session), for instance if the + // user's home database is changed on the server. + // + // - for neo4j schemes + // providing that Bolt protocol version 4.4, which was introduced with Neo4j server 4.4, or above + // is available, the driver fetches the user's home database name from the server on first query execution + // within the session and uses the fetched database name explicitly for all queries executed within the session. + // This ensures that the database name remains consistent within the given session. For instance, if the user's + // home database name is 'movies' and the server supplies it to the driver upon database name fetching for the + // session, all queries within that session are executed with the explicit database name 'movies' supplied. + // Any change to the user’s home database is reflected only in sessions created after such change takes effect. + // This behavior requires additional network communication. + // In clustered environments, it is strongly recommended to avoid a single point of failure. + // For instance, by ensuring that the connection URI resolves to multiple endpoints. + // For older Bolt protocol versions, the behavior is the same as described for the bolt schemes above. + DatabaseName string + // FetchSize defines how many records to pull from server in each batch. + // From Bolt protocol v4 (Neo4j 4+) records can be fetched in batches as compared to fetching + // all in previous versions. + // + // If FetchSize is set to FetchDefault, the driver decides the appropriate size. If set to a positive value + // that size is used if the underlying protocol supports it otherwise it is ignored. + // + // To turn off fetching in batches and always fetch everything, set FetchSize to FetchAll. + // If a single large result is to be retrieved this is the most performant setting. + FetchSize int + // Logging target the session will send its Bolt message traces + // + // Possible to use custom logger (implement log.BoltLogger interface) or + // use neo4j.ConsoleBoltLogger. + BoltLogger log.BoltLogger + // ImpersonatedUser sets the Neo4j user that the session will be acting as. + // If not set, the user configured for the driver will be used. + // + // If user impersonation is used, the default database for that impersonated + // user will be used unless DatabaseName is set. + // + // In the former case, when routing is enabled, using impersonation + // without DatabaseName will cause the driver to query the + // cluster for the name of the default database of the impersonated user. + // This is done at the beginning of the session so that queries are routed + // to the correct cluster member (different databases may have different + // leaders). + ImpersonatedUser string + // BookmarkManager defines a central point to externally supply bookmarks + // and be notified of bookmark updates per database + // Since 5.0 + // default: nil (no-op) + BookmarkManager bm.BookmarkManager + // NotificationsMinSeverity defines the minimum severity level of notifications the server should send. + // By default, the driver's settings are used. + // Else, this option overrides the driver's settings. + // Disabling severities allows the server to skip analysis for those, which can speed up query execution. + NotificationsMinSeverity notifications.NotificationMinimumSeverityLevel + // NotificationsDisabledCategories defines the categories of notifications the server should not send. + // By default, the driver's settings are used. + // Else, this option overrides the driver's settings. + // Disabling categories allows the server to skip analysis for those, which can speed up query execution. + NotificationsDisabledCategories notifications.NotificationDisabledCategories + // Auth is used to overwrite the authentication information for the session. + // This requires the server to support re-authentication on the protocol level. + // `nil` will make the driver use the authentication information from the driver configuration. + // The `neo4j` package provides factory functions for common authentication schemes: + // - `neo4j.NoAuth` + // - `neo4j.BasicAuth` + // - `neo4j.KerberosAuth` + // - `neo4j.BearerAuth` + // - `neo4j.CustomAuth` + Auth *AuthToken + + ForceReAuth bool +} diff --git a/neo4j/config/transaction_config.go b/neo4j/config/transaction_config.go new file mode 100644 index 00000000..df0a0f4b --- /dev/null +++ b/neo4j/config/transaction_config.go @@ -0,0 +1,85 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [https://neo4j.com] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package config + +import "time" + +// TransactionConfig holds the settings for explicit and auto-commit transactions. Actual configuration is expected +// to be done using configuration functions that are predefined, i.e. 'WithTxTimeout' and 'WithTxMetadata', or one +// that you could write by your own. +type TransactionConfig struct { + // Timeout is the configured transaction timeout. + Timeout time.Duration + // Metadata is the configured transaction metadata that will be attached to the underlying transaction. + Metadata map[string]any +} + +// WithTxTimeout returns a transaction configuration function that applies a timeout to a transaction. +// +// Transactions that execute longer than the configured timeout will be terminated by the database. +// This functionality allows user code to limit query/transaction execution time. +// The specified timeout overrides the default timeout configured in the database using the `db.transaction.timeout` +// setting (`dbms.transaction.timeout` before Neo4j 5.0). +// Values higher than `db.transaction.timeout` will be ignored and will fall back to the default for server versions +// between 4.2 and 5.2 (inclusive). +// A `0` duration will make the transaction execute indefinitely. +// `math.MinInt` will use the default timeout configured on the server. +// Other negative durations are invalid. +// +// To apply a transaction timeout to an explicit transaction: +// +// session.BeginTransaction(WithTxTimeout(5*time.Second)) +// +// To apply a transaction timeout to an auto-commit transaction: +// +// session.Run("RETURN 1", nil, WithTxTimeout(5*time.Second)) +// +// To apply a transaction timeout to a read transaction function: +// +// session.ExecuteRead(DoWork, WithTxTimeout(5*time.Second)) +// +// To apply a transaction timeout to a write transaction function: +// +// session.ExecuteWrite(DoWork, WithTxTimeout(5*time.Second)) +func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { + return func(config *TransactionConfig) { + config.Timeout = timeout + } +} + +// WithTxMetadata returns a transaction configuration function that attaches metadata to a transaction. +// +// To attach a metadata to an explicit transaction: +// +// session.BeginTransaction(WithTxMetadata(map[string)any{"work-id": 1})) +// +// To attach a metadata to an auto-commit transaction: +// +// session.Run("RETURN 1", nil, WithTxMetadata(map[string)any{"work-id": 1})) +// +// To attach a metadata to a read transaction function: +// +// session.ExecuteRead(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) +// +// To attach a metadata to a write transaction function: +// +// session.ExecuteWrite(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) +func WithTxMetadata(metadata map[string]any) func(*TransactionConfig) { + return func(config *TransactionConfig) { + config.Metadata = metadata + } +} diff --git a/neo4j/driver.go b/neo4j/driver.go index aad0a1ab..2f8d850c 100644 --- a/neo4j/driver.go +++ b/neo4j/driver.go @@ -21,6 +21,8 @@ package neo4j import ( "context" "net/url" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) // Driver represents a pool(s) of connections to a neo4j server or cluster. It's @@ -31,7 +33,7 @@ type Driver interface { // Target returns the url this driver is bootstrapped Target() url.URL // NewSession creates a new session based on the specified session configuration. - NewSession(config SessionConfig) Session + NewSession(config config.SessionConfig) Session // VerifyConnectivity checks that the driver can connect to a remote server or cluster by // establishing a network connection with the remote. Returns nil if succesful // or error describing the problem. @@ -80,7 +82,7 @@ func (d *driver) Target() url.URL { return d.delegate.Target() } -func (d *driver) NewSession(config SessionConfig) Session { +func (d *driver) NewSession(config config.SessionConfig) Session { return d.delegate.NewSession(context.Background(), config).legacy() } diff --git a/neo4j/driver_test.go b/neo4j/driver_test.go index fdc19bc1..ab227783 100644 --- a/neo4j/driver_test.go +++ b/neo4j/driver_test.go @@ -21,6 +21,8 @@ import ( "reflect" "testing" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/router" . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" ) @@ -197,7 +199,7 @@ func TestNewDriverAndClose(t *testing.T) { err = driver.Close() AssertNoError(t, err) - session := driver.NewSession(SessionConfig{}) + session := driver.NewSession(config.SessionConfig{}) _, err = session.Run("cypher", nil) if !IsUsageError(err) { t.Errorf("should not allow new session after driver being closed") @@ -213,13 +215,13 @@ func TestDriverSessionCreation(t *testing.T) { driverSessionCreationTests := []struct { name string testing string - mode AccessMode - bookmarks Bookmarks + mode config.AccessMode + bookmarks bm.Bookmarks }{ - {"Write", "bolt://localhost:7687", AccessModeWrite, []string(nil)}, - {"Read", "bolt://localhost:7687", AccessModeRead, []string(nil)}, - {"Write+bookmarks", "bolt://localhost:7687", AccessModeWrite, []string{"B1", "B2", "B3"}}, - {"Read+bookmarks", "bolt://localhost:7687", AccessModeRead, []string{"B1", "B2", "B3", "B4"}}, + {"Write", "bolt://localhost:7687", config.AccessModeWrite, []string(nil)}, + {"Read", "bolt://localhost:7687", config.AccessModeWrite, []string(nil)}, + {"Write+bookmarks", "bolt://localhost:7687", config.AccessModeWrite, []string{"B1", "B2", "B3"}}, + {"Read+bookmarks", "bolt://localhost:7687", config.AccessModeWrite, []string{"B1", "B2", "B3", "B4"}}, } for _, tt := range driverSessionCreationTests { @@ -227,11 +229,11 @@ func TestDriverSessionCreation(t *testing.T) { driver, err := NewDriver(tt.testing, NoAuth()) AssertNoError(t, err) - sessi := driver.NewSession(SessionConfig{AccessMode: tt.mode, Bookmarks: tt.bookmarks}) + sessi := driver.NewSession(config.SessionConfig{AccessMode: tt.mode, Bookmarks: tt.bookmarks}) sess := sessi.(*session) - if AccessMode(sess.delegate.defaultMode) != tt.mode { - t.Errorf("the defaultMode was not correctly set %v", AccessMode(sess.delegate.defaultMode)) + if config.AccessMode(sess.delegate.defaultMode) != tt.mode { + t.Errorf("the defaultMode was not correctly set %v", config.AccessMode(sess.delegate.defaultMode)) } if len(sess.delegate.bookmarks.currentBookmarks()) != len(tt.bookmarks) { diff --git a/neo4j/driver_with_context.go b/neo4j/driver_with_context.go index 31cf7cb0..0ad7a200 100644 --- a/neo4j/driver_with_context.go +++ b/neo4j/driver_with_context.go @@ -21,15 +21,18 @@ package neo4j import ( "context" "fmt" + "net/url" + "strings" + "sync" + "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" - "net/url" - "strings" - "sync" - "time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/connector" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" @@ -38,14 +41,6 @@ import ( // AccessMode defines modes that routing driver decides to which cluster member // a connection should be opened. -type AccessMode int - -const ( - // AccessModeWrite tells the driver to use a connection to 'Leader' - AccessModeWrite AccessMode = 0 - // AccessModeRead tells the driver to use a connection to one of the 'Follower' or 'Read Replica'. - AccessModeRead AccessMode = 1 -) // DriverWithContext represents a pool of connections to a neo4j server or cluster. It's // safe for concurrent use. @@ -59,13 +54,13 @@ type DriverWithContext interface { // // [...] do something with results and error // bookmarkManager := driver.ExecuteQueryBookmarkManager() // // maintain consistency with sessions as well - // session := driver.NewSession(ctx, neo4j.SessionConfig {BookmarkManager: bookmarkManager}) + // session := driver.NewSession(ctx, config.SessionConfig {BookmarkManager: bookmarkManager}) // // [...] run something within the session - ExecuteQueryBookmarkManager() BookmarkManager + ExecuteQueryBookmarkManager() bm.BookmarkManager // Target returns the url this driver is bootstrapped Target() url.URL // NewSession creates a new session based on the specified session configuration. - NewSession(ctx context.Context, config SessionConfig) SessionWithContext + NewSession(ctx context.Context, config config.SessionConfig) SessionWithContext // VerifyConnectivity checks that the driver can connect to a remote server or cluster by // establishing a network connection with the remote. Returns nil if successful // or error describing the problem. @@ -322,7 +317,7 @@ type driverWithContext struct { executeQueryBookmarkManagerInitializer sync.Once // instance of the bookmark manager only used by default by managed sessions of ExecuteQuery // this is *not* used by default by user-created session (see NewSession) - executeQueryBookmarkManager BookmarkManager + executeQueryBookmarkManager bm.BookmarkManager auth auth.TokenManager now func() time.Time } @@ -331,7 +326,7 @@ func (d *driverWithContext) Target() url.URL { return *d.target } -func (d *driverWithContext) NewSession(ctx context.Context, config SessionConfig) SessionWithContext { +func (d *driverWithContext) NewSession(ctx context.Context, config config.SessionConfig) SessionWithContext { if config.DatabaseName == "" { config.DatabaseName = idb.DefaultDatabase } @@ -341,13 +336,13 @@ func (d *driverWithContext) NewSession(ctx context.Context, config SessionConfig reAuthToken = &idb.ReAuthToken{ Manager: d.auth, FromSession: false, - ForceReAuth: config.forceReAuth, + ForceReAuth: config.ForceReAuth, } } else { reAuthToken = &idb.ReAuthToken{ Manager: config.Auth, FromSession: true, - ForceReAuth: config.forceReAuth, + ForceReAuth: config.ForceReAuth, } } @@ -373,7 +368,7 @@ func (d *driverWithContext) IsEncrypted() bool { } func (d *driverWithContext) GetServerInfo(ctx context.Context) (_ ServerInfo, err error) { - session := d.NewSession(ctx, SessionConfig{}) + session := d.NewSession(ctx, config.SessionConfig{}) defer func() { err = deferredClose(ctx, session, err) }() @@ -395,7 +390,7 @@ func (d *driverWithContext) Close(ctx context.Context) error { } func (d *driverWithContext) VerifyAuthentication(ctx context.Context, auth *AuthToken) (err error) { - session := d.NewSession(ctx, SessionConfig{Auth: auth, forceReAuth: true, DatabaseName: "system"}) + session := d.NewSession(ctx, config.SessionConfig{Auth: auth, ForceReAuth: true, DatabaseName: "system"}) defer func() { err = deferredClose(ctx, session, err) }() @@ -470,7 +465,7 @@ func (d *driverWithContext) VerifyAuthentication(ctx context.Context, auth *Auth // The equivalent functionality of ExecuteQuery can be replicated with pre-existing APIs as follows: // // // all the error handling bits have been omitted for brevity (do not do this in production!) -// session := driver.NewSession(ctx, neo4j.SessionConfig{ +// session := driver.NewSession(ctx, config.SessionConfig{ // DatabaseName: "", // ImpersonatedUser: "", // BookmarkManager: bookmarkManager, @@ -542,10 +537,10 @@ func ExecuteQuery[T any]( return result.(T), err } -func (d *driverWithContext) ExecuteQueryBookmarkManager() BookmarkManager { +func (d *driverWithContext) ExecuteQueryBookmarkManager() bm.BookmarkManager { d.executeQueryBookmarkManagerInitializer.Do(func() { if d.executeQueryBookmarkManager == nil { // this allows tests to init the field themselves - d.executeQueryBookmarkManager = NewBookmarkManager(BookmarkManagerConfig{}) + d.executeQueryBookmarkManager = bm.NewBookmarkManager(bm.BookmarkManagerConfig{}) } }) return d.executeQueryBookmarkManager @@ -640,7 +635,7 @@ func ExecuteQueryWithDatabase(db string) ExecuteQueryConfigurationOption { } // ExecuteQueryWithBookmarkManager configures DriverWithContext.ExecuteQuery to rely on the specified BookmarkManager -func ExecuteQueryWithBookmarkManager(bookmarkManager BookmarkManager) ExecuteQueryConfigurationOption { +func ExecuteQueryWithBookmarkManager(bookmarkManager bm.BookmarkManager) ExecuteQueryConfigurationOption { return func(configuration *ExecuteQueryConfiguration) { configuration.BookmarkManager = bookmarkManager } @@ -665,7 +660,7 @@ type ExecuteQueryConfiguration struct { Routing RoutingControl ImpersonatedUser string Database string - BookmarkManager BookmarkManager + BookmarkManager bm.BookmarkManager BoltLogger log.BoltLogger } @@ -679,8 +674,8 @@ const ( Read ) -func (c *ExecuteQueryConfiguration) toSessionConfig() SessionConfig { - return SessionConfig{ +func (c *ExecuteQueryConfiguration) toSessionConfig() config.SessionConfig { + return config.SessionConfig{ ImpersonatedUser: c.ImpersonatedUser, DatabaseName: c.Database, BookmarkManager: c.BookmarkManager, @@ -688,7 +683,7 @@ func (c *ExecuteQueryConfiguration) toSessionConfig() SessionConfig { } } -type transactionFunction func(context.Context, ManagedTransactionWork, ...func(*TransactionConfig)) (any, error) +type transactionFunction func(context.Context, ManagedTransactionWork, ...func(*config.TransactionConfig)) (any, error) func (c *ExecuteQueryConfiguration) selectTxFunctionApi(session SessionWithContext) (transactionFunction, error) { switch c.Routing { diff --git a/neo4j/driver_with_context_examples_test.go b/neo4j/driver_with_context_examples_test.go index e3854091..01822624 100644 --- a/neo4j/driver_with_context_examples_test.go +++ b/neo4j/driver_with_context_examples_test.go @@ -21,6 +21,8 @@ import ( "context" "errors" "fmt" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) var myDriver DriverWithContext @@ -82,7 +84,7 @@ func ExampleExecuteQuery_defaultBookmarkManagerExplicitReuse() { // retrieve the default bookmark manager used by the previous call (since there was no bookmark manager explicitly // configured) bookmarkManager := myDriver.ExecuteQueryBookmarkManager() - session := myDriver.NewSession(ctx, SessionConfig{BookmarkManager: bookmarkManager}) + session := myDriver.NewSession(ctx, config.SessionConfig{BookmarkManager: bookmarkManager}) // the following transaction function is guaranteed to see the result of the previous query // since the session uses the same bookmark manager as the previous ExecuteQuery call and targets the same diff --git a/neo4j/driver_with_context_test.go b/neo4j/driver_with_context_test.go index 1b556f37..f2092582 100644 --- a/neo4j/driver_with_context_test.go +++ b/neo4j/driver_with_context_test.go @@ -21,14 +21,17 @@ import ( "context" "errors" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing" - . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" "net/url" "sync" "sync/atomic" "testing" "time" "unsafe" + + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/racing" + . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" ) func TestDriverExecuteQuery(outer *testing.T) { @@ -42,7 +45,7 @@ func TestDriverExecuteQuery(outer *testing.T) { summary := &fakeSummary{resultAvailableAfter: 42 * time.Millisecond} defaultBookmarkManager := &fakeBookmarkManager{} customBookmarkManager := &fakeBookmarkManager{} - defaultSessionConfig := SessionConfig{BookmarkManager: defaultBookmarkManager} + defaultSessionConfig := config.SessionConfig{BookmarkManager: defaultBookmarkManager} outer.Run("nil driver is not allowed", func(t *testing.T) { _, err := ExecuteQuery(ctx, nil, "RETURN 42", nil, EagerResultTransformer) @@ -55,7 +58,7 @@ func TestDriverExecuteQuery(outer *testing.T) { resultTransformer func() ResultTransformer[T] configurers []ExecuteQueryConfigurationOption createSession *fakeSession - expectedSessionConfig SessionConfig + expectedSessionConfig config.SessionConfig expectedResult T expectedErr error } @@ -88,7 +91,7 @@ func TestDriverExecuteQuery(outer *testing.T) { nextRecords: records, summary: summary, }}, - expectedSessionConfig: SessionConfig{ImpersonatedUser: "jane", BookmarkManager: defaultBookmarkManager}, + expectedSessionConfig: config.SessionConfig{ImpersonatedUser: "jane", BookmarkManager: defaultBookmarkManager}, expectedResult: &EagerResult{ Keys: keys, Records: records, @@ -106,7 +109,7 @@ func TestDriverExecuteQuery(outer *testing.T) { nextRecords: records, summary: summary, }}, - expectedSessionConfig: SessionConfig{DatabaseName: "imdb", BookmarkManager: defaultBookmarkManager}, + expectedSessionConfig: config.SessionConfig{DatabaseName: "imdb", BookmarkManager: defaultBookmarkManager}, expectedResult: &EagerResult{ Keys: keys, Records: records, @@ -124,7 +127,7 @@ func TestDriverExecuteQuery(outer *testing.T) { nextRecords: records, summary: summary, }}, - expectedSessionConfig: SessionConfig{BookmarkManager: customBookmarkManager}, + expectedSessionConfig: config.SessionConfig{BookmarkManager: customBookmarkManager}, expectedResult: &EagerResult{ Keys: keys, Records: records, @@ -142,7 +145,7 @@ func TestDriverExecuteQuery(outer *testing.T) { nextRecords: records, summary: summary, }}, - expectedSessionConfig: SessionConfig{BookmarkManager: nil}, + expectedSessionConfig: config.SessionConfig{BookmarkManager: nil}, expectedResult: &EagerResult{ Keys: keys, Records: records, @@ -409,7 +412,7 @@ func TestDriverExecuteQuery(outer *testing.T) { for _, testCase := range testCases { outer.Run(testCase.description, func(t *testing.T) { driver := &driverDelegate{ - newSession: func(_ context.Context, config SessionConfig) SessionWithContext { + newSession: func(_ context.Context, config config.SessionConfig) SessionWithContext { AssertDeepEquals(t, testCase.expectedSessionConfig, config) return testCase.createSession }, @@ -429,7 +432,7 @@ func TestDriverExecuteQuery(outer *testing.T) { outer.Run("default bookmark manager is thread-safe", func(t *testing.T) { driver := &driverDelegate{ - newSession: func(_ context.Context, config SessionConfig) SessionWithContext { + newSession: func(_ context.Context, config config.SessionConfig) SessionWithContext { return &fakeSession{ executeWriteErr: fmt.Errorf("oopsie, write failed"), } @@ -448,7 +451,7 @@ func TestDriverExecuteQuery(outer *testing.T) { callExecuteQueryOrBookmarkManagerGetter(driver, i) storeBookmarkManagerAddress( &bookmarkManagerAddresses, - driver.delegate.executeQueryBookmarkManager.(*bookmarkManager)) + driver.delegate.executeQueryBookmarkManager.(*bm.DefaultBookmarkManager)) wait.Done() }(i) } @@ -462,7 +465,7 @@ func TestDriverExecuteQuery(outer *testing.T) { if len(addressCounts) != 1 { t.Errorf("expected exactly 1 bookmark manager pointer to have been created, got %v", addressCounts) } - address := uintptr(unsafe.Pointer(driver.delegate.executeQueryBookmarkManager.(*bookmarkManager))) + address := uintptr(unsafe.Pointer(driver.delegate.executeQueryBookmarkManager.(*bm.DefaultBookmarkManager))) if count, found := addressCounts[address]; !found || count != int32(goroutineCount) { t.Errorf("expected pointer address %v to be seen %d time(s), got these instead %v", address, count, addressCounts) } @@ -479,7 +482,7 @@ func callExecuteQueryOrBookmarkManagerGetter(driver DriverWithContext, i int) { } } -func storeBookmarkManagerAddress(bookmarkManagerAddresses *sync.Map, bookmarkMgr *bookmarkManager) { +func storeBookmarkManagerAddress(bookmarkManagerAddresses *sync.Map, bookmarkMgr *bm.DefaultBookmarkManager) { address := uintptr(unsafe.Pointer(bookmarkMgr)) defaultCount := int32(1) if count, loaded := bookmarkManagerAddresses.LoadOrStore(address, &defaultCount); loaded { @@ -514,10 +517,10 @@ func (f *failingResultTransformer) Complete([]string, ResultSummary) (*EagerResu type driverDelegate struct { delegate *driverWithContext - newSession func(context.Context, SessionConfig) SessionWithContext + newSession func(context.Context, config.SessionConfig) SessionWithContext } -func (d *driverDelegate) ExecuteQueryBookmarkManager() BookmarkManager { +func (d *driverDelegate) ExecuteQueryBookmarkManager() bm.BookmarkManager { return d.delegate.ExecuteQueryBookmarkManager() } @@ -525,7 +528,7 @@ func (d *driverDelegate) Target() url.URL { return d.delegate.Target() } -func (d *driverDelegate) NewSession(ctx context.Context, config SessionConfig) SessionWithContext { +func (d *driverDelegate) NewSession(ctx context.Context, config config.SessionConfig) SessionWithContext { return d.newSession(ctx, config) } @@ -560,7 +563,7 @@ type fakeSession struct { closeErr error } -func (s *fakeSession) LastBookmarks() Bookmarks { +func (s *fakeSession) LastBookmarks() bm.Bookmarks { panic("implement me") } @@ -568,18 +571,18 @@ func (s *fakeSession) lastBookmark() string { panic("implement me") } -func (s *fakeSession) BeginTransaction(context.Context, ...func(*TransactionConfig)) (ExplicitTransaction, error) { +func (s *fakeSession) BeginTransaction(context.Context, ...func(*config.TransactionConfig)) (ExplicitTransaction, error) { panic("implement me") } -func (s *fakeSession) ExecuteRead(_ context.Context, callback ManagedTransactionWork, _ ...func(*TransactionConfig)) (any, error) { +func (s *fakeSession) ExecuteRead(_ context.Context, callback ManagedTransactionWork, _ ...func(*config.TransactionConfig)) (any, error) { return callback(&fakeManagedTransaction{ result: s.executeReadTransactionResult, err: s.executeReadErr, }) } -func (s *fakeSession) ExecuteWrite(_ context.Context, callback ManagedTransactionWork, _ ...func(*TransactionConfig)) (any, error) { +func (s *fakeSession) ExecuteWrite(_ context.Context, callback ManagedTransactionWork, _ ...func(*config.TransactionConfig)) (any, error) { result := s.executeWriteTransactionResult err := s.executeWriteErr if s.executeWriteErrs != nil { @@ -589,14 +592,14 @@ func (s *fakeSession) ExecuteWrite(_ context.Context, callback ManagedTransactio } return callback(&fakeManagedTransaction{result: result, err: err}) } -func (s *fakeSession) executeQueryRead(_ context.Context, callback ManagedTransactionWork, _ ...func(*TransactionConfig)) (any, error) { +func (s *fakeSession) executeQueryRead(_ context.Context, callback ManagedTransactionWork, _ ...func(*config.TransactionConfig)) (any, error) { return callback(&fakeManagedTransaction{ result: s.executeReadTransactionResult, err: s.executeReadErr, }) } -func (s *fakeSession) executeQueryWrite(_ context.Context, callback ManagedTransactionWork, _ ...func(*TransactionConfig)) (any, error) { +func (s *fakeSession) executeQueryWrite(_ context.Context, callback ManagedTransactionWork, _ ...func(*config.TransactionConfig)) (any, error) { result := s.executeWriteTransactionResult err := s.executeWriteErr if s.executeWriteErrs != nil { @@ -606,7 +609,7 @@ func (s *fakeSession) executeQueryWrite(_ context.Context, callback ManagedTrans } return callback(&fakeManagedTransaction{result: result, err: err}) } -func (s *fakeSession) Run(context.Context, string, map[string]any, ...func(*TransactionConfig)) (ResultWithContext, error) { +func (s *fakeSession) Run(context.Context, string, map[string]any, ...func(*config.TransactionConfig)) (ResultWithContext, error) { panic("implement me") } diff --git a/neo4j/graph_example_test.go b/neo4j/graph_example_test.go index 4ce5865f..9463b9dd 100644 --- a/neo4j/graph_example_test.go +++ b/neo4j/graph_example_test.go @@ -20,7 +20,9 @@ package neo4j_test import ( "context" "fmt" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) func ExampleGetProperty() { @@ -28,7 +30,7 @@ func ExampleGetProperty() { driver, err := createDriver() handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer handleClose(ctx, session) result, err := session.Run(ctx, "MATCH (p:Person) RETURN p LIMIT 1", nil) diff --git a/neo4j/graph_test.go b/neo4j/graph_test.go index 98219c79..e0f048bf 100644 --- a/neo4j/graph_test.go +++ b/neo4j/graph_test.go @@ -19,11 +19,12 @@ package neo4j_test import ( "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" "testing" "testing/quick" "time" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" ) func TestGetProperty(outer *testing.T) { diff --git a/neo4j/notifications/notifications.go b/neo4j/notifications/notifications.go index 1252e59e..3838f553 100644 --- a/neo4j/notifications/notifications.go +++ b/neo4j/notifications/notifications.go @@ -44,7 +44,7 @@ func DisableCategories(value ...NotificationCategory) NotificationDisabledCatego } // DisableNoCategories creates a NotificationDisabledCategories that enables all categories. -// Can be used for NotificationsDisabledCategories of neo4j.Config and neo4j.SessionConfig. +// Can be used for NotificationsDisabledCategories of neo4j.Config and config.SessionConfig. func DisableNoCategories() NotificationDisabledCategories { return NotificationDisabledCategories{nil, true} } diff --git a/neo4j/notifications_examples_test.go b/neo4j/notifications_examples_test.go index 4b772127..dcc1eb68 100644 --- a/neo4j/notifications_examples_test.go +++ b/neo4j/notifications_examples_test.go @@ -20,8 +20,10 @@ package neo4j import ( "context" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" "os" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" ) func ExampleConfig_disableNoCategories() { @@ -49,7 +51,7 @@ func ExampleSessionConfig_disableNoCategories() { handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, SessionConfig{ + session := driver.NewSession(ctx, config.SessionConfig{ // makes the server return all notification categories // this overrides the driver level configuration of the same name NotificationsDisabledCategories: notifications.DisableNoCategories(), @@ -94,7 +96,7 @@ func ExampleSessionConfig_disableSomeCategories() { handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, SessionConfig{ + session := driver.NewSession(ctx, config.SessionConfig{ // makes the server return all notification categories but deprecations // this overrides the driver level configuration of the same name NotificationsDisabledCategories: notifications.DisableCategories(notifications.Deprecation), @@ -140,7 +142,7 @@ func ExampleSessionConfig_minimumSeverityLevel() { handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, SessionConfig{ + session := driver.NewSession(ctx, config.SessionConfig{ // makes the server return only notifications with severity level warning or higher // this overrides the driver level configuration of the same name NotificationsMinSeverity: notifications.WarningLevel, diff --git a/neo4j/record_example_test.go b/neo4j/record_example_test.go index 8499e5bd..84c017b4 100644 --- a/neo4j/record_example_test.go +++ b/neo4j/record_example_test.go @@ -20,7 +20,9 @@ package neo4j_test import ( "context" "fmt" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) func ExampleGetRecordValue() { @@ -28,7 +30,7 @@ func ExampleGetRecordValue() { driver, err := createDriver() handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer handleClose(ctx, session) result, err := session.Run(ctx, "MATCH (p:Person) RETURN p LIMIT 1", nil) diff --git a/neo4j/session.go b/neo4j/session.go index 40dd3844..c6b5e93e 100644 --- a/neo4j/session.go +++ b/neo4j/session.go @@ -19,6 +19,9 @@ package neo4j import ( "context" + + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) // Session represents a logical connection (which is not tied to a physical connection) @@ -32,7 +35,7 @@ type Session interface { // LastBookmarks returns the bookmark received following the last successfully completed transaction. // If no bookmark was received or if this transaction was rolled back, the initial set of bookmarks will be // returned. - LastBookmarks() Bookmarks + LastBookmarks() bm.Bookmarks // LastBookmark returns the bookmark received following the last successfully completed transaction. // If no bookmark was received or if this transaction was rolled back, the bookmark value will not be changed. // Warning: this method can lead to unexpected behaviour if the session has not yet successfully completed a @@ -41,15 +44,15 @@ type Session interface { // Deprecated: since version 5.0. Will be removed in 6.0. Use LastBookmarks instead. LastBookmark() string // BeginTransaction starts a new explicit transaction on this session - BeginTransaction(configurers ...func(*TransactionConfig)) (Transaction, error) + BeginTransaction(configurers ...func(*config.TransactionConfig)) (Transaction, error) // ReadTransaction executes the given unit of work in a AccessModeRead transaction with // retry logic in place - ReadTransaction(work TransactionWork, configurers ...func(*TransactionConfig)) (any, error) + ReadTransaction(work TransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) // WriteTransaction executes the given unit of work in a AccessModeWrite transaction with // retry logic in place - WriteTransaction(work TransactionWork, configurers ...func(*TransactionConfig)) (any, error) + WriteTransaction(work TransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) // Run executes an auto-commit statement and returns a result - Run(cypher string, params map[string]any, configurers ...func(*TransactionConfig)) (Result, error) + Run(cypher string, params map[string]any, configurers ...func(*config.TransactionConfig)) (Result, error) // Close closes any open resources and marks this session as unusable Close() error } @@ -58,7 +61,7 @@ type session struct { delegate *sessionWithContext } -func (s *session) LastBookmarks() Bookmarks { +func (s *session) LastBookmarks() bm.Bookmarks { return s.delegate.LastBookmarks() } @@ -66,7 +69,7 @@ func (s *session) LastBookmark() string { return s.delegate.lastBookmark() } -func (s *session) BeginTransaction(configurers ...func(*TransactionConfig)) (Transaction, error) { +func (s *session) BeginTransaction(configurers ...func(*config.TransactionConfig)) (Transaction, error) { tx, err := s.delegate.BeginTransaction(context.Background(), configurers...) if err != nil { return nil, err @@ -75,7 +78,7 @@ func (s *session) BeginTransaction(configurers ...func(*TransactionConfig)) (Tra } func (s *session) ReadTransaction( - work TransactionWork, configurers ...func(*TransactionConfig)) (any, error) { + work TransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) { return s.delegate.ExecuteRead( context.Background(), @@ -85,7 +88,7 @@ func (s *session) ReadTransaction( } func (s *session) WriteTransaction( - work TransactionWork, configurers ...func(*TransactionConfig)) (any, error) { + work TransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) { return s.delegate.ExecuteWrite( context.Background(), @@ -95,7 +98,7 @@ func (s *session) WriteTransaction( } func (s *session) Run( - cypher string, params map[string]any, configurers ...func(*TransactionConfig)) (Result, error) { + cypher string, params map[string]any, configurers ...func(*config.TransactionConfig)) (Result, error) { result, err := s.delegate.Run(context.Background(), cypher, params, configurers...) if err != nil { @@ -122,20 +125,20 @@ func (s *erroredSession) LastBookmark() string { return "" } -func (s *erroredSession) LastBookmarks() Bookmarks { +func (s *erroredSession) LastBookmarks() bm.Bookmarks { return []string{} } -func (s *erroredSession) BeginTransaction(...func(*TransactionConfig)) (Transaction, error) { +func (s *erroredSession) BeginTransaction(...func(*config.TransactionConfig)) (Transaction, error) { return nil, s.err } -func (s *erroredSession) ReadTransaction(TransactionWork, ...func(*TransactionConfig)) (any, error) { +func (s *erroredSession) ReadTransaction(TransactionWork, ...func(*config.TransactionConfig)) (any, error) { return nil, s.err } -func (s *erroredSession) WriteTransaction(TransactionWork, ...func(*TransactionConfig)) (any, error) { +func (s *erroredSession) WriteTransaction(TransactionWork, ...func(*config.TransactionConfig)) (any, error) { return nil, s.err } -func (s *erroredSession) Run(string, map[string]any, ...func(*TransactionConfig)) (Result, error) { +func (s *erroredSession) Run(string, map[string]any, ...func(*config.TransactionConfig)) (Result, error) { return nil, s.err } func (s *erroredSession) Close() error { diff --git a/neo4j/session_bookmarks.go b/neo4j/session_bookmarks.go index d877109c..f96645e6 100644 --- a/neo4j/session_bookmarks.go +++ b/neo4j/session_bookmarks.go @@ -17,21 +17,25 @@ package neo4j -import "context" +import ( + "context" + + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" +) type sessionBookmarks struct { - bookmarkManager BookmarkManager - bookmarks Bookmarks + bookmarkManager bm.BookmarkManager + bookmarks bm.Bookmarks } -func newSessionBookmarks(bookmarkManager BookmarkManager, bookmarks Bookmarks) *sessionBookmarks { +func newSessionBookmarks(bookmarkManager bm.BookmarkManager, bookmarks bm.Bookmarks) *sessionBookmarks { return &sessionBookmarks{ bookmarkManager: bookmarkManager, bookmarks: cleanupBookmarks(bookmarks), } } -func (sb *sessionBookmarks) currentBookmarks() Bookmarks { +func (sb *sessionBookmarks) currentBookmarks() bm.Bookmarks { return sb.bookmarks } @@ -64,7 +68,7 @@ func (sb *sessionBookmarks) replaceSessionBookmarks(newBookmark string) { sb.bookmarks = []string{newBookmark} } -func (sb *sessionBookmarks) getBookmarks(ctx context.Context) (Bookmarks, error) { +func (sb *sessionBookmarks) getBookmarks(ctx context.Context) (bm.Bookmarks, error) { if sb.bookmarkManager == nil { return nil, nil } @@ -73,7 +77,7 @@ func (sb *sessionBookmarks) getBookmarks(ctx context.Context) (Bookmarks, error) // Remove empty string bookmarks to check for "bad" callers // To avoid allocating, first check if this is a problem -func cleanupBookmarks(bookmarks Bookmarks) Bookmarks { +func cleanupBookmarks(bookmarks bm.Bookmarks) bm.Bookmarks { hasBad := false for _, b := range bookmarks { if len(b) == 0 { @@ -86,7 +90,7 @@ func cleanupBookmarks(bookmarks Bookmarks) Bookmarks { return bookmarks } - cleaned := make(Bookmarks, 0, len(bookmarks)-1) + cleaned := make(bm.Bookmarks, 0, len(bookmarks)-1) for _, b := range bookmarks { if len(b) > 0 { cleaned = append(cleaned, b) diff --git a/neo4j/session_bookmarks_test.go b/neo4j/session_bookmarks_test.go index fee363e1..c56ce6c2 100644 --- a/neo4j/session_bookmarks_test.go +++ b/neo4j/session_bookmarks_test.go @@ -21,6 +21,8 @@ import ( "context" "reflect" "testing" + + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" ) func TestSessionBookmarks(outer *testing.T) { @@ -130,7 +132,7 @@ type fakeBookmarkManager struct { recordedCalls []invocation } -func (f *fakeBookmarkManager) UpdateBookmarks(ctx context.Context, previousBookmarks, newBookmarks Bookmarks) error { +func (f *fakeBookmarkManager) UpdateBookmarks(ctx context.Context, previousBookmarks, newBookmarks bm.Bookmarks) error { f.recordedCalls = append(f.recordedCalls, invocation{ function: "UpdateBookmarks", arguments: []any{ctx, previousBookmarks, newBookmarks}, @@ -138,7 +140,7 @@ func (f *fakeBookmarkManager) UpdateBookmarks(ctx context.Context, previousBookm return nil } -func (f *fakeBookmarkManager) GetBookmarks(ctx context.Context) (Bookmarks, error) { +func (f *fakeBookmarkManager) GetBookmarks(ctx context.Context) (bm.Bookmarks, error) { f.recordedCalls = append(f.recordedCalls, invocation{ function: "GetBookmarks", arguments: []any{ctx}, @@ -146,7 +148,7 @@ func (f *fakeBookmarkManager) GetBookmarks(ctx context.Context) (Bookmarks, erro return nil, nil } -func (f *fakeBookmarkManager) GetAllBookmarks(ctx context.Context) (Bookmarks, error) { +func (f *fakeBookmarkManager) GetAllBookmarks(ctx context.Context) (bm.Bookmarks, error) { f.recordedCalls = append(f.recordedCalls, invocation{ function: "GetAllBookmarks", arguments: []any{ctx}, diff --git a/neo4j/session_with_context.go b/neo4j/session_with_context.go index 1e2533a4..d50f3a4f 100644 --- a/neo4j/session_with_context.go +++ b/neo4j/session_with_context.go @@ -20,14 +20,16 @@ package neo4j import ( "context" "fmt" + "math" + "time" + + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/collections" idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/pool" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/telemetry" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" - "math" - "time" "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/retry" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" @@ -51,133 +53,32 @@ type SessionWithContext interface { // LastBookmarks returns the bookmark received following the last successfully completed transaction. // If no bookmark was received or if this transaction was rolled back, the initial set of bookmarks will be // returned. - LastBookmarks() Bookmarks + LastBookmarks() bm.Bookmarks lastBookmark() string // BeginTransaction starts a new explicit transaction on this session // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. - BeginTransaction(ctx context.Context, configurers ...func(*TransactionConfig)) (ExplicitTransaction, error) + BeginTransaction(ctx context.Context, configurers ...func(*config.TransactionConfig)) (ExplicitTransaction, error) // ExecuteRead executes the given unit of work in a AccessModeRead transaction with // retry logic in place // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. - ExecuteRead(ctx context.Context, work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) + ExecuteRead(ctx context.Context, work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) // ExecuteWrite executes the given unit of work in a AccessModeWrite transaction with // retry logic in place // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. - ExecuteWrite(ctx context.Context, work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) + ExecuteWrite(ctx context.Context, work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) // Run executes an auto-commit statement and returns a result // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. - Run(ctx context.Context, cypher string, params map[string]any, configurers ...func(*TransactionConfig)) (ResultWithContext, error) + Run(ctx context.Context, cypher string, params map[string]any, configurers ...func(*config.TransactionConfig)) (ResultWithContext, error) // Close closes any open resources and marks this session as unusable // Contexts terminating too early negatively affect connection pooling and degrade the driver performance. Close(ctx context.Context) error - executeQueryRead(ctx context.Context, work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) - executeQueryWrite(ctx context.Context, work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) + executeQueryRead(ctx context.Context, work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) + executeQueryWrite(ctx context.Context, work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) legacy() Session getServerInfo(ctx context.Context) (ServerInfo, error) verifyAuthentication(ctx context.Context) error } -// SessionConfig is used to configure a new session, its zero value uses safe defaults. -type SessionConfig struct { - // AccessMode used when using Session.Run and explicit transactions. Used to route query - // to read or write servers when running in a cluster. Session.ReadTransaction and Session.WriteTransaction - // does not rely on this mode. - AccessMode AccessMode - // Bookmarks are the initial bookmarks used to ensure that the executing server is at least up - // to date to the point represented by the latest of the provided bookmarks. After running commands - // on the session the bookmark can be retrieved with Session.LastBookmark. All commands executing - // within the same session will automatically use the bookmark from the previous command in the - // session. - Bookmarks Bookmarks - // DatabaseName sets the target database name for the queries executed within the session created with this - // configuration. - // Usage of Cypher clauses like USE is not a replacement for this option. - // Drive​r sends Cypher to the server for processing. - // This option has no explicit value by default, but it is recommended to set one if the target database is known - // in advance. This has the benefit of ensuring a consistent target database name throughout the session in a - // straightforward way and potentially simplifies driver logic as well as reduces network communication resulting - // in better performance. - // When no explicit name is set, the driver behavior depends on the connection URI scheme supplied to the driver on - // instantiation and Bolt protocol version. - // - // Specifically, the following applies: - // - // - for bolt schemes - // queries are dispatched to the server for execution without explicit database name supplied, - // meaning that the target database name for query execution is determined by the server. - // It is important to note that the target database may change (even within the same session), for instance if the - // user's home database is changed on the server. - // - // - for neo4j schemes - // providing that Bolt protocol version 4.4, which was introduced with Neo4j server 4.4, or above - // is available, the driver fetches the user's home database name from the server on first query execution - // within the session and uses the fetched database name explicitly for all queries executed within the session. - // This ensures that the database name remains consistent within the given session. For instance, if the user's - // home database name is 'movies' and the server supplies it to the driver upon database name fetching for the - // session, all queries within that session are executed with the explicit database name 'movies' supplied. - // Any change to the user’s home database is reflected only in sessions created after such change takes effect. - // This behavior requires additional network communication. - // In clustered environments, it is strongly recommended to avoid a single point of failure. - // For instance, by ensuring that the connection URI resolves to multiple endpoints. - // For older Bolt protocol versions, the behavior is the same as described for the bolt schemes above. - DatabaseName string - // FetchSize defines how many records to pull from server in each batch. - // From Bolt protocol v4 (Neo4j 4+) records can be fetched in batches as compared to fetching - // all in previous versions. - // - // If FetchSize is set to FetchDefault, the driver decides the appropriate size. If set to a positive value - // that size is used if the underlying protocol supports it otherwise it is ignored. - // - // To turn off fetching in batches and always fetch everything, set FetchSize to FetchAll. - // If a single large result is to be retrieved this is the most performant setting. - FetchSize int - // Logging target the session will send its Bolt message traces - // - // Possible to use custom logger (implement log.BoltLogger interface) or - // use neo4j.ConsoleBoltLogger. - BoltLogger log.BoltLogger - // ImpersonatedUser sets the Neo4j user that the session will be acting as. - // If not set, the user configured for the driver will be used. - // - // If user impersonation is used, the default database for that impersonated - // user will be used unless DatabaseName is set. - // - // In the former case, when routing is enabled, using impersonation - // without DatabaseName will cause the driver to query the - // cluster for the name of the default database of the impersonated user. - // This is done at the beginning of the session so that queries are routed - // to the correct cluster member (different databases may have different - // leaders). - ImpersonatedUser string - // BookmarkManager defines a central point to externally supply bookmarks - // and be notified of bookmark updates per database - // Since 5.0 - // default: nil (no-op) - BookmarkManager BookmarkManager - // NotificationsMinSeverity defines the minimum severity level of notifications the server should send. - // By default, the driver's settings are used. - // Else, this option overrides the driver's settings. - // Disabling severities allows the server to skip analysis for those, which can speed up query execution. - NotificationsMinSeverity notifications.NotificationMinimumSeverityLevel - // NotificationsDisabledCategories defines the categories of notifications the server should not send. - // By default, the driver's settings are used. - // Else, this option overrides the driver's settings. - // Disabling categories allows the server to skip analysis for those, which can speed up query execution. - NotificationsDisabledCategories notifications.NotificationDisabledCategories - // Auth is used to overwrite the authentication information for the session. - // This requires the server to support re-authentication on the protocol level. - // `nil` will make the driver use the authentication information from the driver configuration. - // The `neo4j` package provides factory functions for common authentication schemes: - // - `neo4j.NoAuth` - // - `neo4j.BasicAuth` - // - `neo4j.KerberosAuth` - // - `neo4j.BearerAuth` - // - `neo4j.CustomAuth` - Auth *AuthToken - - forceReAuth bool -} - // FetchAll turns off fetching records in batches. const FetchAll = -1 @@ -207,13 +108,13 @@ type sessionWithContext struct { log log.Logger throttleTime time.Duration fetchSize int - config SessionConfig + config config.SessionConfig auth *idb.ReAuthToken } func newSessionWithContext( config *Config, - sessConfig SessionConfig, + sessConfig config.SessionConfig, router sessionRouter, pool sessionPool, logger log.Logger, @@ -263,7 +164,7 @@ func (s *sessionWithContext) lastBookmark() string { return s.bookmarks.lastBookmark() } -func (s *sessionWithContext) LastBookmarks() Bookmarks { +func (s *sessionWithContext) LastBookmarks() bm.Bookmarks { // Pick up bookmark from pending auto-commit if there is a bookmark on it // Note: the bookmark manager should not be notified here because: // - the results of the autocommit transaction may have not been consumed @@ -280,7 +181,7 @@ func (s *sessionWithContext) LastBookmarks() Bookmarks { return s.bookmarks.currentBookmarks() } -func (s *sessionWithContext) BeginTransaction(ctx context.Context, configurers ...func(*TransactionConfig)) (ExplicitTransaction, error) { +func (s *sessionWithContext) BeginTransaction(ctx context.Context, configurers ...func(*config.TransactionConfig)) (ExplicitTransaction, error) { // Guard for more than one transaction per session if s.explicitTx != nil { err := &UsageError{Message: "Session already has a pending transaction"} @@ -362,25 +263,25 @@ func (s *sessionWithContext) BeginTransaction(ctx context.Context, configurers . } func (s *sessionWithContext) ExecuteRead(ctx context.Context, - work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) { + work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) { return s.runRetriable(ctx, idb.ReadMode, work, true, telemetry.ManagedTransaction, configurers...) } func (s *sessionWithContext) ExecuteWrite(ctx context.Context, - work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) { + work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) { return s.runRetriable(ctx, idb.WriteMode, work, true, telemetry.ManagedTransaction, configurers...) } func (s *sessionWithContext) executeQueryRead(ctx context.Context, - work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) { + work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) { return s.runRetriable(ctx, idb.ReadMode, work, false, telemetry.ExecuteQuery, configurers...) } func (s *sessionWithContext) executeQueryWrite(ctx context.Context, - work ManagedTransactionWork, configurers ...func(*TransactionConfig)) (any, error) { + work ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) (any, error) { return s.runRetriable(ctx, idb.WriteMode, work, false, telemetry.ExecuteQuery, configurers...) } @@ -391,7 +292,7 @@ func (s *sessionWithContext) runRetriable( work ManagedTransactionWork, blockingTxBegin bool, api telemetry.API, - configurers ...func(*TransactionConfig)) (any, error) { + configurers ...func(*config.TransactionConfig)) (any, error) { // Guard for more than one transaction per session if s.explicitTx != nil { @@ -436,7 +337,7 @@ func (s *sessionWithContext) runRetriable( func (s *sessionWithContext) executeTransactionFunction( ctx context.Context, mode idb.AccessMode, - config TransactionConfig, + config config.TransactionConfig, state *retry.State, work ManagedTransactionWork, blockingTxBegin bool, @@ -571,7 +472,7 @@ func (s *sessionWithContext) getConnection(ctx context.Context, mode idb.AccessM return conn, nil } -func (s *sessionWithContext) retrieveBookmarks(ctx context.Context, conn idb.Connection, sentBookmarks Bookmarks) error { +func (s *sessionWithContext) retrieveBookmarks(ctx context.Context, conn idb.Connection, sentBookmarks bm.Bookmarks) error { if conn == nil { return nil } @@ -586,7 +487,7 @@ func (s *sessionWithContext) retrieveSessionBookmarks(conn idb.Connection) { } func (s *sessionWithContext) Run(ctx context.Context, - cypher string, params map[string]any, configurers ...func(*TransactionConfig)) (ResultWithContext, error) { + cypher string, params map[string]any, configurers ...func(*config.TransactionConfig)) (ResultWithContext, error) { if s.explicitTx != nil { err := &UsageError{Message: "Trying to run auto-commit transaction while in explicit transaction"} @@ -760,7 +661,7 @@ func (s *sessionWithContext) resolveHomeDatabase(ctx context.Context) error { return nil } -func (s *sessionWithContext) getBookmarks(ctx context.Context) (Bookmarks, error) { +func (s *sessionWithContext) getBookmarks(ctx context.Context) (bm.Bookmarks, error) { bookmarks, err := s.bookmarks.getBookmarks(ctx) if err != nil { return nil, err @@ -774,29 +675,29 @@ type erroredSessionWithContext struct { err error } -func (s *erroredSessionWithContext) LastBookmarks() Bookmarks { +func (s *erroredSessionWithContext) LastBookmarks() bm.Bookmarks { return nil } func (s *erroredSessionWithContext) lastBookmark() string { return "" } -func (s *erroredSessionWithContext) BeginTransaction(context.Context, ...func(*TransactionConfig)) (ExplicitTransaction, error) { +func (s *erroredSessionWithContext) BeginTransaction(context.Context, ...func(*config.TransactionConfig)) (ExplicitTransaction, error) { return nil, s.err } -func (s *erroredSessionWithContext) ExecuteRead(context.Context, ManagedTransactionWork, ...func(*TransactionConfig)) (any, error) { +func (s *erroredSessionWithContext) ExecuteRead(context.Context, ManagedTransactionWork, ...func(*config.TransactionConfig)) (any, error) { return nil, s.err } -func (s *erroredSessionWithContext) ExecuteWrite(context.Context, ManagedTransactionWork, ...func(*TransactionConfig)) (any, error) { +func (s *erroredSessionWithContext) ExecuteWrite(context.Context, ManagedTransactionWork, ...func(*config.TransactionConfig)) (any, error) { return nil, s.err } -func (s *erroredSessionWithContext) executeQueryRead(context.Context, ManagedTransactionWork, ...func(*TransactionConfig)) (any, error) { +func (s *erroredSessionWithContext) executeQueryRead(context.Context, ManagedTransactionWork, ...func(*config.TransactionConfig)) (any, error) { return nil, s.err } -func (s *erroredSessionWithContext) executeQueryWrite(context.Context, ManagedTransactionWork, ...func(*TransactionConfig)) (any, error) { +func (s *erroredSessionWithContext) executeQueryWrite(context.Context, ManagedTransactionWork, ...func(*config.TransactionConfig)) (any, error) { return nil, s.err } -func (s *erroredSessionWithContext) Run(context.Context, string, map[string]any, ...func(*TransactionConfig)) (ResultWithContext, error) { +func (s *erroredSessionWithContext) Run(context.Context, string, map[string]any, ...func(*config.TransactionConfig)) (ResultWithContext, error) { return nil, s.err } func (s *erroredSessionWithContext) Close(context.Context) error { @@ -813,11 +714,11 @@ func (s *erroredSessionWithContext) verifyAuthentication(context.Context) error return s.err } -func defaultTransactionConfig() TransactionConfig { - return TransactionConfig{Timeout: math.MinInt, Metadata: nil} +func defaultTransactionConfig() config.TransactionConfig { + return config.TransactionConfig{Timeout: math.MinInt, Metadata: nil} } -func validateTransactionConfig(config TransactionConfig) error { +func validateTransactionConfig(config config.TransactionConfig) error { if config.Timeout != math.MinInt && config.Timeout < 0 { err := fmt.Sprintf("Negative transaction timeouts are not allowed. Given: %d", config.Timeout) return &UsageError{Message: err} diff --git a/neo4j/session_with_context_test.go b/neo4j/session_with_context_test.go index 5a788ee1..bc2dcd99 100644 --- a/neo4j/session_with_context_test.go +++ b/neo4j/session_with_context_test.go @@ -21,20 +21,23 @@ import ( "context" "errors" "fmt" - idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" "io" "reflect" "sync" "testing" "time" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + idb "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/db" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/errorutil" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" "github.com/neo4j/neo4j-go-driver/v5/neo4j/log" ) -type transactionFunc func(context.Context, ManagedTransactionWork, ...func(*TransactionConfig)) (any, error) +type transactionFunc func(context.Context, ManagedTransactionWork, ...func(*config.TransactionConfig)) (any, error) type transactionFuncApi func(session SessionWithContext) transactionFunc func TestSession(outer *testing.T) { @@ -52,13 +55,13 @@ func TestSession(outer *testing.T) { conf := Config{MaxTransactionRetryTime: 3 * time.Millisecond, MaxConnectionPoolSize: 100} router := RouterFake{} pool := PoolFake{} - sessConfig := SessionConfig{AccessMode: AccessModeRead, BoltLogger: boltLogger} + sessConfig := config.SessionConfig{AccessMode: config.AccessModeRead, BoltLogger: boltLogger} sess := newSessionWithContext(&conf, sessConfig, &router, &pool, logger, nil, &now) sess.throttleTime = time.Millisecond * 1 return &router, &pool, sess } - createSessionFromConfig := func(sessConfig SessionConfig) (*RouterFake, *PoolFake, *sessionWithContext) { + createSessionFromConfig := func(sessConfig config.SessionConfig) (*RouterFake, *PoolFake, *sessionWithContext) { conf := Config{MaxTransactionRetryTime: 3 * time.Millisecond} router := RouterFake{} pool := PoolFake{} @@ -67,8 +70,8 @@ func TestSession(outer *testing.T) { return &router, &pool, sess } - createSessionWithBookmarks := func(bookmarks Bookmarks) (*RouterFake, *PoolFake, *sessionWithContext) { - sessConfig := SessionConfig{AccessMode: AccessModeRead, Bookmarks: bookmarks, BoltLogger: boltLogger} + createSessionWithBookmarks := func(bookmarks bm.Bookmarks) (*RouterFake, *PoolFake, *sessionWithContext) { + sessConfig := config.SessionConfig{AccessMode: config.AccessModeRead, Bookmarks: bookmarks, BoltLogger: boltLogger} return createSessionFromConfig(sessConfig) } @@ -143,7 +146,7 @@ func TestSession(outer *testing.T) { }) inner.Run("Retrieves default database name for impersonated user", func(t *testing.T) { - sessConfig := SessionConfig{ImpersonatedUser: "me"} + sessConfig := config.SessionConfig{ImpersonatedUser: "me"} router, pool, sess := createSessionFromConfig(sessConfig) conn := &ConnFake{} pool.BorrowConn = conn @@ -174,7 +177,7 @@ func TestSession(outer *testing.T) { for name, txFuncApi := range transactionFunctions { inner.Run(fmt.Sprintf("Implicitly rolls back when a %s panics without retry", name), func(t *testing.T) { - _, pool, sess := createSessionFromConfig(SessionConfig{}) + _, pool, sess := createSessionFromConfig(config.SessionConfig{}) pool.BorrowConn = &ConnFake{Alive: true} poolReturnCalled := 0 pool.ReturnHook = func() { @@ -197,13 +200,13 @@ func TestSession(outer *testing.T) { outer.Run("Bookmarking", func(inner *testing.T) { inner.Run("Initial bookmarks are returned from LastBookmarks", func(t *testing.T) { - _, _, sess := createSessionWithBookmarks(BookmarksFromRawValues("b1", "b2")) - AssertDeepEquals(t, sess.LastBookmarks(), BookmarksFromRawValues("b1", "b2")) + _, _, sess := createSessionWithBookmarks(bm.BookmarksFromRawValues("b1", "b2")) + AssertDeepEquals(t, sess.LastBookmarks(), bm.BookmarksFromRawValues("b1", "b2")) }) inner.Run("Initial bookmarks are used and cleaned up before usage", func(t *testing.T) { - dirtyBookmarks := BookmarksFromRawValues("", "b1", "", "b2", "") - cleanBookmarks := BookmarksFromRawValues("b1", "b2") + dirtyBookmarks := bm.BookmarksFromRawValues("", "b1", "", "b2", "") + cleanBookmarks := bm.BookmarksFromRawValues("b1", "b2") _, pool, sess := createSessionWithBookmarks(dirtyBookmarks) err := errors.New("make all fail") conn := &ConnFake{Alive: true, RunErr: err, TxBeginErr: err} @@ -254,13 +257,13 @@ func TestSession(outer *testing.T) { // Should call Buffer on connection to ensure that first Run is buffered and // it's bookmark retrieved sess.Run(context.Background(), "cypher", nil) - AssertDeepEquals(t, BookmarksToRawValues(sess.LastBookmarks()), []string{"buffer-1"}) + AssertDeepEquals(t, bm.BookmarksToRawValues(sess.LastBookmarks()), []string{"buffer-1"}) result, _ := sess.Run(context.Background(), "cypher", nil) - AssertDeepEquals(t, BookmarksToRawValues(sess.LastBookmarks()), []string{"buffer-2"}) + AssertDeepEquals(t, bm.BookmarksToRawValues(sess.LastBookmarks()), []string{"buffer-2"}) // And finally consuming the last result should give a new bookmark AssertIntEqual(t, consumeCalls, 0) result.Consume(context.Background()) - AssertDeepEquals(t, BookmarksToRawValues(sess.LastBookmarks()), []string{"consume-1"}) + AssertDeepEquals(t, bm.BookmarksToRawValues(sess.LastBookmarks()), []string{"consume-1"}) }) inner.Run("Pending and invoke tx function", func(t *testing.T) { @@ -285,7 +288,7 @@ func TestSession(outer *testing.T) { if !reflect.DeepEqual([]string{"1"}, rtx.Bookmarks) { t.Errorf("Using unclean or no bookmarks: %+v", rtx) } - AssertDeepEquals(t, BookmarksToRawValues(sess.LastBookmarks()), []string{"1"}) + AssertDeepEquals(t, bm.BookmarksToRawValues(sess.LastBookmarks()), []string{"1"}) AssertIntEqual(t, bufferCalls, 1) }) @@ -309,7 +312,7 @@ func TestSession(outer *testing.T) { if !reflect.DeepEqual([]string{"1"}, rtx.Bookmarks) { t.Errorf("Using unclean or no bookmarks: %+v", rtx) } - AssertDeepEquals(t, BookmarksToRawValues(sess.LastBookmarks()), []string{"1"}) + AssertDeepEquals(t, bm.BookmarksToRawValues(sess.LastBookmarks()), []string{"1"}) AssertIntEqual(t, bufferCalls, 1) }) @@ -326,7 +329,7 @@ func TestSession(outer *testing.T) { }) inner.Run("Retrieves default database name for impersonated user", func(t *testing.T) { - sessConfig := SessionConfig{ImpersonatedUser: "me"} + sessConfig := config.SessionConfig{ImpersonatedUser: "me"} router, pool, sess := createSessionFromConfig(sessConfig) conn := &ConnFake{} pool.BorrowConn = conn @@ -471,7 +474,7 @@ func TestSession(outer *testing.T) { // Begin and commit a transaction on the session tx, _ := sess.BeginTransaction(context.Background()) tx.Commit(context.Background()) - AssertDeepEquals(t, BookmarksToRawValues(sess.LastBookmarks()), []string{bookmark}) + AssertDeepEquals(t, bm.BookmarksToRawValues(sess.LastBookmarks()), []string{bookmark}) // The bookmark should be used in next transaction sess.BeginTransaction(context.Background()) AssertLen(t, conn.RecordedTxs, 2) @@ -494,7 +497,7 @@ func TestSession(outer *testing.T) { }) inner.Run("Retrieves default database name for impersonated user", func(t *testing.T) { - sessConfig := SessionConfig{ImpersonatedUser: "me"} + sessConfig := config.SessionConfig{ImpersonatedUser: "me"} router, pool, sess := createSessionFromConfig(sessConfig) conn := &ConnFake{} pool.BorrowConn = conn diff --git a/neo4j/test-integration/auth_test.go b/neo4j/test-integration/auth_test.go index 00473a1a..eb1943b8 100644 --- a/neo4j/test-integration/auth_test.go +++ b/neo4j/test-integration/auth_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -39,7 +40,7 @@ func TestAuthentication(outer *testing.T) { panic(err) } - return driver, driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + return driver, driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) } outer.Run("when wrong credentials are provided, it should fail with authentication error", func(t *testing.T) { diff --git a/neo4j/test-integration/bookmark_test.go b/neo4j/test-integration/bookmark_test.go index 8d695e24..7f82bcff 100644 --- a/neo4j/test-integration/bookmark_test.go +++ b/neo4j/test-integration/bookmark_test.go @@ -23,6 +23,8 @@ import ( "testing" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -34,7 +36,7 @@ func TestBookmark(outer *testing.T) { server := dbserver.GetDbServer(ctx) createNodeInTx := func(driver neo4j.DriverWithContext) string { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -50,7 +52,7 @@ func TestBookmark(outer *testing.T) { }) assertNil(outer, err) - bookmarks := neo4j.BookmarksToRawValues(session.LastBookmarks()) + bookmarks := bm.BookmarksToRawValues(session.LastBookmarks()) assertEquals(outer, len(bookmarks), 1) return bookmarks[0] } @@ -58,7 +60,7 @@ func TestBookmark(outer *testing.T) { outer.Run("session constructed with no bookmarks", func(inner *testing.T) { setUp := func() (neo4j.DriverWithContext, neo4j.SessionWithContext) { driver := server.Driver() - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) return driver, session } @@ -81,7 +83,7 @@ func TestBookmark(outer *testing.T) { _, err = result.Consume(ctx) assertNil(t, err) - assertStringsNotEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsNotEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) inner.Run("when a node is created in explicit transaction and committed, last bookmark should not be empty", func(t *testing.T) { @@ -100,7 +102,7 @@ func TestBookmark(outer *testing.T) { err = tx.Commit(ctx) assertNil(t, err) - assertStringsNotEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsNotEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) inner.Run("when a node is created in explicit transaction and rolled back, last bookmark should be empty", func(t *testing.T) { @@ -119,7 +121,7 @@ func TestBookmark(outer *testing.T) { err = tx.Rollback(ctx) assertNil(t, err) - assertStringsEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) inner.Run("when a node is created in transaction function, last bookmark should not be empty", func(t *testing.T) { @@ -138,7 +140,7 @@ func TestBookmark(outer *testing.T) { assertNil(t, err) assertEquals(t, result, 1) - assertStringsNotEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsNotEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) inner.Run("when a node is created in transaction function and rolled back, last bookmark should be empty", func(t *testing.T) { @@ -158,7 +160,7 @@ func TestBookmark(outer *testing.T) { assertEquals(t, err, failWith) assertNil(t, result) - assertStringsEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) inner.Run("when a node is queried in transaction function, last bookmark should not be empty", func(t *testing.T) { @@ -180,7 +182,7 @@ func TestBookmark(outer *testing.T) { assertNil(t, err) assertEquals(t, result, 1) - assertStringsNotEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsNotEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) inner.Run("when a node is created in transaction function and rolled back, last bookmark should be empty", func(t *testing.T) { @@ -203,7 +205,7 @@ func TestBookmark(outer *testing.T) { assertEquals(t, err, failWith) assertNil(t, result) - assertStringsEmpty(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) + assertStringsEmpty(t, bm.BookmarksToRawValues(session.LastBookmarks())) }) }) @@ -211,9 +213,9 @@ func TestBookmark(outer *testing.T) { setUp := func() (neo4j.DriverWithContext, neo4j.SessionWithContext, string) { driver := server.Driver() bookmark := createNodeInTx(driver) - session := driver.NewSession(ctx, neo4j.SessionConfig{ - AccessMode: neo4j.AccessModeWrite, - Bookmarks: neo4j.BookmarksFromRawValues(bookmark), + session := driver.NewSession(ctx, config.SessionConfig{ + AccessMode: config.AccessModeWrite, + Bookmarks: bm.BookmarksFromRawValues(bookmark), }) return driver, session, bookmark } @@ -236,7 +238,7 @@ func TestBookmark(outer *testing.T) { assertNil(t, err) defer tx.Close(ctx) - assertEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) + assertEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) }) inner.Run("given bookmarks should be accessible after ROLLBACK", func(t *testing.T) { @@ -253,7 +255,7 @@ func TestBookmark(outer *testing.T) { err = tx.Rollback(ctx) assertNil(t, err) - assertEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) + assertEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) }) inner.Run("given bookmarks should be accessible when transaction fails", func(t *testing.T) { @@ -269,7 +271,7 @@ func TestBookmark(outer *testing.T) { err = tx.Close(ctx) assertNil(t, err) - assertEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) + assertEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) }) inner.Run("given bookmarks should be accessible after run", func(t *testing.T) { @@ -282,7 +284,7 @@ func TestBookmark(outer *testing.T) { _, err = result.Consume(ctx) assertNil(t, err) - assertEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) + assertEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) }) inner.Run("given bookmarks should be accessible after failed run", func(t *testing.T) { @@ -292,7 +294,7 @@ func TestBookmark(outer *testing.T) { _, err := session.Run(ctx, "RETURN", nil) assertNotNil(t, err) - assertEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) + assertEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark}) }) }) @@ -311,9 +313,9 @@ func TestBookmark(outer *testing.T) { bookmark2 = createNodeInTx(driver) assertNotEquals(inner, bookmark1, bookmark2) - session = driver.NewSession(ctx, neo4j.SessionConfig{ - AccessMode: neo4j.AccessModeWrite, - Bookmarks: neo4j.BookmarksFromRawValues(bookmark1, bookmark2), + session = driver.NewSession(ctx, config.SessionConfig{ + AccessMode: config.AccessModeWrite, + Bookmarks: bm.BookmarksFromRawValues(bookmark1, bookmark2), }) defer func() { @@ -331,7 +333,7 @@ func TestBookmark(outer *testing.T) { assertNil(t, err) defer tx.Close(ctx) - assertEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark1, bookmark2}) + assertEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark1, bookmark2}) }) inner.Run("new bookmark should be reported back by the server after committing", func(t *testing.T) { @@ -349,9 +351,9 @@ func TestBookmark(outer *testing.T) { err = tx.Commit(ctx) assertNil(t, err) - assertNotNil(t, neo4j.BookmarksToRawValues(session.LastBookmarks())) - assertNotEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark1}) - assertNotEquals(t, neo4j.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark2}) + assertNotNil(t, bm.BookmarksToRawValues(session.LastBookmarks())) + assertNotEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark1}) + assertNotEquals(t, bm.BookmarksToRawValues(session.LastBookmarks()), []string{bookmark2}) }) }) @@ -363,9 +365,9 @@ func TestBookmark(outer *testing.T) { bookmark := createNodeInTx(driver) - session := driver.NewSession(ctx, neo4j.SessionConfig{ - AccessMode: neo4j.AccessModeWrite, - Bookmarks: neo4j.BookmarksFromRawValues(bookmark + "0"), + session := driver.NewSession(ctx, config.SessionConfig{ + AccessMode: config.AccessModeWrite, + Bookmarks: bm.BookmarksFromRawValues(bookmark + "0"), }) return driver, session, bookmark } diff --git a/neo4j/test-integration/context_test.go b/neo4j/test-integration/context_test.go index 692ad415..d75b09f6 100644 --- a/neo4j/test-integration/context_test.go +++ b/neo4j/test-integration/context_test.go @@ -19,9 +19,11 @@ package test_integration import ( "context" + "testing" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" - "testing" ) func TestContext(outer *testing.T) { @@ -35,7 +37,7 @@ func TestContext(outer *testing.T) { outer.Run("server does not hold on transaction when driver cancels context", func(t *testing.T) { driver := server.Driver() defer driver.Close(ctx) - session := driver.NewSession(ctx, neo4j.SessionConfig{FetchSize: 1}) + session := driver.NewSession(ctx, config.SessionConfig{FetchSize: 1}) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) assertNil(t, err) @@ -55,7 +57,7 @@ func TestContext(outer *testing.T) { } func listTransactionWorkloads(ctx context.Context, driver neo4j.DriverWithContext, server dbserver.DbServer) []string { - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer session.Close(ctx) transactionQuery := server.GetTransactionWorkloadsQuery() results, err := session.Run(ctx, transactionQuery, nil) diff --git a/neo4j/test-integration/dbserver/dbserver.go b/neo4j/test-integration/dbserver/dbserver.go index ae57c5fc..61caf143 100644 --- a/neo4j/test-integration/dbserver/dbserver.go +++ b/neo4j/test-integration/dbserver/dbserver.go @@ -118,7 +118,7 @@ func setServerVersion(ctx context.Context, server *DbServer, envVersion Version) // this is used when the TEST_NEO4J_VERSION environment variable is not set. func (s *DbServer) getVersionFromDB(ctx context.Context) (Version, error) { driver := s.Driver() - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) result, err := session.Run(ctx, "CALL dbms.components() YIELD versions UNWIND versions AS version RETURN version;", nil) @@ -146,7 +146,7 @@ func (s *DbServer) getVersionFromDB(ctx context.Context) (Version, error) { func (s DbServer) deleteData(ctx context.Context) { driver := s.Driver() - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) for { diff --git a/neo4j/test-integration/driver_test.go b/neo4j/test-integration/driver_test.go index 8fc92332..659c7fa8 100644 --- a/neo4j/test-integration/driver_test.go +++ b/neo4j/test-integration/driver_test.go @@ -19,11 +19,12 @@ package test_integration import ( "context" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "math" "testing" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -56,7 +57,7 @@ func TestDriver(outer *testing.T) { setUp := func() (neo4j.DriverWithContext, neo4j.SessionWithContext) { driver := server.Driver() - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) return driver, session } @@ -105,7 +106,7 @@ func TestDriver(outer *testing.T) { err = driver.Close(ctx) assertNil(t, err) - _ = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + _ = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) }) }) @@ -130,19 +131,19 @@ func TestDriver(outer *testing.T) { inner.Run("should return error when pool is full", func(t *testing.T) { // Open connection 1 - session1 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session1 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) _, err = session1.Run(ctx, "UNWIND RANGE(1, 100) AS N RETURN N", nil) assertNil(t, err) // Open connection 2 - session2 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session2 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) _, err = session2.Run(ctx, "UNWIND RANGE(1, 100) AS N RETURN N", nil) assertNil(t, err) // Try opening connection 3 - session3 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session3 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) _, err = session3.Run(ctx, "UNWIND RANGE(1, 100) AS N RETURN N", nil) assertTrue(t, neo4j.IsConnectivityError(err)) @@ -169,19 +170,19 @@ func TestDriver(outer *testing.T) { inner.Run("should return error when pool is full", func(t *testing.T) { // Open connection 1 - session1 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session1 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) _, err = session1.Run(ctx, "UNWIND RANGE(1, 100) AS N RETURN N", nil) assertNil(t, err) // Open connection 2 - session2 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session2 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) _, err = session2.Run(ctx, "UNWIND RANGE(1, 100) AS N RETURN N", nil) assertNil(t, err) // Try opening connection 3 - session3 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session3 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) start := time.Now() _, err = session3.Run(ctx, "UNWIND RANGE(1, 100) AS N RETURN N", nil) diff --git a/neo4j/test-integration/examples_test.go b/neo4j/test-integration/examples_test.go index 485663f5..577e7e8a 100644 --- a/neo4j/test-integration/examples_test.go +++ b/neo4j/test-integration/examples_test.go @@ -21,10 +21,12 @@ import ( "context" "errors" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "testing" "time" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" "github.com/neo4j/neo4j-go-driver/v5/neo4j/dbtype" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" @@ -239,7 +241,7 @@ func TestExamples(outer *testing.T) { } // end::geospatial-types-point2d[] - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) assertNotNil(t, session) defer session.Close(ctx) @@ -313,7 +315,7 @@ func TestExamples(outer *testing.T) { } // end::geospatial-types-point3d[] - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) assertNotNil(t, session) defer session.Close(ctx) @@ -377,7 +379,7 @@ func helloWorld(ctx context.Context, uri, username, password string) (string, er } defer driver.Close(ctx) - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) greeting, err := session.ExecuteWrite(ctx, func(transaction neo4j.ManagedTransaction) (any, error) { @@ -474,7 +476,7 @@ func addPerson(ctx context.Context, name string) error { } defer driver.Close(ctx) - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) result, err := session.Run(ctx, "CREATE (n:Person { name: $name})", map[string]any{"name": name}) @@ -524,7 +526,7 @@ func createDriverWithMaxRetryTime(uri, username, password string) (neo4j.DriverW // tag::service-unavailable[] func createItem(ctx context.Context, driver neo4j.DriverWithContext) error { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -542,7 +544,7 @@ func createItem(ctx context.Context, driver neo4j.DriverWithContext) error { // end::service-unavailable[] func countNodes(ctx context.Context, driver neo4j.DriverWithContext, label string, property string, value string) (int64, error) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) result, err := session.Run(ctx, fmt.Sprintf("MATCH (a:%s {%s: $value}) RETURN count(a)", label, property), map[string]any{"value": value}) @@ -559,7 +561,7 @@ func countNodes(ctx context.Context, driver neo4j.DriverWithContext, label strin // tag::session[] func addPersonInSession(ctx context.Context, driver neo4j.DriverWithContext, name string) error { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) result, err := session.Run(ctx, "CREATE (a:Person {name: $name})", map[string]any{"name": name}) @@ -578,7 +580,7 @@ func addPersonInSession(ctx context.Context, driver neo4j.DriverWithContext, nam // tag::autocommit-transaction[] func addPersonInAutoCommitTx(ctx context.Context, driver neo4j.DriverWithContext, name string) error { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) result, err := session.Run(ctx, "CREATE (a:Person {name: $name})", map[string]any{"name": name}) @@ -597,7 +599,7 @@ func addPersonInAutoCommitTx(ctx context.Context, driver neo4j.DriverWithContext // tag::transaction-function[] func addPersonInTxFunc(ctx context.Context, driver neo4j.DriverWithContext, name string) error { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -616,7 +618,7 @@ func addPersonInTxFunc(ctx context.Context, driver neo4j.DriverWithContext, name // tag::transaction-timeout-config[] func configTxTimeout(ctx context.Context, driver neo4j.DriverWithContext, name string) error { - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer session.Close(ctx) _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -626,7 +628,7 @@ func configTxTimeout(ctx context.Context, driver neo4j.DriverWithContext, name s } return result.Consume(ctx) - }, neo4j.WithTxTimeout(5*time.Second)) + }, config.WithTxTimeout(5*time.Second)) return err } @@ -635,7 +637,7 @@ func configTxTimeout(ctx context.Context, driver neo4j.DriverWithContext, name s // tag::transaction-metadata-config[] func configTxMetadata(ctx context.Context, driver neo4j.DriverWithContext, name string) error { - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer session.Close(ctx) _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -645,7 +647,7 @@ func configTxMetadata(ctx context.Context, driver neo4j.DriverWithContext, name } return result.Consume(ctx) - }, neo4j.WithTxMetadata(map[string]any{"applicationId": 123})) + }, config.WithTxMetadata(map[string]any{"applicationId": 123})) return err } @@ -722,8 +724,8 @@ func printFriendsTxFunc(ctx context.Context) neo4j.ManagedTransactionWork { } } -func addAndEmploy(ctx context.Context, driver neo4j.DriverWithContext, person string, company string) (neo4j.Bookmarks, error) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) +func addAndEmploy(ctx context.Context, driver neo4j.DriverWithContext, person string, company string) (bm.Bookmarks, error) { + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) if _, err := session.ExecuteWrite(ctx, addCompanyTxFunc(ctx, company)); err != nil { @@ -739,8 +741,8 @@ func addAndEmploy(ctx context.Context, driver neo4j.DriverWithContext, person st return session.LastBookmarks(), nil } -func makeFriend(ctx context.Context, driver neo4j.DriverWithContext, person1 string, person2 string, bookmarks neo4j.Bookmarks) (neo4j.Bookmarks, error) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite, Bookmarks: bookmarks}) +func makeFriend(ctx context.Context, driver neo4j.DriverWithContext, person1 string, person2 string, bookmarks bm.Bookmarks) (bm.Bookmarks, error) { + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite, Bookmarks: bookmarks}) defer session.Close(ctx) if _, err := session.ExecuteWrite(ctx, makeFriendTxFunc(ctx, person1, person2)); err != nil { @@ -751,7 +753,7 @@ func makeFriend(ctx context.Context, driver neo4j.DriverWithContext, person1 str } func addEmployAndMakeFriends(ctx context.Context, driver neo4j.DriverWithContext) error { - var bookmarks1, bookmarks2, bookmarks3 neo4j.Bookmarks + var bookmarks1, bookmarks2, bookmarks3 bm.Bookmarks var err error if bookmarks1, err = addAndEmploy(ctx, driver, "Alice", "Wayne Enterprises"); err != nil { @@ -762,13 +764,13 @@ func addEmployAndMakeFriends(ctx context.Context, driver neo4j.DriverWithContext return err } - if bookmarks3, err = makeFriend(ctx, driver, "Bob", "Alice", neo4j.CombineBookmarks(bookmarks1, bookmarks2)); err != nil { + if bookmarks3, err = makeFriend(ctx, driver, "Bob", "Alice", bm.CombineBookmarks(bookmarks1, bookmarks2)); err != nil { return err } - session := driver.NewSession(ctx, neo4j.SessionConfig{ - AccessMode: neo4j.AccessModeRead, - Bookmarks: neo4j.CombineBookmarks(bookmarks1, bookmarks2, bookmarks3), + session := driver.NewSession(ctx, config.SessionConfig{ + AccessMode: config.AccessModeRead, + Bookmarks: bm.CombineBookmarks(bookmarks1, bookmarks2, bookmarks3), }) defer session.Close(ctx) @@ -809,7 +811,7 @@ func matchPersonNodeTxFunc(ctx context.Context, name string) neo4j.ManagedTransa } func addPersonNode(ctx context.Context, driver neo4j.DriverWithContext, name string) (int64, error) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) if _, err := session.ExecuteWrite(ctx, addPersonNodeTxFunc(ctx, name)); err != nil { @@ -836,14 +838,14 @@ func TestExamplesDatabaseSelection(t *testing.T) { driver := dbserver.GetDbServer(ctx).Driver() defer driver.Close(ctx) // tag::database-selection[] - session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "example"}) + session := driver.NewSession(ctx, config.SessionConfig{DatabaseName: "example"}) // end::database-selection[] defer session.Close(ctx) } // tag::result-consume[] func getPeople(ctx context.Context, driver neo4j.DriverWithContext) ([]string, error) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) people, err := session.ExecuteRead(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -875,7 +877,7 @@ func getPeople(ctx context.Context, driver neo4j.DriverWithContext) ([]string, e // tag::result-retain[] func addPersonsAsEmployees(ctx context.Context, driver neo4j.DriverWithContext, companyName string) (int, error) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) results, err := session.Run(ctx, "MATCH (a:Person) RETURN a.name AS name", nil) diff --git a/neo4j/test-integration/multidatabase_test.go b/neo4j/test-integration/multidatabase_test.go index 38fc1a02..af27c6e5 100644 --- a/neo4j/test-integration/multidatabase_test.go +++ b/neo4j/test-integration/multidatabase_test.go @@ -21,7 +21,7 @@ import ( "context" "testing" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -47,7 +47,7 @@ func TestMultidatabase(outer *testing.T) { // Ensure that a test database exists using system database func() { - sysSess := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "system"}) + sysSess := driver.NewSession(ctx, config.SessionConfig{DatabaseName: "system"}) defer sysSess.Close(ctx) _, err := sysSess.Run(ctx, server.DropDatabaseQuery("testdb"), nil) assertNil(outer, err) @@ -57,17 +57,17 @@ func TestMultidatabase(outer *testing.T) { outer.Run("Node created in test db should not be visible in default db", func(t *testing.T) { // Create node in testdb session - testSess := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "testdb"}) + testSess := driver.NewSession(ctx, config.SessionConfig{DatabaseName: "testdb"}) randId := createRandomNode(ctx, t, testSess) testSess.Close(ctx) // Look for above node in default database session, it shouldn't exist there - defaultSess := driver.NewSession(ctx, neo4j.SessionConfig{}) + defaultSess := driver.NewSession(ctx, config.SessionConfig{}) assertNoRandomNode(ctx, t, defaultSess, randId) defaultSess.Close(ctx) // Look again in testdb session, should of course exist here - testSess = driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "testdb"}) + testSess = driver.NewSession(ctx, config.SessionConfig{DatabaseName: "testdb"}) assertRandomNode(ctx, t, testSess, randId) testSess.Close(ctx) }) diff --git a/neo4j/test-integration/routing_test.go b/neo4j/test-integration/routing_test.go index cbf236a6..44beff94 100644 --- a/neo4j/test-integration/routing_test.go +++ b/neo4j/test-integration/routing_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -55,7 +56,7 @@ func TestRouting(outer *testing.T) { assertNil(t, err) defer driver.Close(ctx) - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) result, err = session.Run(ctx, "RETURN 1", nil) @@ -75,7 +76,7 @@ func TestRouting(outer *testing.T) { driver := getDriver(server.URI()) assertNil(t, err) - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) writeCount, err = session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { writeResult, err := tx.Run(ctx, "MERGE (n:Person {name: 'John'}) RETURN 1", nil) diff --git a/neo4j/test-integration/session_test.go b/neo4j/test-integration/session_test.go index ed8907d4..23031679 100644 --- a/neo4j/test-integration/session_test.go +++ b/neo4j/test-integration/session_test.go @@ -20,10 +20,11 @@ package test_integration import ( "context" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "testing" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" @@ -50,7 +51,7 @@ func TestSession(outer *testing.T) { }) assertNotNil(inner, driver) - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) assertNotNil(inner, session) defer func() { @@ -172,7 +173,7 @@ func TestSession(outer *testing.T) { ) driver = server.Driver() - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer func() { if session != nil { @@ -332,7 +333,7 @@ func TestSession(outer *testing.T) { var err error innerExecutor := func() error { - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) if result, err = session.Run(ctx, "UNWIND RANGE(1,100) AS N RETURN N", nil); err != nil { @@ -354,7 +355,7 @@ func TestSession(outer *testing.T) { var err1, err2 error innerExecutor := func() error { - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) if result1, err1 = session.Run(ctx, "UNWIND RANGE(1,100) AS N RETURN N", nil); err != nil { @@ -391,7 +392,7 @@ func TestSession(outer *testing.T) { innerExecutor := func() error { var tx neo4j.ExplicitTransaction - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer session.Close(ctx) if tx, err = session.BeginTransaction(ctx); err != nil { @@ -426,7 +427,7 @@ func TestSession(outer *testing.T) { assertEquals(t, records2[99].Values[0], 100) assertEquals(t, records2[99].Values[1], "Text 100") - newSession := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + newSession := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) assertNotNil(t, newSession) defer newSession.Close(ctx) @@ -449,7 +450,7 @@ func TestSession(outer *testing.T) { inner.Skip("this test is targeted for server version after neo4j 3.5.0") } - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) assertNotNil(inner, session) defer func() { @@ -474,7 +475,7 @@ func TestSession(outer *testing.T) { t.Skip("Can not list transactions on non-enterprise version") } - matched, err := session.ExecuteRead(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata), neo4j.WithTxMetadata(metadata)) + matched, err := session.ExecuteRead(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata), config.WithTxMetadata(metadata)) assertNil(t, err) assertTrue(t, matched.(bool)) @@ -491,7 +492,7 @@ func TestSession(outer *testing.T) { t.Skip("Can not list transactions on non-enterprise version") } - matched, err := session.ExecuteRead(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata), neo4j.WithTxMetadata(metadata)) + matched, err := session.ExecuteRead(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata), config.WithTxMetadata(metadata)) assertNil(t, err) assertTrue(t, matched.(bool)) }) @@ -507,7 +508,7 @@ func TestSession(outer *testing.T) { t.Skip("Can not list transactions on non-enterprise version") } - matched, err := session.ExecuteWrite(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata), neo4j.WithTxMetadata(metadata)) + matched, err := session.ExecuteWrite(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata), config.WithTxMetadata(metadata)) assertNil(t, err) assertTrue(t, matched.(bool)) }) @@ -515,14 +516,14 @@ func TestSession(outer *testing.T) { inner.Run("should set transaction timeout", func(t *testing.T) { createNode(ctx, t, session, "RunTxTimeOut", nil) - session2, tx2 := newSessionAndTx(ctx, t, driver, neo4j.AccessModeWrite) + session2, tx2 := newSessionAndTx(ctx, t, driver, config.AccessModeWrite) defer session2.Close(ctx) defer tx2.Close(ctx) updateNodeInTx(ctx, t, tx2, "RunTxTimeOut", map[string]any{"id": 1}) - session3 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session3 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) - result3, err := session3.Run(ctx, "MATCH (n:RunTxTimeOut) SET n.id = 2", nil, neo4j.WithTxTimeout(1*time.Second)) + result3, err := session3.Run(ctx, "MATCH (n:RunTxTimeOut) SET n.id = 2", nil, config.WithTxTimeout(1*time.Second)) // Up to db to determine when error occurs if err != nil { dbErr := err.(*db.Neo4jError) @@ -542,14 +543,14 @@ func TestSession(outer *testing.T) { inner.Run("should set transaction timeout on ExecuteWrite", func(t *testing.T) { createNode(ctx, t, session, "WriteTransactionTxTimeOut", nil) - session2, tx2 := newSessionAndTx(ctx, t, driver, neo4j.AccessModeWrite) + session2, tx2 := newSessionAndTx(ctx, t, driver, config.AccessModeWrite) defer session2.Close(ctx) defer tx2.Close(ctx) updateNodeInTx(ctx, t, tx2, "WriteTransactionTxTimeOut", map[string]any{"id": 1}) - session3 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session3 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) - _, err := session3.ExecuteWrite(ctx, updateNodeWork(ctx, t, "WriteTransactionTxTimeOut", map[string]any{"id": 2}), neo4j.WithTxTimeout(1*time.Second)) + _, err := session3.ExecuteWrite(ctx, updateNodeWork(ctx, t, "WriteTransactionTxTimeOut", map[string]any{"id": 2}), config.WithTxTimeout(1*time.Second)) assertNotNil(t, err) dbErr := err.(*db.Neo4jError) assertStringContains(t, dbErr.Msg, "terminated") diff --git a/neo4j/test-integration/summary_test.go b/neo4j/test-integration/summary_test.go index 5dfa0eac..36ee1d89 100644 --- a/neo4j/test-integration/summary_test.go +++ b/neo4j/test-integration/summary_test.go @@ -19,10 +19,12 @@ package test_integration import ( "context" + "testing" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" - "testing" ) func TestResultSummary(outer *testing.T) { @@ -50,7 +52,7 @@ func TestResultSummary(outer *testing.T) { } inner.Run("does not include any database information", func(t *testing.T) { - session := driver.NewSession(ctx, neo4j.SessionConfig{Bookmarks: neo4j.BookmarksFromRawValues(bookmark)}) + session := driver.NewSession(ctx, config.SessionConfig{Bookmarks: bm.BookmarksFromRawValues(bookmark)}) defer assertCloses(ctx, t, session) result, err := session.Run(ctx, "RETURN 42", noParams) assertNil(t, err) @@ -70,18 +72,18 @@ func TestResultSummary(outer *testing.T) { inner.Skip("Multi-tenancy is a Neo4j 4+ feature") } - session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "system", BoltLogger: neo4j.ConsoleBoltLogger()}) + session := driver.NewSession(ctx, config.SessionConfig{DatabaseName: "system", BoltLogger: neo4j.ConsoleBoltLogger()}) defer assertCloses(ctx, inner, session) res, err := session.Run(ctx, server.CreateDatabaseQuery(extraDatabase), map[string]any{}) assertNil(inner, err) _, err = res.Consume(ctx) // consume result to obtain bookmark assertNil(inner, err) - bookmarks := neo4j.BookmarksToRawValues(session.LastBookmarks()) + bookmarks := bm.BookmarksToRawValues(session.LastBookmarks()) assertEquals(inner, len(bookmarks), 1) bookmark = bookmarks[0] defer func() { - session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "system", Bookmarks: neo4j.BookmarksFromRawValues(bookmark)}) + session := driver.NewSession(ctx, config.SessionConfig{DatabaseName: "system", Bookmarks: bm.BookmarksFromRawValues(bookmark)}) defer assertCloses(ctx, inner, session) res, err := session.Run(ctx, server.DropDatabaseQuery(extraDatabase), map[string]any{}) assertNil(inner, err) @@ -91,7 +93,7 @@ func TestResultSummary(outer *testing.T) { }() inner.Run("includes the default database information", func(t *testing.T) { - session := driver.NewSession(ctx, neo4j.SessionConfig{Bookmarks: neo4j.BookmarksFromRawValues(bookmark)}) + session := driver.NewSession(ctx, config.SessionConfig{Bookmarks: bm.BookmarksFromRawValues(bookmark)}) defer assertCloses(ctx, t, session) result, err := session.Run(ctx, "RETURN 42", noParams) assertNil(t, err) @@ -102,7 +104,7 @@ func TestResultSummary(outer *testing.T) { }) inner.Run("includes the database information, based on session configuration", func(t *testing.T) { - session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: extraDatabase, Bookmarks: neo4j.BookmarksFromRawValues(bookmark)}) + session := driver.NewSession(ctx, config.SessionConfig{DatabaseName: extraDatabase, Bookmarks: bm.BookmarksFromRawValues(bookmark)}) defer assertCloses(ctx, t, session) result, err := session.Run(ctx, "RETURN 42", noParams) assertNil(t, err) diff --git a/neo4j/test-integration/timeout_test.go b/neo4j/test-integration/timeout_test.go index 7e5b53d1..8a167c7b 100644 --- a/neo4j/test-integration/timeout_test.go +++ b/neo4j/test-integration/timeout_test.go @@ -19,10 +19,11 @@ package test_integration import ( "context" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "testing" "time" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -49,10 +50,10 @@ func TestTimeoutAndLifetime(outer *testing.T) { assertNotNil(t, driver) defer driver.Close(ctx) - session1, _ = newSessionAndTx(ctx, t, driver, neo4j.AccessModeRead) + session1, _ = newSessionAndTx(ctx, t, driver, config.AccessModeRead) defer session1.Close(ctx) - session2 = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session2 = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) assertNotNil(t, session2) defer session2.Close(ctx) @@ -72,7 +73,7 @@ func TestTimeoutAndLifetime(outer *testing.T) { assertNotNil(t, driver) defer driver.Close(ctx) - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session.Close(ctx) _, err = session.BeginTransaction(ctx) diff --git a/neo4j/test-integration/transaction_test.go b/neo4j/test-integration/transaction_test.go index a84f2d6c..153d8c3a 100644 --- a/neo4j/test-integration/transaction_test.go +++ b/neo4j/test-integration/transaction_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -41,7 +42,7 @@ func TestTransaction(outer *testing.T) { var result neo4j.ResultWithContext driver = server.Driver() - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) defer func() { if session != nil { @@ -239,7 +240,7 @@ func TestTransaction(outer *testing.T) { "m4": neo4j.LocalDateTimeOf(time.Now()), } - tx, err = session.BeginTransaction(ctx, neo4j.WithTxMetadata(metadata)) + tx, err = session.BeginTransaction(ctx, config.WithTxMetadata(metadata)) assertNil(t, err) defer tx.Close(ctx) @@ -250,7 +251,7 @@ func TestTransaction(outer *testing.T) { t.Skip("Can not list transactions on non-enterprise version") } - session2 := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}) + session2 := driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeRead}) defer session2.Close(ctx) matched, err := session2.ExecuteRead(ctx, listTransactionsAndMatchMetadataWork(ctx, server.Version, metadata)) assertNil(t, err) @@ -260,13 +261,13 @@ func TestTransaction(outer *testing.T) { inner.Run("should set transaction timeout", func(t *testing.T) { createNode(ctx, t, session, "TxTimeOut", nil) - session2, tx2 := newSessionAndTx(ctx, t, driver, neo4j.AccessModeWrite) + session2, tx2 := newSessionAndTx(ctx, t, driver, config.AccessModeWrite) defer session2.Close(ctx) defer tx2.Close(ctx) updateNodeInTx(ctx, t, tx2, "TxTimeOut", map[string]any{"id": 1}) - session3, tx3 := newSessionAndTx(ctx, t, driver, neo4j.AccessModeWrite, neo4j.WithTxTimeout(1*time.Second)) + session3, tx3 := newSessionAndTx(ctx, t, driver, config.AccessModeWrite, config.WithTxTimeout(1*time.Second)) defer session3.Close(ctx) defer tx3.Close(ctx) @@ -282,12 +283,12 @@ func TestTransaction(outer *testing.T) { } t.Run("should fail when transaction timeout is set for Session.BeginTransaction", func(t *testing.T) { - _, err := session.BeginTransaction(ctx, neo4j.WithTxTimeout(1*time.Second)) + _, err := session.BeginTransaction(ctx, config.WithTxTimeout(1*time.Second)) assertNotNil(t, err) }) t.Run("should fail when transaction metadata is set for Session.BeginTransaction", func(t *testing.T) { - _, err := session.BeginTransaction(ctx, neo4j.WithTxMetadata(map[string]any{"x": 1})) + _, err := session.BeginTransaction(ctx, config.WithTxMetadata(map[string]any{"x": 1})) assertNotNil(t, err) }) }) diff --git a/neo4j/test-integration/types_test.go b/neo4j/test-integration/types_test.go index 0f656a3b..eb1bbee2 100644 --- a/neo4j/test-integration/types_test.go +++ b/neo4j/test-integration/types_test.go @@ -25,6 +25,7 @@ import ( "testing" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" ) @@ -41,7 +42,7 @@ func TestTypes(outer *testing.T) { var result neo4j.ResultWithContext driver = server.Driver() - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: config.AccessModeWrite}) assertNotNil(outer, session) defer func() { @@ -440,7 +441,7 @@ func TestTypes(outer *testing.T) { }) deepT.Run("should fail when sending as tx metadata", func(t *testing.T) { - result, err = session.Run(ctx, "CREATE (n)", nil, neo4j.WithTxMetadata(map[string]any{"m1": unsupportedType{}})) + result, err = session.Run(ctx, "CREATE (n)", nil, config.WithTxMetadata(map[string]any{"m1": unsupportedType{}})) assertNotNil(t, err) //Expect(err).To(BeGenericError(ContainSubstring("unable to convert tx metadata to connector value for run message"))) assertNil(t, result) diff --git a/neo4j/test-integration/utils_test.go b/neo4j/test-integration/utils_test.go index 792342e8..c468deea 100644 --- a/neo4j/test-integration/utils_test.go +++ b/neo4j/test-integration/utils_test.go @@ -20,11 +20,13 @@ package test_integration import ( "context" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" "reflect" "sort" "testing" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/test-integration/dbserver" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" ) @@ -48,22 +50,22 @@ func transactionWithIntWork(t *testing.T, tx neo4j.ExplicitTransaction, work neo return result.(int64) } -func readTransactionWithIntWork(ctx context.Context, t *testing.T, session neo4j.SessionWithContext, work neo4j.ManagedTransactionWork, configurers ...func(*neo4j.TransactionConfig)) int64 { +func readTransactionWithIntWork(ctx context.Context, t *testing.T, session neo4j.SessionWithContext, work neo4j.ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) int64 { result, err := session.ExecuteRead(ctx, work, configurers...) assertNil(t, err) return result.(int64) } -func writeTransactionWithIntWork(ctx context.Context, t *testing.T, session neo4j.SessionWithContext, work neo4j.ManagedTransactionWork, configurers ...func(*neo4j.TransactionConfig)) int64 { +func writeTransactionWithIntWork(ctx context.Context, t *testing.T, session neo4j.SessionWithContext, work neo4j.ManagedTransactionWork, configurers ...func(*config.TransactionConfig)) int64 { result, err := session.ExecuteWrite(ctx, work, configurers...) assertNil(t, err) return result.(int64) } -func newSessionAndTx(ctx context.Context, t *testing.T, driver neo4j.DriverWithContext, mode neo4j.AccessMode, configurers ...func(*neo4j.TransactionConfig)) (neo4j.SessionWithContext, neo4j.ExplicitTransaction) { - session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: mode}) +func newSessionAndTx(ctx context.Context, t *testing.T, driver neo4j.DriverWithContext, mode config.AccessMode, configurers ...func(*config.TransactionConfig)) (neo4j.SessionWithContext, neo4j.ExplicitTransaction) { + session := driver.NewSession(ctx, config.SessionConfig{AccessMode: mode}) tx, err := session.BeginTransaction(ctx, configurers...) assertNil(t, err) diff --git a/neo4j/transaction_config.go b/neo4j/transaction_config.go index 4f86aae5..dd82e428 100644 --- a/neo4j/transaction_config.go +++ b/neo4j/transaction_config.go @@ -16,71 +16,3 @@ */ package neo4j - -import "time" - -// TransactionConfig holds the settings for explicit and auto-commit transactions. Actual configuration is expected -// to be done using configuration functions that are predefined, i.e. 'WithTxTimeout' and 'WithTxMetadata', or one -// that you could write by your own. -type TransactionConfig struct { - // Timeout is the configured transaction timeout. - Timeout time.Duration - // Metadata is the configured transaction metadata that will be attached to the underlying transaction. - Metadata map[string]any -} - -// WithTxTimeout returns a transaction configuration function that applies a timeout to a transaction. -// -// Transactions that execute longer than the configured timeout will be terminated by the database. -// This functionality allows user code to limit query/transaction execution time. -// The specified timeout overrides the default timeout configured in the database using the `db.transaction.timeout` -// setting (`dbms.transaction.timeout` before Neo4j 5.0). -// Values higher than `db.transaction.timeout` will be ignored and will fall back to the default for server versions -// between 4.2 and 5.2 (inclusive). -// A `0` duration will make the transaction execute indefinitely. -// `math.MinInt` will use the default timeout configured on the server. -// Other negative durations are invalid. -// -// To apply a transaction timeout to an explicit transaction: -// -// session.BeginTransaction(WithTxTimeout(5*time.Second)) -// -// To apply a transaction timeout to an auto-commit transaction: -// -// session.Run("RETURN 1", nil, WithTxTimeout(5*time.Second)) -// -// To apply a transaction timeout to a read transaction function: -// -// session.ExecuteRead(DoWork, WithTxTimeout(5*time.Second)) -// -// To apply a transaction timeout to a write transaction function: -// -// session.ExecuteWrite(DoWork, WithTxTimeout(5*time.Second)) -func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { - return func(config *TransactionConfig) { - config.Timeout = timeout - } -} - -// WithTxMetadata returns a transaction configuration function that attaches metadata to a transaction. -// -// To attach a metadata to an explicit transaction: -// -// session.BeginTransaction(WithTxMetadata(map[string)any{"work-id": 1})) -// -// To attach a metadata to an auto-commit transaction: -// -// session.Run("RETURN 1", nil, WithTxMetadata(map[string)any{"work-id": 1})) -// -// To attach a metadata to a read transaction function: -// -// session.ExecuteRead(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) -// -// To attach a metadata to a write transaction function: -// -// session.ExecuteWrite(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) -func WithTxMetadata(metadata map[string]any) func(*TransactionConfig) { - return func(config *TransactionConfig) { - config.Metadata = metadata - } -} diff --git a/neo4j/transaction_helpers.go b/neo4j/transaction_helpers.go index 39a01bb2..5706bd21 100644 --- a/neo4j/transaction_helpers.go +++ b/neo4j/transaction_helpers.go @@ -19,6 +19,8 @@ package neo4j import ( "context" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) type ManagedTransactionWorkT[T any] func(tx ManagedTransaction) (T, error) @@ -31,7 +33,7 @@ type ManagedTransactionWorkT[T any] func(tx ManagedTransaction) (T, error) // If an error occurs, the zero value of T is returned. func ExecuteRead[T any](ctx context.Context, session SessionWithContext, work ManagedTransactionWorkT[T], - configurers ...func(config *TransactionConfig)) (T, error) { + configurers ...func(config *config.TransactionConfig)) (T, error) { return castGeneric[T](session.ExecuteRead(ctx, transactionWorkAdapter(work), configurers...)) } @@ -44,7 +46,7 @@ func ExecuteRead[T any](ctx context.Context, session SessionWithContext, // If an error occurs, the zero value of T is returned. func ExecuteWrite[T any](ctx context.Context, session SessionWithContext, work ManagedTransactionWorkT[T], - configurers ...func(config *TransactionConfig)) (T, error) { + configurers ...func(config *config.TransactionConfig)) (T, error) { return castGeneric[T](session.ExecuteWrite(ctx, transactionWorkAdapter(work), configurers...)) } diff --git a/neo4j/transaction_helpers_example_test.go b/neo4j/transaction_helpers_example_test.go index 140504b3..78891770 100644 --- a/neo4j/transaction_helpers_example_test.go +++ b/neo4j/transaction_helpers_example_test.go @@ -20,8 +20,10 @@ package neo4j_test import ( "context" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j" "os" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) type Person struct { @@ -45,7 +47,7 @@ func ExampleExecuteWrite() { driver, err := createDriver() handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer handleClose(ctx, session) person := readPersonFromRequest() @@ -84,7 +86,7 @@ func ExampleExecuteRead() { driver, err := createDriver() handleError(err) defer handleClose(ctx, driver) - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) defer handleClose(ctx, session) personLogin := readPersonLoginFromRequest() diff --git a/neo4j/transaction_helpers_test.go b/neo4j/transaction_helpers_test.go index a88a906a..30589db8 100644 --- a/neo4j/transaction_helpers_test.go +++ b/neo4j/transaction_helpers_test.go @@ -20,9 +20,12 @@ package neo4j_test import ( "context" "fmt" + "testing" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" . "github.com/neo4j/neo4j-go-driver/v5/neo4j/internal/testutil" - "testing" ) func TestExecuteRead(outer *testing.T) { @@ -79,7 +82,7 @@ type fakeSession struct { neo4j.SessionWithContext } -func (f *fakeSession) LastBookmarks() neo4j.Bookmarks { +func (f *fakeSession) LastBookmarks() bm.Bookmarks { panic("implement me") } @@ -88,19 +91,19 @@ func (f *fakeSession) lastBookmark() string { panic("implement me") } -func (f *fakeSession) BeginTransaction(ctx context.Context, configurers ...func(*neo4j.TransactionConfig)) (neo4j.ExplicitTransaction, error) { +func (f *fakeSession) BeginTransaction(ctx context.Context, configurers ...func(*config.TransactionConfig)) (neo4j.ExplicitTransaction, error) { panic("implement me") } -func (f *fakeSession) ExecuteRead(_ context.Context, work neo4j.ManagedTransactionWork, _ ...func(*neo4j.TransactionConfig)) (any, error) { +func (f *fakeSession) ExecuteRead(_ context.Context, work neo4j.ManagedTransactionWork, _ ...func(*config.TransactionConfig)) (any, error) { return work(&FakeTransaction{}) } -func (f *fakeSession) ExecuteWrite(_ context.Context, work neo4j.ManagedTransactionWork, _ ...func(*neo4j.TransactionConfig)) (any, error) { +func (f *fakeSession) ExecuteWrite(_ context.Context, work neo4j.ManagedTransactionWork, _ ...func(*config.TransactionConfig)) (any, error) { return work(&FakeTransaction{}) } -func (f *fakeSession) Run(context.Context, string, map[string]any, ...func(*neo4j.TransactionConfig)) (neo4j.ResultWithContext, error) { +func (f *fakeSession) Run(context.Context, string, map[string]any, ...func(*config.TransactionConfig)) (neo4j.ResultWithContext, error) { panic("implement me") } diff --git a/test-stress/bigdata.go b/test-stress/bigdata.go index 7311dadb..42c6c9d4 100644 --- a/test-stress/bigdata.go +++ b/test-stress/bigdata.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) func nCopiesInt(n int, x int) []int { @@ -105,7 +106,7 @@ func runBigDataThing(ctx context.Context, driver neo4j.DriverWithContext) { const nodeCount = 30000 // Write nodes - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) for index := 0; index < nodeCount; { _, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { batch := 0 diff --git a/test-stress/clean.go b/test-stress/clean.go index f99fddaf..0910fefb 100644 --- a/test-stress/clean.go +++ b/test-stress/clean.go @@ -19,11 +19,13 @@ package main import ( "context" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) func cleanDb(ctx context.Context, driver neo4j.DriverWithContext) { - session := driver.NewSession(ctx, neo4j.SessionConfig{}) + session := driver.NewSession(ctx, config.SessionConfig{}) batch := 1000 for { x, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { diff --git a/test-stress/executors.go b/test-stress/executors.go index 93061796..2c39edcf 100644 --- a/test-stress/executors.go +++ b/test-stress/executors.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" ) func ExpectNoError(err error) { @@ -60,15 +61,15 @@ func ExpectInt(a, b int) { } } -func newStressSession(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool, accessMode neo4j.AccessMode, testContext *TestContext) neo4j.SessionWithContext { +func newStressSession(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool, accessMode config.AccessMode, testContext *TestContext) neo4j.SessionWithContext { var session neo4j.SessionWithContext if useBookmark { - session = driver.NewSession(ctx, neo4j.SessionConfig{ + session = driver.NewSession(ctx, config.SessionConfig{ AccessMode: accessMode, Bookmarks: testContext.getBookmarks(), }) } else { - session = driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: accessMode}) + session = driver.NewSession(ctx, config.SessionConfig{AccessMode: accessMode}) } ExpectNotNil(session) return session @@ -77,7 +78,7 @@ func newStressSession(ctx context.Context, driver neo4j.DriverWithContext, useBo // ReadQueryExecutor returns a new test executor which reads using Session.Run func ReadQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) result, err := session.Run(ctx, "MATCH (n) RETURN n LIMIT 1", nil) @@ -105,7 +106,7 @@ func ReadQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext, useB // ReadQueryInTxExecutor returns a new test executor which reads using Transaction.Run func ReadQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) @@ -140,7 +141,7 @@ func ReadQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext, // ReadQueryWithReadTransactionExecutor returns a new test executor which reads using Session.ExecuteRead func ReadQueryWithReadTransactionExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) summary, err := session.ExecuteRead(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -170,7 +171,7 @@ func ReadQueryWithReadTransactionExecutor(ctx context.Context, driver neo4j.Driv // WriteQueryExecutor returns a new test executor which writes using Session.Run func WriteQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeWrite, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeWrite, testContext) defer session.Close(ctx) result, err := session.Run(ctx, "CREATE ()", nil) @@ -189,7 +190,7 @@ func WriteQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext, use // WriteQueryInTxExecutor returns a new test executor which writes using Transaction.Run func WriteQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeWrite, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeWrite, testContext) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) @@ -215,7 +216,7 @@ func WriteQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext, // VaccuumQueryInTxExecutor returns a new test executor which deletes all data func VaccuumQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeWrite, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeWrite, testContext) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) @@ -240,7 +241,7 @@ func VaccuumQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContex // WriteQueryWithWriteTransactionExecutor returns a new test executor which writes using Session.ExecuteWrite func WriteQueryWithWriteTransactionExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeWrite, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeWrite, testContext) defer session.Close(ctx) summary, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -261,7 +262,7 @@ func WriteQueryWithWriteTransactionExecutor(ctx context.Context, driver neo4j.Dr // WriteQueryInReadSessionExecutor returns a new test executor which tries to perform writes using Session.Run with read access mode func WriteQueryInReadSessionExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) _, err := session.Run(ctx, "CREATE ()", nil) @@ -272,7 +273,7 @@ func WriteQueryInReadSessionExecutor(ctx context.Context, driver neo4j.DriverWit // WriteQueryInTxInReadSessionExecutor returns a new test executor which tries writes using Transaction.Run with read access mode func WriteQueryInTxInReadSessionExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) @@ -287,7 +288,7 @@ func WriteQueryInTxInReadSessionExecutor(ctx context.Context, driver neo4j.Drive // FailingQueryExecutor returns a new test executor which fails in streaming using Session.Run func FailingQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) result, err := session.Run(ctx, "UNWIND [10, 5, 0] AS x RETURN 10 / x", nil) @@ -302,7 +303,7 @@ func FailingQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext, u // FailingQueryInTxExecutor returns a new test executor which fails in streaming using Transaction.Run func FailingQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) @@ -321,7 +322,7 @@ func FailingQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContex // FailingQueryWithReadTransactionExecutor returns a new test executor which fails in streaming using Session.ExecuteRead func FailingQueryWithReadTransactionExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) summary, err := session.ExecuteRead(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -343,7 +344,7 @@ func FailingQueryWithReadTransactionExecutor(ctx context.Context, driver neo4j.D // FailingQueryWithWriteTransactionExecutor returns a new test executor which fails in streaming using Session.ExecuteWrite func FailingQueryWithWriteTransactionExecutor(ctx context.Context, driver neo4j.DriverWithContext, useBookmark bool) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, useBookmark, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, useBookmark, config.AccessModeRead, testContext) defer session.Close(ctx) summary, err := session.ExecuteWrite(ctx, func(tx neo4j.ManagedTransaction) (any, error) { @@ -366,7 +367,7 @@ func FailingQueryWithWriteTransactionExecutor(ctx context.Context, driver neo4j. // WrongQueryExecutor returns a new test executor which fails using Session.Run func WrongQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, false, neo4j.AccessModeRead, testContext) + session := newStressSession(ctx, driver, false, config.AccessModeRead, testContext) defer session.Close(ctx) _, err := session.Run(ctx, "RETURN wrongThing", nil) @@ -377,7 +378,7 @@ func WrongQueryExecutor(ctx context.Context, driver neo4j.DriverWithContext) fun // WrongQueryInTxExecutor returns a new test executor which fails using Transaction.Run func WrongQueryInTxExecutor(ctx context.Context, driver neo4j.DriverWithContext) func(*TestContext) { return func(testContext *TestContext) { - session := newStressSession(ctx, driver, false, neo4j.AccessModeWrite, testContext) + session := newStressSession(ctx, driver, false, config.AccessModeWrite, testContext) defer session.Close(ctx) tx, err := session.BeginTransaction(ctx) diff --git a/test-stress/testcontext.go b/test-stress/testcontext.go index bd90993a..2ef61106 100644 --- a/test-stress/testcontext.go +++ b/test-stress/testcontext.go @@ -23,6 +23,7 @@ import ( "sync/atomic" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" ) // TestContext provides state data shared across tests @@ -48,7 +49,7 @@ func NewTestContext(driver neo4j.DriverWithContext) *TestContext { createdNodeCount: 0, } - result.bookmarks.Store(neo4j.Bookmarks{}) + result.bookmarks.Store(bm.Bookmarks{}) return result } @@ -71,11 +72,11 @@ func (ctx *TestContext) addRead() { atomic.AddInt32(&ctx.readNodeCount, 1) } -func (ctx *TestContext) getBookmarks() neo4j.Bookmarks { - return ctx.bookmarks.Load().(neo4j.Bookmarks) +func (ctx *TestContext) getBookmarks() bm.Bookmarks { + return ctx.bookmarks.Load().(bm.Bookmarks) } -func (ctx *TestContext) setBookmarks(bookmarks neo4j.Bookmarks) { +func (ctx *TestContext) setBookmarks(bookmarks bm.Bookmarks) { ctx.bookmarks.Store(bookmarks) } diff --git a/testkit-backend/backend.go b/testkit-backend/backend.go index 4a539f62..f2170e54 100644 --- a/testkit-backend/backend.go +++ b/testkit-backend/backend.go @@ -23,8 +23,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" - "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" "io" "math" "net/url" @@ -33,6 +31,10 @@ import ( "sync" "time" + bm "github.com/neo4j/neo4j-go-driver/v5/neo4j/bookmarks" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/config" + "github.com/neo4j/neo4j-go-driver/v5/neo4j/notifications" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" "github.com/neo4j/neo4j-go-driver/v5/neo4j/auth" "github.com/neo4j/neo4j-go-driver/v5/neo4j/db" @@ -57,9 +59,9 @@ type backend struct { resolvedBearerTokens map[string]AuthTokenAndExpiration id int // ID to use for next object created by frontend wrLock sync.Mutex - suppliedBookmarks map[string]neo4j.Bookmarks + suppliedBookmarks map[string]bm.Bookmarks consumedBookmarks map[string]struct{} - bookmarkManagers map[string]neo4j.BookmarkManager + bookmarkManagers map[string]bm.BookmarkManager timer *Timer } @@ -131,8 +133,8 @@ func newBackend(rd *bufio.Reader, wr io.Writer) *backend { resolvedBasicTokens: make(map[string]AuthToken), resolvedBearerTokens: make(map[string]AuthTokenAndExpiration), id: 0, - bookmarkManagers: make(map[string]neo4j.BookmarkManager), - suppliedBookmarks: make(map[string]neo4j.Bookmarks), + bookmarkManagers: make(map[string]bm.BookmarkManager), + suppliedBookmarks: make(map[string]bm.Bookmarks), consumedBookmarks: make(map[string]struct{}), } } @@ -294,8 +296,8 @@ func (b *backend) toRequest(s string) map[string]any { return req } -func (b *backend) toTransactionConfigApply(data map[string]any) func(*neo4j.TransactionConfig) { - txConfig := neo4j.TransactionConfig{Timeout: math.MinInt} +func (b *backend) toTransactionConfigApply(data map[string]any) func(*config.TransactionConfig) { + txConfig := config.TransactionConfig{Timeout: math.MinInt} // Optional transaction meta data if data["txMeta"] != nil { txMetadata, err := b.toParams(data["txMeta"].(map[string]any)) @@ -308,7 +310,7 @@ func (b *backend) toTransactionConfigApply(data map[string]any) func(*neo4j.Tran if data["timeout"] != nil { txConfig.Timeout = time.Millisecond * time.Duration(asInt64(data["timeout"].(json.Number))) } - return func(conf *neo4j.TransactionConfig) { + return func(conf *config.TransactionConfig) { if txConfig.Metadata != nil { conf.Metadata = txConfig.Metadata } @@ -448,7 +450,7 @@ func (b *backend) handleRequest(req map[string]any) { case "BookmarksSupplierCompleted": requestId := data["requestId"].(string) rawBookmarks := data["bookmarks"].([]any) - bookmarks := make(neo4j.Bookmarks, len(rawBookmarks)) + bookmarks := make(bm.Bookmarks, len(rawBookmarks)) for i, bookmark := range rawBookmarks { bookmarks[i] = bookmark.(string) } @@ -618,15 +620,15 @@ func (b *backend) handleRequest(req map[string]any) { case "NewSession": driver := b.drivers[data["driverId"].(string)] - sessionConfig := neo4j.SessionConfig{ + sessionConfig := config.SessionConfig{ BoltLogger: &streamLog{writeLine: b.writeLineLocked}, } if data["accessMode"] != nil { switch data["accessMode"].(string) { case "r": - sessionConfig.AccessMode = neo4j.AccessModeRead + sessionConfig.AccessMode = config.AccessModeRead case "w": - sessionConfig.AccessMode = neo4j.AccessModeWrite + sessionConfig.AccessMode = config.AccessModeWrite default: b.writeError(errors.New("Unknown access mode: " + data["accessMode"].(string))) return @@ -638,7 +640,7 @@ func (b *backend) handleRequest(req map[string]any) { for i, x := range rawBookmarks { bookmarks[i] = x.(string) } - sessionConfig.Bookmarks = neo4j.BookmarksFromRawValues(bookmarks...) + sessionConfig.Bookmarks = bm.BookmarksFromRawValues(bookmarks...) } if data["database"] != nil { sessionConfig.DatabaseName = data["database"].(string) @@ -691,7 +693,7 @@ func (b *backend) handleRequest(req map[string]any) { case "NewBookmarkManager": bookmarkManagerId := b.nextId() - b.bookmarkManagers[bookmarkManagerId] = neo4j.NewBookmarkManager( + b.bookmarkManagers[bookmarkManagerId] = bm.NewBookmarkManager( b.bookmarkManagerConfig(bookmarkManagerId, data)) b.writeResponse("BookmarkManager", map[string]any{ "id": bookmarkManagerId, @@ -748,7 +750,7 @@ func (b *backend) handleRequest(req map[string]any) { case "SessionLastBookmarks": sessionState := b.sessionStates[data["sessionId"].(string)] - bookmarks := neo4j.BookmarksToRawValues(sessionState.session.LastBookmarks()) + bookmarks := bm.BookmarksToRawValues(sessionState.session.LastBookmarks()) if bookmarks == nil { bookmarks = []string{} } @@ -905,7 +907,7 @@ func (b *backend) handleRequest(req map[string]any) { case "CheckMultiDBSupport": driver := b.drivers[data["driverId"].(string)] - session := driver.NewSession(ctx, neo4j.SessionConfig{ + session := driver.NewSession(ctx, config.SessionConfig{ BoltLogger: neo4j.ConsoleBoltLogger(), }) result, err := session.Run(ctx, "RETURN 42", nil) @@ -1583,13 +1585,13 @@ func patchNumbersInMap(dictionary map[string]any) error { } func (b *backend) bookmarkManagerConfig(bookmarkManagerId string, - config map[string]any) neo4j.BookmarkManagerConfig { + config map[string]any) bm.BookmarkManagerConfig { - var initialBookmarks neo4j.Bookmarks + var initialBookmarks bm.Bookmarks if config["initialBookmarks"] != nil { initialBookmarks = convertInitialBookmarks(config["initialBookmarks"].([]any)) } - result := neo4j.BookmarkManagerConfig{InitialBookmarks: initialBookmarks} + result := bm.BookmarkManagerConfig{InitialBookmarks: initialBookmarks} supplierRegistered := config["bookmarksSupplierRegistered"] if supplierRegistered != nil && supplierRegistered.(bool) { result.BookmarkSupplier = b.supplyBookmarks(bookmarkManagerId) @@ -1601,8 +1603,8 @@ func (b *backend) bookmarkManagerConfig(bookmarkManagerId string, return result } -func (b *backend) supplyBookmarks(bookmarkManagerId string) func(context.Context) (neo4j.Bookmarks, error) { - return func(ctx context.Context) (neo4j.Bookmarks, error) { +func (b *backend) supplyBookmarks(bookmarkManagerId string) func(context.Context) (bm.Bookmarks, error) { + return func(ctx context.Context) (bm.Bookmarks, error) { id := b.nextId() msg := map[string]any{"id": id, "bookmarkManagerId": bookmarkManagerId} b.writeResponse("BookmarksSupplierRequest", msg) @@ -1611,8 +1613,8 @@ func (b *backend) supplyBookmarks(bookmarkManagerId string) func(context.Context } } -func (b *backend) consumeBookmarks(bookmarkManagerId string) func(context.Context, neo4j.Bookmarks) error { - return func(_ context.Context, bookmarks neo4j.Bookmarks) error { +func (b *backend) consumeBookmarks(bookmarkManagerId string) func(context.Context, bm.Bookmarks) error { + return func(_ context.Context, bookmarks bm.Bookmarks) error { id := b.nextId() b.writeResponse("BookmarksConsumerRequest", map[string]any{ "id": id, @@ -1629,8 +1631,8 @@ func (b *backend) consumeBookmarks(bookmarkManagerId string) func(context.Contex } } -func convertInitialBookmarks(bookmarks []any) neo4j.Bookmarks { - result := make(neo4j.Bookmarks, len(bookmarks)) +func convertInitialBookmarks(bookmarks []any) bm.Bookmarks { + result := make(bm.Bookmarks, len(bookmarks)) for i, bookmark := range bookmarks { result[i] = bookmark.(string) }