diff --git a/neo4j/driver_with_context.go b/neo4j/driver_with_context.go index 31cf7cb0..a5cf2233 100644 --- a/neo4j/driver_with_context.go +++ b/neo4j/driver_with_context.go @@ -535,7 +535,7 @@ func ExecuteQuery[T any]( if err != nil { return *new(T), err } - result, err := txFunction(ctx, executeQueryCallback(ctx, query, parameters, newResultTransformer)) + result, err := txFunction(ctx, executeQueryCallback(ctx, query, parameters, newResultTransformer), configuration.TransactionConfigurers...) if err != nil { return *new(T), err } @@ -660,13 +660,21 @@ func ExecuteQueryWithBoltLogger(boltLogger log.BoltLogger) ExecuteQueryConfigura } } +// ExecuteQueryWithTransactionConfig configures DriverWithContext.ExecuteQuery with additional transaction configuration. +func ExecuteQueryWithTransactionConfig(configurers ...func(*TransactionConfig)) ExecuteQueryConfigurationOption { + return func(configuration *ExecuteQueryConfiguration) { + configuration.TransactionConfigurers = configurers + } +} + // ExecuteQueryConfiguration holds all the possible configuration settings for DriverWithContext.ExecuteQuery type ExecuteQueryConfiguration struct { - Routing RoutingControl - ImpersonatedUser string - Database string - BookmarkManager BookmarkManager - BoltLogger log.BoltLogger + Routing RoutingControl + ImpersonatedUser string + Database string + BookmarkManager BookmarkManager + BoltLogger log.BoltLogger + TransactionConfigurers []func(*TransactionConfig) } // RoutingControl specifies how the query executed by DriverWithContext.ExecuteQuery is to be routed diff --git a/neo4j/transaction_config.go b/neo4j/transaction_config.go index 4f86aae5..f7cca870 100644 --- a/neo4j/transaction_config.go +++ b/neo4j/transaction_config.go @@ -56,6 +56,12 @@ type TransactionConfig struct { // To apply a transaction timeout to a write transaction function: // // session.ExecuteWrite(DoWork, WithTxTimeout(5*time.Second)) +// +// To apply a transaction timeout with the ExecuteQuery function, use ExecuteQueryWithTransactionConfig: +// +// ExecuteQuery(ctx, driver, query, parameters, transformer, +// ExecuteQueryWithTransactionConfig(WithTxTimeout(*time.Second)) +// ) func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { return func(config *TransactionConfig) { config.Timeout = timeout @@ -64,21 +70,27 @@ func WithTxTimeout(timeout time.Duration) func(*TransactionConfig) { // WithTxMetadata returns a transaction configuration function that attaches metadata to a transaction. // -// To attach a metadata to an explicit transaction: +// To attach metadata to an explicit transaction: +// +// session.BeginTransaction(WithTxMetadata(map[string]any{"work-id": 1})) +// +// To attach metadata to an auto-commit transaction: // -// session.BeginTransaction(WithTxMetadata(map[string)any{"work-id": 1})) +// session.Run("RETURN 1", nil, WithTxMetadata(map[string]any{"work-id": 1})) // -// To attach a metadata to an auto-commit transaction: +// To attach metadata to a read transaction function: // -// session.Run("RETURN 1", nil, WithTxMetadata(map[string)any{"work-id": 1})) +// session.ExecuteRead(DoWork, WithTxMetadata(map[string]any{"work-id": 1})) // -// To attach a metadata to a read transaction function: +// To attach metadata to a write transaction function: // -// session.ExecuteRead(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) +// session.ExecuteWrite(DoWork, WithTxMetadata(map[string]any{"work-id": 1})) // -// To attach a metadata to a write transaction function: +// To attach metadata with the ExecuteQuery function, use ExecuteQueryWithTransactionConfig: // -// session.ExecuteWrite(DoWork, WithTxMetadata(map[string)any{"work-id": 1})) +// ExecuteQuery(ctx, driver, query, parameters, transformer, +// ExecuteQueryWithTransactionConfig(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/testkit-backend/backend.go b/testkit-backend/backend.go index 4a539f62..4e41ee1f 100644 --- a/testkit-backend/backend.go +++ b/testkit-backend/backend.go @@ -297,17 +297,9 @@ func (b *backend) toRequest(s string) map[string]any { func (b *backend) toTransactionConfigApply(data map[string]any) func(*neo4j.TransactionConfig) { txConfig := neo4j.TransactionConfig{Timeout: math.MinInt} // Optional transaction meta data - if data["txMeta"] != nil { - txMetadata, err := b.toParams(data["txMeta"].(map[string]any)) - if err != nil { - panic(err) - } - txConfig.Metadata = txMetadata - } + txConfig.Metadata = b.toTxMetadata(data) // Optional timeout in milliseconds - if data["timeout"] != nil { - txConfig.Timeout = time.Millisecond * time.Duration(asInt64(data["timeout"].(json.Number))) - } + txConfig.Timeout = b.toTimeout(data) return func(conf *neo4j.TransactionConfig) { if txConfig.Metadata != nil { conf.Metadata = txConfig.Metadata @@ -318,6 +310,24 @@ func (b *backend) toTransactionConfigApply(data map[string]any) func(*neo4j.Tran } } +func (b *backend) toTxMetadata(data map[string]any) map[string]any { + if data["txMeta"] != nil { + txMetadata, err := b.toParams(data["txMeta"].(map[string]any)) + if err != nil { + panic(err) + } + return txMetadata + } + return nil +} + +func (b *backend) toTimeout(data map[string]any) time.Duration { + if data["timeout"] != nil { + return time.Millisecond * time.Duration(asInt64(data["timeout"].(json.Number))) + } + return math.MinInt +} + func (b *backend) toCypherAndParams(data map[string]any) (string, map[string]any, error) { rawParameters, _ := data["params"].(map[string]any) parameters, err := b.toParams(rawParameters) @@ -596,6 +606,13 @@ func (b *backend) handleRequest(req map[string]any) { config.BookmarkManager = b.bookmarkManagers[bookmarkManagerId.(string)] } } + // Append configurers to config if they exist. + if executeQueryConfig["timeout"] != nil { + config.TransactionConfigurers = append(config.TransactionConfigurers, neo4j.WithTxTimeout(b.toTimeout(executeQueryConfig))) + } + if executeQueryConfig["txMeta"] != nil { + config.TransactionConfigurers = append(config.TransactionConfigurers, neo4j.WithTxMetadata(b.toTxMetadata(executeQueryConfig))) + } }) }