Skip to content

Commit

Permalink
Add ExecuteQueryWithTransactionConfig option for ExecuteQuery (#553)
Browse files Browse the repository at this point in the history
* Add a new configuration option
  • Loading branch information
StephenCathcart authored Dec 8, 2023
1 parent 8602aef commit 4354f3a
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 24 deletions.
20 changes: 14 additions & 6 deletions neo4j/driver_with_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down
28 changes: 20 additions & 8 deletions neo4j/transaction_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
37 changes: 27 additions & 10 deletions testkit-backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)))
}
})
}

Expand Down

0 comments on commit 4354f3a

Please sign in to comment.