Skip to content

Commit

Permalink
Merge pull request #111 from tangyang9464/master
Browse files Browse the repository at this point in the history
feat: adds multiple databases support to gorm-adapter by DBResolver
  • Loading branch information
hsluoyz authored Jun 16, 2021
2 parents b448b9d + 2900499 commit 9500f7f
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
test:
runs-on: ubuntu-latest

services:
services:
mysql:
image: mysql
env:
Expand Down
49 changes: 49 additions & 0 deletions adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/plugin/dbresolver"
)

const (
Expand Down Expand Up @@ -89,6 +90,24 @@ func finalizer(a *Adapter) {
}
}

//Select conn according to table name(use map store name-index)
type specificPolicy int

func (p *specificPolicy) Resolve(connPools []gorm.ConnPool) gorm.ConnPool {
return connPools[*p]
}

type DbPool struct {
dbMap map[string]specificPolicy
policy *specificPolicy
source *gorm.DB
}

func (dbPool *DbPool) switchDb(dbName string) *gorm.DB {
*dbPool.policy = dbPool.dbMap[dbName]
return dbPool.source.Clauses(dbresolver.Write)
}

// NewAdapter is the constructor for Adapter.
// Params : databaseName,tableName,dbSpecified
// databaseName,{tableName/dbSpecified}
Expand Down Expand Up @@ -182,6 +201,36 @@ func NewAdapterByDBUseTableName(db *gorm.DB, prefix string, tableName string) (*
return a, nil
}

// InitDbResolver multiple databases support
// Example usage:
// dbPool,err := InitDbResolver([]gorm.Dialector{mysql.Open(dsn),mysql.Open(dsn2)},[]string{"casbin1","casbin2"})
// a := initAdapterWithGormInstanceByMulDb(t,dbPool,"casbin1","","casbin_rule1")
// a = initAdapterWithGormInstanceByMulDb(t,dbPool,"casbin2","","casbin_rule2")/*
func InitDbResolver(dbArr []gorm.Dialector, dbNames []string) (DbPool, error) {
if len(dbArr) == 0 {
panic("dbArr len is 0")
}
source, e := gorm.Open(dbArr[0])
if e != nil {
panic(e.Error())
}
var p specificPolicy
p = 0
err := source.Use(dbresolver.Register(dbresolver.Config{Policy: &p, Sources: dbArr}))
dbMap := make(map[string]specificPolicy)
for i := 0; i < len(dbNames); i++ {
dbMap[dbNames[i]] = specificPolicy(i)
}
return DbPool{dbMap: dbMap, policy: &p, source: source}, err
}

func NewAdapterByMulDb(dbPool DbPool, dbName string, prefix string, tableName string) (*Adapter, error) {
//change DB
dbPool.switchDb(dbName)

return NewAdapterByDBUseTableName(dbPool.source, prefix, tableName)
}

// NewFilteredAdapter is the constructor for FilteredAdapter.
// Casbin will not automatically call LoadPolicy() for a filtered adapter.
func NewFilteredAdapter(driverName string, dataSourceName string, params ...interface{}) (*Adapter, error) {
Expand Down
66 changes: 65 additions & 1 deletion adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ func testSaveLoad(t *testing.T, a *Adapter) {
// Now the DB has policy, so we can provide a normal use case.
// Create an adapter and an enforcer.
// NewEnforcer() will load the policy automatically.

e, _ := casbin.NewEnforcer("examples/rbac_model.conf", a)
testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}, {"bob", "data2", "write"}, {"data2_admin", "data2", "read"}, {"data2_admin", "data2", "write"}})
}
Expand Down Expand Up @@ -189,6 +188,18 @@ func initAdapterWithGormInstanceByName(t *testing.T, db *gorm.DB, name string) *
return a
}

func initAdapterWithGormInstanceByMulDb(t *testing.T, dbPool DbPool, dbName string, prefix string, tableName string) *Adapter {
//Create an Adapter
a, _ := NewAdapterByMulDb(dbPool, dbName, prefix, tableName)
// Initialize some policy in DB.
initPolicy(t, a)
// Now the DB has policy, so we can provide a normal use case.
// Note: you don't need to look at the above code
// if you already have a working DB with policy inside.

return a
}

