Skip to content

Commit

Permalink
first
Browse files Browse the repository at this point in the history
  • Loading branch information
stefano-ottolenghi committed Nov 17, 2023
1 parent 558b9f8 commit b1a6f10
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 21 deletions.
9 changes: 4 additions & 5 deletions go-manual/modules/ROOT/pages/query-simple.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Query parameters should get grouped into a map and passed as second parameter to

[source, go]
----
parameters = map[string]any{
parameters := map[string]any{
"name": "Alice",
"age": 42,
}
Expand Down Expand Up @@ -218,7 +218,7 @@ neo4j.ExecuteQuery(ctx, driver,
"MATCH (p:Person) RETURN p.name",
nil,
neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j")
neo4j.ExecuteQueryWithDatabase("neo4j"),
neo4j.ExecuteQueryWithReadersRouting())
----

Expand All @@ -239,9 +239,8 @@ neo4j.ExecuteQuery(ctx, driver,
"MATCH (p:Person) RETURN p.name",
nil,
neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j")
neo4j.ExecuteQueryWithDatabase("neo4j"),
neo4j.ExecuteQueryWithImpersonatedUser("<somebodyElse>"))
)
----

When impersonating a user, the query is run within the complete security context of the impersonated user and not the authenticated user (i.e., home database, permissions, etc.).
Expand All @@ -263,7 +262,7 @@ func main() {
ctx := context.Background()
// Connection to database
dbUri := "<URI to Neo4j database>"
dbUri := "<URI for Neo4j database>"
dbUser := "<Username>"
dbPassword := "<Password>"
driver, err := neo4j.NewDriverWithContext(
Expand Down
91 changes: 75 additions & 16 deletions go-manual/modules/ROOT/pages/transactions.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Within a transaction function, a `return` statement where `error` is `nil` resul
.A transaction with multiple queries, client logic, and potential roll backs
[source, go]
----
ppackage main
package main
import (
"fmt"
Expand All @@ -96,7 +96,7 @@ func main() {
var employeeThreshold int64 = 10 // Neo4j's integer maps to Go's int64
// Connection to database
dbUri := "<URI to Neo4j database>"
dbUri := "<URI for Neo4j database>"
dbUser := "<Username>"
dbPassword := "<Password>"
driver, err := neo4j.NewDriverWithContext(
Expand Down Expand Up @@ -252,7 +252,10 @@ You run queries inside an explicit transaction with the method link:https://pkg.
----
session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "neo4j"})
defer session.Close(ctx)
tx := session.BeginTransaction(ctx)
tx, err := session.BeginTransaction(ctx)
if err != nil {
panic(err)
}
// use tx.Run() to run queries
// tx.Commit() to commit the transaction
// tx.Rollback() to rollback the transaction
Expand All @@ -265,22 +268,72 @@ Explicit transactions are most useful for applications that need to distribute C
.A sketch of an explicit transaction interacting with external APIs
[source, go]
----
func transferToOtherBank(driver neo4j.DriverWithContext, customerId string, otherBankId string, amount float) {
package main
import (
"fmt"
"context"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)
func main() {
ctx := context.Background()
// Connection to database
dbUri := "<URI for Neo4j database>"
dbUser := "<Username>"
dbPassword := "<Password>"
driver, err := neo4j.NewDriverWithContext(
dbUri,
neo4j.BasicAuth(dbUser, dbPassword, ""))
if err != nil {
panic(err)
}
defer driver.Close(ctx)
err = driver.VerifyConnectivity(ctx)
if err != nil {
panic(err)
}
customerId, err := createCustomer(ctx, driver)
if err != nil {
panic(err)
}
otherBankId := 42
transferToOtherBank(ctx, driver, customerId, otherBankId, 999)
}
func createCustomer(ctx context.Context, driver neo4j.DriverWithContext) (string, error) {
result, err := neo4j.ExecuteQuery(ctx, driver, `
MERGE (c:Customer {id: randomUUID()})
RETURN c.id AS id
`, nil,
neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
if err != nil {
return "", err
}
customerId, _ := result.Records[0].Get("id")
return customerId.(string), err
}
func transferToOtherBank(ctx context.Context, driver neo4j.DriverWithContext, customerId string, otherBankId int, amount float32) {
session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "neo4j"})
defer session.Close(ctx)
tx := session.BeginTransaction(ctx)
tx, err := session.BeginTransaction(ctx)
if err != nil {
panic(err)
}
if ! customerBalanceCheck(ctx, tx, customerId, amount) {
// give up
return nil
return
}
otherBankTransferApi(ctx, customerId, otherBankId, amount)
// Now the money has been transferred => can't rollback anymore
// (cannot rollback external services interactions)
err := decreaseCustomerBalance(ctx, tx, customerId, amount)
err = decreaseCustomerBalance(ctx, tx, customerId, amount)
if err != nil {
requestInspection(ctx, customerId, otherBankId, amount, err)
}
Expand All @@ -290,26 +343,31 @@ func transferToOtherBank(driver neo4j.DriverWithContext, customerId string, othe
}
}
func customerBalanceCheck(ctx context.Context, tx neo4j.ExplicitTransaction, customerId string, amount float) (bool) {
result = tx.Run(ctx, `
func customerBalanceCheck(ctx context.Context, tx neo4j.ExplicitTransaction, customerId string, amount float32) (bool) {
result, err := tx.Run(ctx, `
MATCH (c:Customer {id: $id})
RETURN c.balance >= $amount AS sufficient
`, map[string]any{
"id": customerId,
"amount": amount,
})
if err == nil {
return false
}
record, err := result.Single(ctx)
if err != nil {
if err == nil {
return false
}
return record.AsMap()["sufficient"]
sufficient := record.AsMap()["sufficient"]
return sufficient.(bool)
}
func otherBankTransferApi(ctx context.Context, customerId string, otherBankId string, amount float):
...
func otherBankTransferApi(ctx context.Context, customerId string, otherBankId int, amount float32) {
// make some API call to other bank
}
func decreaseCustomerBalance(ctx context.Context, tx neo4j.ExplicitTransaction, customerId string, amount float) (error) {
_, err = tx.Run(ctx, `
func decreaseCustomerBalance(ctx context.Context, tx neo4j.ExplicitTransaction, customerId string, amount float32) (error) {
_, err := tx.Run(ctx, `
MATCH (c:Customer {id: $id})
SET c.balance = c.balance - $amount
`, map[string]any{
Expand All @@ -319,10 +377,11 @@ func decreaseCustomerBalance(ctx context.Context, tx neo4j.ExplicitTransaction,
return err
}
func requestInspection(ctx context.Context, customerId string, otherBankId string, amount float, err error):
func requestInspection(ctx context.Context, customerId string, otherBankId int, amount float32, err error) {
// manual cleanup required; log this or similar
fmt.Println("WARNING: transaction rolled back due to exception:", err)
fmt.Println("customerId:", customerId, "otherBankId:", otherBankId, "amount:", amount)
}
----


Expand Down

0 comments on commit b1a6f10

Please sign in to comment.