mirror of https://github.com/go-gorm/gorm.git
Made it possible to implement driver.Valuer for byte slices
This commit is contained in:
parent
fd15156d39
commit
3b6d790e93
|
@ -33,6 +33,7 @@ type User struct {
|
||||||
CompanyID *int
|
CompanyID *int
|
||||||
Company Company
|
Company Company
|
||||||
Role Role
|
Role Role
|
||||||
|
Password EncryptedData
|
||||||
PasswordHash []byte
|
PasswordHash []byte
|
||||||
IgnoreMe int64 `sql:"-"`
|
IgnoreMe int64 `sql:"-"`
|
||||||
IgnoreStringSlice []string `sql:"-"`
|
IgnoreStringSlice []string `sql:"-"`
|
||||||
|
@ -116,6 +117,31 @@ type Company struct {
|
||||||
Owner *User `sql:"-"`
|
Owner *User `sql:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EncryptedData []byte
|
||||||
|
|
||||||
|
func (data *EncryptedData) Scan(value interface{}) error {
|
||||||
|
if b, ok := value.([]byte); ok {
|
||||||
|
if len(b) < 3 || b[0] != '*' || b[1] != '*' || b[2] != '*'{
|
||||||
|
return errors.New("Too short")
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = b[3:]
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New("Bytes expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data EncryptedData) Value() (driver.Value, error) {
|
||||||
|
if len(data) > 0 && data[0] == 'x' {
|
||||||
|
//needed to test failures
|
||||||
|
return nil, errors.New("Should not start with 'x'")
|
||||||
|
}
|
||||||
|
|
||||||
|
//prepend asterisks
|
||||||
|
return append([]byte("***"), data...), nil
|
||||||
|
}
|
||||||
|
|
||||||
type Role struct {
|
type Role struct {
|
||||||
Name string `gorm:"size:256"`
|
Name string `gorm:"size:256"`
|
||||||
}
|
}
|
||||||
|
|
90
scope.go
90
scope.go
|
@ -557,22 +557,29 @@ func (scope *Scope) buildWhereCondition(clause map[string]interface{}) (str stri
|
||||||
|
|
||||||
args := clause["args"].([]interface{})
|
args := clause["args"].([]interface{})
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch reflect.ValueOf(arg).Kind() {
|
rArg := reflect.ValueOf(arg)
|
||||||
case reflect.Slice: // For where("id in (?)", []int64{1,2})
|
rArgType := reflect.TypeOf(arg)
|
||||||
if bytes, ok := arg.([]byte); ok {
|
vArg, isValuer := arg.(driver.Valuer)
|
||||||
str = strings.Replace(str, "?", scope.AddToVars(bytes), 1)
|
var err error
|
||||||
} else if values := reflect.ValueOf(arg); values.Len() > 0 {
|
|
||||||
var tempMarks []string
|
//non byte slice and non driver.Valuer
|
||||||
for i := 0; i < values.Len(); i++ {
|
if rArgType.Kind() == reflect.Slice && rArgType.Elem().Kind() != reflect.Uint8 && !isValuer {
|
||||||
tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
|
if rArg.Len() > 0 {
|
||||||
|
tempMarks := make([]string, 0, rArg.Len())
|
||||||
|
for i := 0; i < rArg.Len(); i++ {
|
||||||
|
tempMarks = append(tempMarks, scope.AddToVars(rArg.Index(i).Interface()))
|
||||||
}
|
}
|
||||||
|
|
||||||
str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
|
str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
|
||||||
} else {
|
} else {
|
||||||
str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
|
str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
|
||||||
}
|
}
|
||||||
default:
|
} else {
|
||||||
if valuer, ok := interface{}(arg).(driver.Valuer); ok {
|
if isValuer {
|
||||||
arg, _ = valuer.Value()
|
arg, err = vArg.Value()
|
||||||
|
if err != nil {
|
||||||
|
scope.Err(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
|
str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
|
||||||
|
@ -629,23 +636,31 @@ func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string
|
||||||
|
|
||||||
args := clause["args"].([]interface{})
|
args := clause["args"].([]interface{})
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch reflect.ValueOf(arg).Kind() {
|
rArg := reflect.ValueOf(arg)
|
||||||
case reflect.Slice: // For where("id in (?)", []int64{1,2})
|
rArgType := reflect.TypeOf(arg)
|
||||||
if bytes, ok := arg.([]byte); ok {
|
vArg, isValuer := arg.(driver.Valuer)
|
||||||
str = strings.Replace(str, "?", scope.AddToVars(bytes), 1)
|
var err error
|
||||||
} else if values := reflect.ValueOf(arg); values.Len() > 0 {
|
|
||||||
var tempMarks []string
|
//non byte slice and non driver.Valuer
|
||||||
for i := 0; i < values.Len(); i++ {
|
if rArgType.Kind() == reflect.Slice && rArgType.Elem().Kind() != reflect.Uint8 && !isValuer {
|
||||||
tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
|
if rArg.Len() > 0 {
|
||||||
|
tempMarks := make([]string, 0, rArg.Len())
|
||||||
|
for i := 0; i < rArg.Len(); i++ {
|
||||||
|
tempMarks = append(tempMarks, scope.AddToVars(rArg.Index(i).Interface()))
|
||||||
}
|
}
|
||||||
|
|
||||||
str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
|
str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
|
||||||
} else {
|
} else {
|
||||||
str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
|
str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
|
||||||
}
|
}
|
||||||
default:
|
} else {
|
||||||
if scanner, ok := interface{}(arg).(driver.Valuer); ok {
|
if isValuer {
|
||||||
arg, _ = scanner.Value()
|
arg, err = vArg.Value()
|
||||||
|
if err != nil {
|
||||||
|
scope.Err(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
str = strings.Replace(notEqualSQL, "?", scope.AddToVars(arg), 1)
|
str = strings.Replace(notEqualSQL, "?", scope.AddToVars(arg), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -662,18 +677,31 @@ func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string)
|
||||||
|
|
||||||
args := clause["args"].([]interface{})
|
args := clause["args"].([]interface{})
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch reflect.ValueOf(arg).Kind() {
|
rArg := reflect.ValueOf(arg)
|
||||||
case reflect.Slice:
|
rArgType := reflect.TypeOf(arg)
|
||||||
values := reflect.ValueOf(arg)
|
vArg, isValuer := arg.(driver.Valuer)
|
||||||
var tempMarks []string
|
var err error
|
||||||
for i := 0; i < values.Len(); i++ {
|
|
||||||
tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
|
//non byte slice and non driver.Valuer
|
||||||
|
if rArgType.Kind() == reflect.Slice && rArgType.Elem().Kind() != reflect.Uint8 && !isValuer {
|
||||||
|
if rArg.Len() > 0 {
|
||||||
|
tempMarks := make([]string, 0, rArg.Len())
|
||||||
|
for i := 0; i < rArg.Len(); i++ {
|
||||||
|
tempMarks = append(tempMarks, scope.AddToVars(rArg.Index(i).Interface()))
|
||||||
}
|
}
|
||||||
|
|
||||||
str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
|
str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
|
||||||
default:
|
} else {
|
||||||
if valuer, ok := interface{}(arg).(driver.Valuer); ok {
|
str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
|
||||||
arg, _ = valuer.Value()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if isValuer {
|
||||||
|
arg, err = vArg.Value()
|
||||||
|
if err != nil {
|
||||||
|
scope.Err(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
|
str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package gorm_test
|
package gorm_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,3 +44,42 @@ func TestScopes(t *testing.T) {
|
||||||
t.Errorf("Should found two users's name in 1, 3")
|
t.Errorf("Should found two users's name in 1, 3")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func randName() string {
|
||||||
|
data := make([]byte, 8)
|
||||||
|
rand.Read(data)
|
||||||
|
|
||||||
|
return "n-" + hex.EncodeToString(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValuer(t *testing.T) {
|
||||||
|
name := randName()
|
||||||
|
|
||||||
|
origUser := User{Name: name, Age: 1, Password: EncryptedData("pass1"), PasswordHash: []byte("abc")}
|
||||||
|
err := DB.Save(&origUser).Error
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
var user2 User
|
||||||
|
err = DB.Where("name=? AND password=? AND password_hash=?", name, EncryptedData("pass1"), []byte("abc")).First(&user2).Error
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFailedValuer(t *testing.T) {
|
||||||
|
name := randName()
|
||||||
|
|
||||||
|
err := DB.Exec("INSERT INTO users(name, password) VALUES(?, ?)", name, EncryptedData("xpass1")).Error
|
||||||
|
if err == nil {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(err.Error(), "Should not start with") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue