This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin.git
The following commit(s) were added to refs/heads/master by this push:
new 9a94fde feat: expose Transaction.GetAdapter() to share the tx with
GORM
9a94fde is described below
commit 9a94fde4757836d1327ac8f8df0877ffc97ca66b
Author: Yang Luo <[email protected]>
AuthorDate: Thu Aug 6 23:14:57 2026 +0800
feat: expose Transaction.GetAdapter() to share the tx with GORM
---
transaction.go | 22 +++++++++++++++++++
transaction_adapter_test.go | 51 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/transaction.go b/transaction.go
index 7c921ca..387432c 100644
--- a/transaction.go
+++ b/transaction.go
@@ -48,6 +48,28 @@ type Transaction struct {
mutex sync.RWMutex // Protects transaction state.
}
+// GetAdapter returns the adapter that operates within this transaction.
+// Writes done through it join the same database transaction as the buffered
+// policy changes, so non-policy operations can be made atomic together with
the
+// policy changes, e.g. with the GORM adapter:
+//
+// err := e.WithTransaction(ctx, func(tx *casbin.Transaction) error {
+// db := tx.GetAdapter().(*gormadapter.Adapter).GetDb().
+// Session(&gorm.Session{NewDB: true})
+// if err := db.Where("name = ?", "admin").Delete(&Role{}).Error;
err != nil {
+// return err
+// }
+// _, err := tx.RemoveGroupingPolicy("alice", "admin")
+// return err
+// })
+//
+// Mind the Session(&gorm.Session{NewDB: true}): the GORM adapter pins its
+// *gorm.DB to the policy table, and without resetting the statement every
query
+// would silently run against casbin_rule instead of the caller's own table.
+func (tx *Transaction) GetAdapter() persist.Adapter {
+ return tx.txContext.GetAdapter()
+}
+
// AddPolicy adds a policy within the transaction.
// The policy is buffered and will be applied when the transaction is
committed.
func (tx *Transaction) AddPolicy(params ...interface{}) (bool, error) {
diff --git a/transaction_adapter_test.go b/transaction_adapter_test.go
new file mode 100644
index 0000000..e38fa4d
--- /dev/null
+++ b/transaction_adapter_test.go
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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
+//
+// http://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 casbin
+
+import (
+ "context"
+ "testing"
+)
+
+// GetAdapter hands out the transaction scoped adapter, so the caller can run
+// its own database operations in the same transaction as the policy changes.
+// See https://github.com/casbin/casbin/issues/1706.
+func TestTransactionGetAdapter(t *testing.T) {
+ adapter := NewMockTransactionalAdapter()
+ e, err := NewTransactionalEnforcer("examples/rbac_model.conf", adapter)
+ if err != nil {
+ t.Fatalf("Failed to create transactional enforcer: %v", err)
+ }
+
+ err = e.WithTransaction(context.Background(), func(tx *Transaction)
error {
+ // The adapter of the transaction, not the one of the enforcer:
for a
+ // real adapter this is the one bound to the open database
transaction.
+ if tx.GetAdapter() == nil {
+ t.Error("The transaction scoped adapter should be
reachable")
+ }
+ _, addErr := tx.AddPolicy("admin", "data1", "read")
+ return addErr
+ })
+ if err != nil {
+ t.Fatalf("Failed to run transaction: %v", err)
+ }
+
+ if ok, err := e.HasPolicy("admin", "data1", "read"); err != nil || !ok {
+ t.Fatalf("The policy added in the transaction should be in
effect, got %v, %v", ok, err)
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]