Skip to content

Commit

Permalink
feat(scopes): Update WithTenantSchema to support pointer to array/s…
Browse files Browse the repository at this point in the history
…lice of structs

This commit modifies the `scopes` package to improve the logic for retrieving table names. The previous `tableNameFromReflectValue` was renamed to  `tableNameFromInterface`. Additionally, the `tableNameFromReflectValue` is now responsible for handling reflect values of arrays, and slices. These changes enhance the reliability and flexibility of table name retrieval in the `scopes` package.
  • Loading branch information
bartventer committed May 23, 2024
1 parent b699143 commit b0682b8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 10 deletions.
29 changes: 24 additions & 5 deletions scopes/scopes.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Package scopes provides a set of predefined GORM scopes for managing multi-tenan
package scopes

import (
"errors"
"reflect"

"gorm.io/gorm"
"gorm.io/gorm/schema"
)
Expand Down Expand Up @@ -44,11 +47,15 @@ func WithTenantSchema(tenant string) func(db *gorm.DB) *gorm.DB {
case db.Statement.Table != "":
tn = db.Statement.Table
case db.Statement.Model != nil:
tn = tableNameFromReflectValue(db.Statement.Model)
tn = tableNameFromInterface(db.Statement.Model)
case db.Statement.Dest != nil:
tn = tableNameFromReflectValue(db.Statement.Dest)
destPtr := reflect.ValueOf(db.Statement.Dest)
if destPtr.Kind() != reflect.Ptr {
_ = db.AddError(errors.New("destination must be a pointer"))
} else {
tn = tableNameFromReflectValue(db.Statement.Dest)
}
}

if tn != "" {
return db.Table(tenant + "." + tn)
}
Expand All @@ -58,10 +65,22 @@ func WithTenantSchema(tenant string) func(db *gorm.DB) *gorm.DB {
}
}

// tableNameFromReflectValue returns the table name from the model.
func tableNameFromReflectValue(val interface{}) string {
// tableNameFromInterface returns the table name from a interface.
func tableNameFromInterface(val interface{}) string {
if s, ok := val.(schema.Tabler); ok {
return s.TableName()
}
return ""
}

// tableNameFromReflectValue returns the table name from a reflect.Value.
func tableNameFromReflectValue(valPtr interface{}) string {
val := reflect.ValueOf(valPtr).Elem()
if val.Kind() == reflect.Struct {
return tableNameFromInterface(val.Interface())
}
if val.Kind() == reflect.Slice || val.Kind() == reflect.Array {
return tableNameFromInterface(reflect.New(val.Type().Elem()).Interface())
}
return ""
}
31 changes: 26 additions & 5 deletions scopes/scopes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,42 @@ func TestWithTenantSchema(t *testing.T) {
expected string
}{
{
name: "test-with-tenant-schema",
name: "valid: with table name set",
queryFn: func(tx *gorm.DB) *gorm.DB {
return tx.Table("books").Scopes(WithTenantSchema("tenant2")).Find(&Book{})
},
expected: `SELECT * FROM "tenant2"."books"`,
},
{
name: "valid: with model set",
queryFn: func(tx *gorm.DB) *gorm.DB {
return tx.Model(&Book{}).Scopes(WithTenantSchema("tenant1")).Find(&Book{})
},
expected: `SELECT * FROM "tenant1"."books"`,
},
{
name: "test-with-tenant-schema-and-table-set-manually",
name: "valid: with dest pointer to struct",
queryFn: func(tx *gorm.DB) *gorm.DB {
return tx.Table("books").Scopes(WithTenantSchema("tenant2")).Find(&Book{})
return tx.Scopes(WithTenantSchema("tenant1")).Find(&Book{})
},
expected: `SELECT * FROM "tenant2"."books"`,
expected: `SELECT * FROM "tenant1"."books"`,
},
{
name: "invalid: dest not a pointer",
queryFn: func(tx *gorm.DB) *gorm.DB {
return tx.Scopes(WithTenantSchema("tenant1")).Find(Book{})
},
expected: ``,
},
{
name: "valid: with dest pointer to array/slice",
queryFn: func(tx *gorm.DB) *gorm.DB {
return tx.Scopes(WithTenantSchema("tenant1")).Find(&[]Book{})
},
expected: `SELECT * FROM "tenant1"."books"`,
},
{
name: "invalid:table-name-not-set",
name: "invalid: Tabler interface not implemented",
queryFn: func(tx *gorm.DB) *gorm.DB {
return tx.Scopes(WithTenantSchema("tenant3")).Find(&struct{}{})
},
Expand Down

0 comments on commit b0682b8

Please sign in to comment.