func initAdapterWithGormInstanceByPrefixAndName(t *testing.T, db *gorm.DB, prefix, name string) *Adapter {
//Create an Adapter
a, _ := NewAdapterByDBUseTableName(db, prefix, name)
Expand Down Expand Up @@ -339,6 +350,59 @@ func TestAdapterWithCustomTable(t *testing.T) {
testFilteredPolicy(t, a)
}

func TestAdapterWithMulDb(t *testing.T) {
//create new database
NewAdapter("mysql", "root:@tcp(127.0.0.1:3306)/", "casbin")
NewAdapter("mysql", "root:@tcp(127.0.0.1:3306)/", "casbin2")

testBasicFeatures(t)
testIndependenceBetweenMulDb(t)
}

func testIndependenceBetweenMulDb(t *testing.T) {
dsn := "root:@tcp(127.0.0.1:3306)/casbin"
dsn2 := "root:@tcp(127.0.0.1:3306)/casbin2"

dbPool, err := InitDbResolver([]gorm.Dialector{mysql.Open(dsn), mysql.Open(dsn2)}, []string{"casbin", "casbin2"})

if err != nil {
panic(err)
}

//test independence between multi adapter
a1 := initAdapterWithGormInstanceByMulDb(t, dbPool, "casbin", "", "casbin_rule")
a1.AddPolicy("p", "p", []string{"alice", "book", "read"})
a2 := initAdapterWithGormInstanceByMulDb(t, dbPool, "casbin2", "", "casbin_rule2")
e, _ := casbin.NewEnforcer("./examples/rbac_model.conf", a2)
res, err := e.Enforce("alice", "book", "read")
if err != nil || res {
t.Error("switch DB fail because data don't change")
}
}

func testBasicFeatures(t *testing.T) {
dsn := "root:@tcp(127.0.0.1:3306)/casbin"
dsn2 := "root:@tcp(127.0.0.1:3306)/casbin2"

dbPool, err := InitDbResolver([]gorm.Dialector{mysql.Open(dsn), mysql.Open(dsn2)}, []string{"casbin", "casbin2"})

if err != nil {
panic(err)
}
//test basic features
a := initAdapterWithGormInstanceByMulDb(t, dbPool, "casbin", "", "casbin_rule")
testAutoSave(t, a)
testSaveLoad(t, a)
a = initAdapterWithGormInstanceByMulDb(t, dbPool, "casbin", "", "casbin_rule")
testFilteredPolicy(t, a)

a = initAdapterWithGormInstanceByMulDb(t, dbPool, "casbin2", "", "casbin_rule2")
testAutoSave(t, a)
testSaveLoad(t, a)
a = initAdapterWithGormInstanceByMulDb(t, dbPool, "casbin2", "", "casbin_rule2")
testFilteredPolicy(t, a)
}

func TestAdapters(t *testing.T) {
a := initAdapter(t, "mysql", "root:@tcp(127.0.0.1:3306)/", "casbin", "casbin_rule")
testAutoSave(t, a)
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ require (
github.com/jackc/pgconn v1.8.0
github.com/lib/pq v1.8.0
github.com/stretchr/testify v1.6.1
gorm.io/driver/mysql v1.0.1
gorm.io/driver/mysql v1.0.3
gorm.io/driver/postgres v1.0.8
gorm.io/driver/sqlserver v1.0.4
gorm.io/gorm v1.21.9
gorm.io/plugin/dbresolver v1.1.0
)
9 changes: 6 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,18 @@ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:a
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.1 h1:omJoilUzyrAp0xNoio88lGJCroGdIOen9hq2A/+3ifw=
gorm.io/driver/mysql v1.0.1/go.mod h1:KtqSthtg55lFp3S5kUXqlGaelnWpKitn4k1xZTnoiPw=
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
gorm.io/driver/postgres v1.0.8 h1:PAgM+PaHOSAeroTjHkCHCBIHHoBIf9RgPWGo8dF2DA8=
gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg=
gorm.io/driver/sqlserver v1.0.4 h1:V15fszi0XAo7fbx3/cF50ngshDSN4QT0MXpWTylyPTY=
gorm.io/driver/sqlserver v1.0.4/go.mod h1:ciEo5btfITTBCj9BkoUVDvgQbUdLWQNqdFY5OGuGnRg=
gorm.io/gorm v1.9.19/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.0/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.9 h1:INieZtn4P2Pw6xPJ8MzT0G4WUOsHq3RhfuDF1M6GW0E=
gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/plugin/dbresolver v1.1.0 h1:cegr4DeprR6SkLIQlKhJLYxH8muFbJ4SmnojXvoeb00=
gorm.io/plugin/dbresolver v1.1.0/go.mod h1:tpImigFAEejCALOttyhWqsy4vfa2Uh/vAUVnL5IRF7Y=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

0 comments on commit 9500f7f

Please sign in to comment.