Skip to content

Commit

Permalink
feat: support transaction (#176)
Browse files Browse the repository at this point in the history
* feat: support transaction

* feat: add tx options

* feat: transaction return error

* feat: replace enforcer to interface IEnforcer; reload policy at the end of transaction

* Update adapter.go

* feat: add to README about the new transaction usage

Co-authored-by: Yang Luo <[email protected]>
  • Loading branch information
VaneLord67 and hsluoyz authored Aug 28, 2022
1 parent e137c23 commit e1dae28
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,31 @@ func main() {
e.SavePolicy()
}
```
## Transaction
You can modify policies within a transaction.See example:
```go
package main

func main() {
a, err := NewAdapterByDB(db)
e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a)
err = e.GetAdapter().(*Adapter).Transaction(e, func(e casbin.IEnforcer) error {
_, err := e.AddPolicy("jack", "data1", "write")
if err != nil {
return err
}
_, err = e.AddPolicy("jack", "data2", "write")
if err != nil {
return err
}
return nil
})
if err != nil {
// handle if transaction failed
return
}
}
```
## Getting Help

- [Casbin](https://github.com/casbin/casbin)
Expand Down
29 changes: 29 additions & 0 deletions adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ package gormadapter

import (
"context"
"database/sql"
"errors"
"fmt"
"runtime"
"strings"

"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
"github.com/casbin/casbin/v2/persist"
"github.com/glebarez/sqlite"
Expand Down Expand Up @@ -611,6 +613,33 @@ func (a *Adapter) AddPolicies(sec string, ptype string, rules [][]string) error
return a.db.Create(&lines).Error
}

// Transaction perform a set of operations within a transaction
func (a *Adapter) Transaction(e casbin.IEnforcer, fc func(casbin.IEnforcer) error, opts ...*sql.TxOptions) error {
var err error
oriAdapter := a.db
// reload policy from database to sync with the transaction
defer func() {
e.SetAdapter(&Adapter{db: oriAdapter})
err = e.LoadPolicy()
if err != nil {
panic(err)
}
}()
copyDB := *a.db
tx := copyDB.Begin(opts...)
b := &Adapter{db: tx}
// copy enforcer to set the new adapter with transaction tx
copyEnforcer := e
copyEnforcer.SetAdapter(b)
err = fc(copyEnforcer)
if err != nil {
tx.Rollback()
return err
}
err = tx.Commit().Error
return err
}

// RemovePolicies removes multiple policy rules from the storage.
func (a *Adapter) RemovePolicies(sec string, ptype string, rules [][]string) error {
return a.db.Transaction(func(tx *gorm.DB) error {
Expand Down
20 changes: 20 additions & 0 deletions adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -628,3 +628,23 @@ func TestAddPolicies(t *testing.T) {

testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}, {"jack", "data1", "read"}, {"jack2", "data1", "read"}})
}

func TestTransaction(t *testing.T) {
a := initAdapter(t, "mysql", "root:@tcp(127.0.0.1:3306)/", "casbin", "casbin_rule")
e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a)
err := e.GetAdapter().(*Adapter).Transaction(e, func(e casbin.IEnforcer) error {
_, err := e.AddPolicy("jack", "data1", "write")
if err != nil {
return err
}
_, err = e.AddPolicy("jack", "data2", "write")
//err = errors.New("some error")
if err != nil {
return err
}
return nil
})
if err != nil {
return
}
}

0 comments on commit e1dae28

Please sign in to comment.