Merge branch 'readdle-fix-valuer'

This commit is contained in:
Jinzhu 2018-02-11 12:48:19 +08:00
commit 4c93473b2d
3 changed files with 82 additions and 5 deletions

View File

@ -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
}
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"`
} }

View File

@ -557,9 +557,13 @@ 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 {
var err error
switch reflect.ValueOf(arg).Kind() { switch reflect.ValueOf(arg).Kind() {
case reflect.Slice: // For where("id in (?)", []int64{1,2}) case reflect.Slice: // For where("id in (?)", []int64{1,2})
if bytes, ok := arg.([]byte); ok { if scanner, ok := interface{}(arg).(driver.Valuer); ok {
arg, err = scanner.Value()
str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
} else if bytes, ok := arg.([]byte); ok {
str = strings.Replace(str, "?", scope.AddToVars(bytes), 1) str = strings.Replace(str, "?", scope.AddToVars(bytes), 1)
} else if values := reflect.ValueOf(arg); values.Len() > 0 { } else if values := reflect.ValueOf(arg); values.Len() > 0 {
var tempMarks []string var tempMarks []string
@ -572,11 +576,14 @@ func (scope *Scope) buildWhereCondition(clause map[string]interface{}) (str stri
} }
default: default:
if valuer, ok := interface{}(arg).(driver.Valuer); ok { if valuer, ok := interface{}(arg).(driver.Valuer); ok {
arg, _ = valuer.Value() arg, err = valuer.Value()
} }
str = strings.Replace(str, "?", scope.AddToVars(arg), 1) str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
} }
if err != nil {
scope.Err(err)
}
} }
return return
} }
@ -629,9 +636,13 @@ 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 {
var err error
switch reflect.ValueOf(arg).Kind() { switch reflect.ValueOf(arg).Kind() {
case reflect.Slice: // For where("id in (?)", []int64{1,2}) case reflect.Slice: // For where("id in (?)", []int64{1,2})
if bytes, ok := arg.([]byte); ok { if scanner, ok := interface{}(arg).(driver.Valuer); ok {
arg, err = scanner.Value()
str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
} else if bytes, ok := arg.([]byte); ok {
str = strings.Replace(str, "?", scope.AddToVars(bytes), 1) str = strings.Replace(str, "?", scope.AddToVars(bytes), 1)
} else if values := reflect.ValueOf(arg); values.Len() > 0 { } else if values := reflect.ValueOf(arg); values.Len() > 0 {
var tempMarks []string var tempMarks []string
@ -644,10 +655,13 @@ func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string
} }
default: default:
if scanner, ok := interface{}(arg).(driver.Valuer); ok { if scanner, ok := interface{}(arg).(driver.Valuer); ok {
arg, _ = scanner.Value() arg, err = scanner.Value()
} }
str = strings.Replace(notEqualSQL, "?", scope.AddToVars(arg), 1) str = strings.Replace(notEqualSQL, "?", scope.AddToVars(arg), 1)
} }
if err != nil {
scope.Err(err)
}
} }
return return
} }

View File

@ -1,8 +1,12 @@
package gorm_test package gorm_test
import ( import (
"github.com/jinzhu/gorm" "encoding/hex"
"math/rand"
"strings"
"testing" "testing"
"github.com/jinzhu/gorm"
) )
func NameIn1And2(d *gorm.DB) *gorm.DB { func NameIn1And2(d *gorm.DB) *gorm.DB {
@ -41,3 +45,36 @@ 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")}
if err := DB.Save(&origUser).Error; err != nil {
t.Errorf("No error should happen when saving user, but got %v", err)
}
var user2 User
if err := DB.Where("name = ? AND password = ? AND password_hash = ?", name, EncryptedData("pass1"), []byte("abc")).First(&user2).Error; err != nil {
t.Errorf("No error should happen when querying user with valuer, but got %v", err)
}
}
func TestFailedValuer(t *testing.T) {
name := randName()
err := DB.Exec("INSERT INTO users(name, password) VALUES(?, ?)", name, EncryptedData("xpass1")).Error
if err == nil {
t.Errorf("There should be an error should happen when insert data")
} else if !strings.HasPrefix(err.Error(), "Should not start with") {
t.Errorf("The error should be returned from Valuer, but get %v", err)
}
}