mirror of https://github.com/go-gorm/gorm.git
Add mores tests for query
This commit is contained in:
parent
76b8e78dcb
commit
dffc2713f0
|
@ -111,21 +111,27 @@ func (db *DB) Omit(columns ...string) (tx *DB) {
|
|||
// Where add conditions
|
||||
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
tx.Statement.AddClause(clause.Where{Exprs: tx.Statement.BuildCondtion(query, args...)})
|
||||
if conds := tx.Statement.BuildCondtion(query, args...); len(conds) > 0 {
|
||||
tx.Statement.AddClause(clause.Where{Exprs: conds})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Not add NOT conditions
|
||||
func (db *DB) Not(query interface{}, args ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
tx.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.Not(tx.Statement.BuildCondtion(query, args...)...)}})
|
||||
if conds := tx.Statement.BuildCondtion(query, args...); len(conds) > 0 {
|
||||
tx.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.Not(conds...)}})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Or add OR conditions
|
||||
func (db *DB) Or(query interface{}, args ...interface{}) (tx *DB) {
|
||||
tx = db.getInstance()
|
||||
tx.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.Or(tx.Statement.BuildCondtion(query, args...)...)}})
|
||||
if conds := tx.Statement.BuildCondtion(query, args...); len(conds) > 0 {
|
||||
tx.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.Or(conds...)}})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
21
statement.go
21
statement.go
|
@ -204,12 +204,15 @@ func (stmt *Statement) AddClauseIfNotExists(v clause.Interface) {
|
|||
// BuildCondtion build condition
|
||||
func (stmt Statement) BuildCondtion(query interface{}, args ...interface{}) (conds []clause.Expression) {
|
||||
if sql, ok := query.(string); ok {
|
||||
if i, err := strconv.Atoi(sql); err == nil {
|
||||
query = i
|
||||
} else if len(args) == 0 || (len(args) > 0 && strings.Contains(sql, "?")) || strings.Contains(sql, "@") {
|
||||
return []clause.Expression{clause.Expr{SQL: sql, Vars: args}}
|
||||
} else if len(args) == 1 {
|
||||
return []clause.Expression{clause.Eq{Column: sql, Value: args[0]}}
|
||||
// if it is a number, then treats it as primary key
|
||||
if _, err := strconv.Atoi(sql); err != nil {
|
||||
if sql == "" && len(args) == 0 {
|
||||
return
|
||||
} else if len(args) == 0 || (len(args) > 0 && strings.Contains(sql, "?")) || strings.Contains(sql, "@") {
|
||||
return []clause.Expression{clause.Expr{SQL: sql, Vars: args}}
|
||||
} else if len(args) == 1 {
|
||||
return []clause.Expression{clause.Eq{Column: sql, Value: args[0]}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,14 +270,12 @@ func (stmt Statement) BuildCondtion(query interface{}, args ...interface{}) (con
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if len(conds) == 0 {
|
||||
conds = append(conds, clause.IN{Column: clause.PrimaryColumn, Values: args})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(conds) == 0 {
|
||||
conds = append(conds, clause.IN{Column: clause.PrimaryColumn, Values: args})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package tests_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
. "github.com/jinzhu/gorm/tests"
|
||||
)
|
||||
|
||||
|
@ -115,8 +117,14 @@ func TestPluck(t *testing.T) {
|
|||
t.Errorf("got error when pluck name: %v", err)
|
||||
}
|
||||
|
||||
var names2 []string
|
||||
if err := DB.Model(User{}).Where("name like ?", "pluck-user%").Order("name desc").Pluck("name", &names2).Error; err != nil {
|
||||
t.Errorf("got error when pluck name: %v", err)
|
||||
}
|
||||
AssertEqual(t, names, sort.Reverse(sort.StringSlice(names2)))
|
||||
|
||||
var ids []int
|
||||
if err := DB.Model(User{}).Where("name like ?", "pluck-user%").Order("name").Pluck("id", &ids).Error; err != nil {
|
||||
if err := DB.Model(User{}).Where("name like ?", "pluck-user%").Pluck("id", &ids).Error; err != nil {
|
||||
t.Errorf("got error when pluck id: %v", err)
|
||||
}
|
||||
|
||||
|
@ -133,6 +141,21 @@ func TestPluck(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSelect(t *testing.T) {
|
||||
user := User{Name: "SelectUser1"}
|
||||
DB.Save(&user)
|
||||
|
||||
var result User
|
||||
DB.Where("name = ?", user.Name).Select("name").Find(&result)
|
||||
if result.ID != 0 {
|
||||
t.Errorf("Should not have ID because only selected name, %+v", result.ID)
|
||||
}
|
||||
|
||||
if user.Name != result.Name {
|
||||
t.Errorf("Should have user Name when selected it")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluckWithSelect(t *testing.T) {
|
||||
users := []User{
|
||||
{Name: "pluck_with_select_1", Age: 25},
|
||||
|
@ -151,3 +174,175 @@ func TestPluckWithSelect(t *testing.T) {
|
|||
|
||||
AssertEqual(t, userAges, []int{26, 27})
|
||||
}
|
||||
|
||||
func TestSelectWithVariables(t *testing.T) {
|
||||
DB.Save(&User{Name: "select_with_variables"})
|
||||
|
||||
rows, _ := DB.Table("users").Where("name = ?", "select_with_variables").Select("? as fake", gorm.Expr("name")).Rows()
|
||||
|
||||
if !rows.Next() {
|
||||
t.Errorf("Should have returned at least one row")
|
||||
} else {
|
||||
columns, _ := rows.Columns()
|
||||
AssertEqual(t, columns, []string{"fake"})
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
func TestSelectWithArrayInput(t *testing.T) {
|
||||
DB.Save(&User{Name: "select_with_array", Age: 42})
|
||||
|
||||
var user User
|
||||
DB.Select([]string{"name", "age"}).Where("age = 42 AND name = ?", "select_with_array").First(&user)
|
||||
|
||||
if user.Name != "select_with_array" || user.Age != 42 {
|
||||
t.Errorf("Should have selected both age and name")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomizedTypePrimaryKey(t *testing.T) {
|
||||
type ID uint
|
||||
type CustomizedTypePrimaryKey struct {
|
||||
ID ID
|
||||
Name string
|
||||
}
|
||||
|
||||
DB.Migrator().DropTable(&CustomizedTypePrimaryKey{})
|
||||
if err := DB.AutoMigrate(&CustomizedTypePrimaryKey{}); err != nil {
|
||||
t.Fatalf("failed to migrate, got error %v", err)
|
||||
}
|
||||
|
||||
p1 := CustomizedTypePrimaryKey{Name: "p1"}
|
||||
p2 := CustomizedTypePrimaryKey{Name: "p2"}
|
||||
p3 := CustomizedTypePrimaryKey{Name: "p3"}
|
||||
DB.Create(&p1)
|
||||
DB.Create(&p2)
|
||||
DB.Create(&p3)
|
||||
|
||||
var p CustomizedTypePrimaryKey
|
||||
|
||||
if err := DB.First(&p, p2.ID).Error; err != nil {
|
||||
t.Errorf("No error should returns, but got %v", err)
|
||||
}
|
||||
|
||||
AssertEqual(t, p, p2)
|
||||
|
||||
if err := DB.First(&p, "id = ?", p2.ID).Error; err != nil {
|
||||
t.Errorf("No error should happen when querying with customized type for primary key, got err %v", err)
|
||||
}
|
||||
|
||||
AssertEqual(t, p, p2)
|
||||
}
|
||||
|
||||
func TestStringPrimaryKeyForNumericValueStartingWithZero(t *testing.T) {
|
||||
type AddressByZipCode struct {
|
||||
ZipCode string `gorm:"primary_key"`
|
||||
Address string
|
||||
}
|
||||
|
||||
DB.Migrator().DropTable(&AddressByZipCode{})
|
||||
if err := DB.AutoMigrate(&AddressByZipCode{}); err != nil {
|
||||
t.Fatalf("failed to migrate, got error %v", err)
|
||||
}
|
||||
|
||||
address := AddressByZipCode{ZipCode: "00501", Address: "Holtsville"}
|
||||
DB.Create(&address)
|
||||
|
||||
var result AddressByZipCode
|
||||
DB.First(&result, "00501")
|
||||
|
||||
AssertEqual(t, result, address)
|
||||
}
|
||||
|
||||
func TestSearchWithEmptyChain(t *testing.T) {
|
||||
user := User{Name: "search_with_empty_chain", Age: 1}
|
||||
DB.Create(&user)
|
||||
|
||||
var result User
|
||||
if DB.Where("").Where("").First(&result).Error != nil {
|
||||
t.Errorf("Should not raise any error if searching with empty strings")
|
||||
}
|
||||
|
||||
if DB.Where(&User{}).Where("name = ?", user.Name).First(&result).Error != nil {
|
||||
t.Errorf("Should not raise any error if searching with empty struct")
|
||||
}
|
||||
|
||||
if DB.Where(map[string]interface{}{}).Where("name = ?", user.Name).First(&result).Error != nil {
|
||||
t.Errorf("Should not raise any error if searching with empty map")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLimit(t *testing.T) {
|
||||
users := []User{
|
||||
{Name: "LimitUser1", Age: 1},
|
||||
{Name: "LimitUser2", Age: 10},
|
||||
{Name: "LimitUser3", Age: 20},
|
||||
{Name: "LimitUser4", Age: 10},
|
||||
{Name: "LimitUser5", Age: 20},
|
||||
}
|
||||
|
||||
DB.Create(&users)
|
||||
|
||||
var users1, users2, users3 []User
|
||||
DB.Order("age desc").Limit(3).Find(&users1).Limit(5).Find(&users2).Limit(-1).Find(&users3)
|
||||
|
||||
if len(users1) != 3 || len(users2) != 5 || len(users3) <= 5 {
|
||||
t.Errorf("Limit should works")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOffset(t *testing.T) {
|
||||
for i := 0; i < 20; i++ {
|
||||
DB.Save(&User{Name: fmt.Sprintf("OffsetUser%v", i)})
|
||||
}
|
||||
var users1, users2, users3, users4 []User
|
||||
|
||||
DB.Limit(100).Where("name like ?", "OffsetUser%").Order("age desc").Find(&users1).Offset(3).Find(&users2).Offset(5).Find(&users3).Offset(-1).Find(&users4)
|
||||
|
||||
if (len(users1) != len(users4)) || (len(users1)-len(users2) != 3) || (len(users1)-len(users3) != 5) {
|
||||
t.Errorf("Offset should work")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchWithMap(t *testing.T) {
|
||||
users := []User{
|
||||
*GetUser("map_search_user1", Config{}),
|
||||
*GetUser("map_search_user2", Config{}),
|
||||
*GetUser("map_search_user3", Config{}),
|
||||
*GetUser("map_search_user4", Config{Company: true}),
|
||||
}
|
||||
|
||||
DB.Create(&users)
|
||||
|
||||
var user User
|
||||
DB.First(&user, map[string]interface{}{"name": users[0].Name})
|
||||
CheckUser(t, user, users[0])
|
||||
|
||||
DB.Where(map[string]interface{}{"name": users[1].Name}).First(&user)
|
||||
CheckUser(t, user, users[1])
|
||||
|
||||
var results []User
|
||||
DB.Where(map[string]interface{}{"name": users[2].Name}).Find(&results)
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("Search all records with inline map")
|
||||
}
|
||||
|
||||
CheckUser(t, results[0], users[2])
|
||||
|
||||
var results2 []User
|
||||
DB.Find(&results2, map[string]interface{}{"name": users[3].Name, "company_id": nil})
|
||||
if len(results2) != 0 {
|
||||
t.Errorf("Search all records with inline map containing null value finding 0 records")
|
||||
}
|
||||
|
||||
DB.Find(&results2, map[string]interface{}{"name": users[0].Name, "company_id": nil})
|
||||
if len(results2) != 1 {
|
||||
t.Errorf("Search all records with inline map containing null value finding 1 record")
|
||||
}
|
||||
|
||||
DB.Find(&results2, map[string]interface{}{"name": users[3].Name, "company_id": users[3].CompanyID})
|
||||
if len(results2) != 1 {
|
||||
t.Errorf("Search all records with inline multiple value map")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,47 @@ func TestScannerValuer(t *testing.T) {
|
|||
AssertObjEqual(t, data, result, "Name", "Gender", "Age", "Male", "Height", "Birthday", "Password", "Num", "Strings", "Structs")
|
||||
}
|
||||
|
||||
func TestScannerValuerWithFirstOrCreate(t *testing.T) {
|
||||
DB.Migrator().DropTable(&ScannerValuerStruct{})
|
||||
if err := DB.Migrator().AutoMigrate(&ScannerValuerStruct{}); err != nil {
|
||||
t.Errorf("no error should happen when migrate scanner, valuer struct")
|
||||
}
|
||||
|
||||
data := ScannerValuerStruct{
|
||||
Name: sql.NullString{String: "name", Valid: true},
|
||||
Gender: &sql.NullString{String: "M", Valid: true},
|
||||
Age: sql.NullInt64{Int64: 18, Valid: true},
|
||||
}
|
||||
|
||||
var result ScannerValuerStruct
|
||||
tx := DB.Where(data).FirstOrCreate(&result)
|
||||
|
||||
if tx.RowsAffected != 1 {
|
||||
t.Errorf("RowsAffected should be 1 after create some record")
|
||||
}
|
||||
|
||||
if tx.Error != nil {
|
||||
t.Errorf("Should not raise any error, but got %v", tx.Error)
|
||||
}
|
||||
|
||||
AssertObjEqual(t, result, data, "Name", "Gender", "Age")
|
||||
|
||||
if err := DB.Where(data).Assign(ScannerValuerStruct{Age: sql.NullInt64{Int64: 18, Valid: true}}).FirstOrCreate(&result).Error; err != nil {
|
||||
t.Errorf("Should not raise any error, but got %v", err)
|
||||
}
|
||||
|
||||
if result.Age.Int64 != 18 {
|
||||
t.Errorf("should update age to 18")
|
||||
}
|
||||
|
||||
var result2 ScannerValuerStruct
|
||||
if err := DB.First(&result2, result.ID).Error; err != nil {
|
||||
t.Errorf("got error %v when query with %v", err, result.ID)
|
||||
}
|
||||
|
||||
AssertObjEqual(t, result2, result, "ID", "CreatedAt", "UpdatedAt", "Name", "Gender", "Age")
|
||||
}
|
||||
|
||||
func TestInvalidValuer(t *testing.T) {
|
||||
DB.Migrator().DropTable(&ScannerValuerStruct{})
|
||||
if err := DB.Migrator().AutoMigrate(&ScannerValuerStruct{}); err != nil {
|
||||
|
|
|
@ -80,3 +80,45 @@ func TestRaw(t *testing.T) {
|
|||
t.Error("Raw sql to update records")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRowsWithGroup(t *testing.T) {
|
||||
users := []User{
|
||||
{Name: "having_user_1", Age: 1},
|
||||
{Name: "having_user_2", Age: 10},
|
||||
{Name: "having_user_1", Age: 20},
|
||||
{Name: "having_user_1", Age: 30},
|
||||
}
|
||||
|
||||
DB.Create(&users)
|
||||
|
||||
rows, err := DB.Select("name, count(*) as total").Table("users").Group("name").Having("name IN ?", []string{users[0].Name, users[1].Name}).Rows()
|
||||
if err != nil {
|
||||
t.Fatalf("got error %v", err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var name string
|
||||
var total int64
|
||||
rows.Scan(&name, &total)
|
||||
|
||||
if name == users[0].Name && total != 3 {
|
||||
t.Errorf("Should have one user having name %v", users[0].Name)
|
||||
} else if name == users[1].Name && total != 1 {
|
||||
t.Errorf("Should have two users having name %v", users[1].Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryRaw(t *testing.T) {
|
||||
users := []*User{
|
||||
GetUser("row_query_user", Config{}),
|
||||
GetUser("row_query_user", Config{}),
|
||||
GetUser("row_query_user", Config{}),
|
||||
}
|
||||
DB.Create(&users)
|
||||
|
||||
var user User
|
||||
DB.Raw("select * from users WHERE id = ?", users[1].ID).First(&user)
|
||||
CheckUser(t, user, *users[1])
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue