forked from mirror/gorm
fix(Joins): args with select and omit (#5790)
* fix(Joins): args with select and omit * chore: gofumpt style
This commit is contained in:
parent
9d82aa5673
commit
b2f42528a4
|
@ -117,12 +117,20 @@ func BuildQuerySQL(db *gorm.DB) {
|
||||||
} else if relation, ok := db.Statement.Schema.Relationships.Relations[join.Name]; ok {
|
} else if relation, ok := db.Statement.Schema.Relationships.Relations[join.Name]; ok {
|
||||||
tableAliasName := relation.Name
|
tableAliasName := relation.Name
|
||||||
|
|
||||||
|
columnStmt := gorm.Statement{
|
||||||
|
Table: tableAliasName, DB: db, Schema: relation.FieldSchema,
|
||||||
|
Selects: join.Selects, Omits: join.Omits,
|
||||||
|
}
|
||||||
|
|
||||||
|
selectColumns, restricted := columnStmt.SelectAndOmitColumns(false, false)
|
||||||
for _, s := range relation.FieldSchema.DBNames {
|
for _, s := range relation.FieldSchema.DBNames {
|
||||||
clauseSelect.Columns = append(clauseSelect.Columns, clause.Column{
|
if v, ok := selectColumns[s]; (ok && v) || (!ok && !restricted) {
|
||||||
Table: tableAliasName,
|
clauseSelect.Columns = append(clauseSelect.Columns, clause.Column{
|
||||||
Name: s,
|
Table: tableAliasName,
|
||||||
Alias: tableAliasName + "__" + s,
|
Name: s,
|
||||||
})
|
Alias: tableAliasName + "__" + s,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exprs := make([]clause.Expression, len(relation.References))
|
exprs := make([]clause.Expression, len(relation.References))
|
||||||
|
|
|
@ -10,10 +10,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Model specify the model you would like to run db operations
|
// Model specify the model you would like to run db operations
|
||||||
// // update all users's name to `hello`
|
//
|
||||||
// db.Model(&User{}).Update("name", "hello")
|
// // update all users's name to `hello`
|
||||||
// // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello`
|
// db.Model(&User{}).Update("name", "hello")
|
||||||
// db.Model(&user).Update("name", "hello")
|
// // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello`
|
||||||
|
// db.Model(&user).Update("name", "hello")
|
||||||
func (db *DB) Model(value interface{}) (tx *DB) {
|
func (db *DB) Model(value interface{}) (tx *DB) {
|
||||||
tx = db.getInstance()
|
tx = db.getInstance()
|
||||||
tx.Statement.Model = value
|
tx.Statement.Model = value
|
||||||
|
@ -179,18 +180,21 @@ func (db *DB) Or(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Joins specify Joins conditions
|
// Joins specify Joins conditions
|
||||||
// db.Joins("Account").Find(&user)
|
//
|
||||||
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
// db.Joins("Account").Find(&user)
|
||||||
// db.Joins("Account", DB.Select("id").Where("user_id = users.id AND name = ?", "someName").Model(&Account{}))
|
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
||||||
|
// db.Joins("Account", DB.Select("id").Where("user_id = users.id AND name = ?", "someName").Model(&Account{}))
|
||||||
func (db *DB) Joins(query string, args ...interface{}) (tx *DB) {
|
func (db *DB) Joins(query string, args ...interface{}) (tx *DB) {
|
||||||
tx = db.getInstance()
|
tx = db.getInstance()
|
||||||
|
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
if db, ok := args[0].(*DB); ok {
|
if db, ok := args[0].(*DB); ok {
|
||||||
|
j := join{Name: query, Conds: args, Selects: db.Statement.Selects, Omits: db.Statement.Omits}
|
||||||
if where, ok := db.Statement.Clauses["WHERE"].Expression.(clause.Where); ok {
|
if where, ok := db.Statement.Clauses["WHERE"].Expression.(clause.Where); ok {
|
||||||
tx.Statement.Joins = append(tx.Statement.Joins, join{Name: query, Conds: args, On: &where})
|
j.On = &where
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
tx.Statement.Joins = append(tx.Statement.Joins, j)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,8 +223,9 @@ func (db *DB) Having(query interface{}, args ...interface{}) (tx *DB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order specify order when retrieve records from database
|
// Order specify order when retrieve records from database
|
||||||
// db.Order("name DESC")
|
//
|
||||||
// db.Order(clause.OrderByColumn{Column: clause.Column{Name: "name"}, Desc: true})
|
// db.Order("name DESC")
|
||||||
|
// db.Order(clause.OrderByColumn{Column: clause.Column{Name: "name"}, Desc: true})
|
||||||
func (db *DB) Order(value interface{}) (tx *DB) {
|
func (db *DB) Order(value interface{}) (tx *DB) {
|
||||||
tx = db.getInstance()
|
tx = db.getInstance()
|
||||||
|
|
||||||
|
@ -256,17 +261,18 @@ func (db *DB) Offset(offset int) (tx *DB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scopes pass current database connection to arguments `func(DB) DB`, which could be used to add conditions dynamically
|
// Scopes pass current database connection to arguments `func(DB) DB`, which could be used to add conditions dynamically
|
||||||
// func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
|
|
||||||
// return db.Where("amount > ?", 1000)
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
|
// func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
|
||||||
// return func (db *gorm.DB) *gorm.DB {
|
// return db.Where("amount > ?", 1000)
|
||||||
// return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
|
// }
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
|
// func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
|
||||||
|
// return func (db *gorm.DB) *gorm.DB {
|
||||||
|
// return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
|
||||||
func (db *DB) Scopes(funcs ...func(*DB) *DB) (tx *DB) {
|
func (db *DB) Scopes(funcs ...func(*DB) *DB) (tx *DB) {
|
||||||
tx = db.getInstance()
|
tx = db.getInstance()
|
||||||
tx.Statement.scopes = append(tx.Statement.scopes, funcs...)
|
tx.Statement.scopes = append(tx.Statement.scopes, funcs...)
|
||||||
|
@ -274,7 +280,8 @@ func (db *DB) Scopes(funcs ...func(*DB) *DB) (tx *DB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preload preload associations with given conditions
|
// Preload preload associations with given conditions
|
||||||
// db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
|
//
|
||||||
|
// db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
|
||||||
func (db *DB) Preload(query string, args ...interface{}) (tx *DB) {
|
func (db *DB) Preload(query string, args ...interface{}) (tx *DB) {
|
||||||
tx = db.getInstance()
|
tx = db.getInstance()
|
||||||
if tx.Statement.Preloads == nil {
|
if tx.Statement.Preloads == nil {
|
||||||
|
|
13
statement.go
13
statement.go
|
@ -49,9 +49,11 @@ type Statement struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type join struct {
|
type join struct {
|
||||||
Name string
|
Name string
|
||||||
Conds []interface{}
|
Conds []interface{}
|
||||||
On *clause.Where
|
On *clause.Where
|
||||||
|
Selects []string
|
||||||
|
Omits []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatementModifier statement modifier interface
|
// StatementModifier statement modifier interface
|
||||||
|
@ -544,8 +546,9 @@ func (stmt *Statement) clone() *Statement {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColumn set column's value
|
// SetColumn set column's value
|
||||||
// stmt.SetColumn("Name", "jinzhu") // Hooks Method
|
//
|
||||||
// stmt.SetColumn("Name", "jinzhu", true) // Callbacks Method
|
// stmt.SetColumn("Name", "jinzhu") // Hooks Method
|
||||||
|
// stmt.SetColumn("Name", "jinzhu", true) // Callbacks Method
|
||||||
func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks ...bool) {
|
func (stmt *Statement) SetColumn(name string, value interface{}, fromCallbacks ...bool) {
|
||||||
if v, ok := stmt.Dest.(map[string]interface{}); ok {
|
if v, ok := stmt.Dest.(map[string]interface{}); ok {
|
||||||
v[name] = value
|
v[name] = value
|
||||||
|
|
|
@ -260,3 +260,46 @@ func TestJoinWithSameColumnName(t *testing.T) {
|
||||||
t.Fatalf("wrong pet name")
|
t.Fatalf("wrong pet name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJoinArgsWithDB(t *testing.T) {
|
||||||
|
user := *GetUser("joins-args-db", Config{Pets: 2})
|
||||||
|
DB.Save(&user)
|
||||||
|
|
||||||
|
// test where
|
||||||
|
var user1 User
|
||||||
|
onQuery := DB.Where(&Pet{Name: "joins-args-db_pet_2"})
|
||||||
|
if err := DB.Joins("NamedPet", onQuery).Where("users.name = ?", user.Name).First(&user1).Error; err != nil {
|
||||||
|
t.Fatalf("Failed to load with joins on, got error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
AssertEqual(t, user1.NamedPet.Name, "joins-args-db_pet_2")
|
||||||
|
|
||||||
|
// test where and omit
|
||||||
|
onQuery2 := DB.Where(&Pet{Name: "joins-args-db_pet_2"}).Omit("Name")
|
||||||
|
var user2 User
|
||||||
|
if err := DB.Joins("NamedPet", onQuery2).Where("users.name = ?", user.Name).First(&user2).Error; err != nil {
|
||||||
|
t.Fatalf("Failed to load with joins on, got error: %v", err)
|
||||||
|
}
|
||||||
|
AssertEqual(t, user2.NamedPet.ID, user1.NamedPet.ID)
|
||||||
|
AssertEqual(t, user2.NamedPet.Name, "")
|
||||||
|
|
||||||
|
// test where and select
|
||||||
|
onQuery3 := DB.Where(&Pet{Name: "joins-args-db_pet_2"}).Select("Name")
|
||||||
|
var user3 User
|
||||||
|
if err := DB.Joins("NamedPet", onQuery3).Where("users.name = ?", user.Name).First(&user3).Error; err != nil {
|
||||||
|
t.Fatalf("Failed to load with joins on, got error: %v", err)
|
||||||
|
}
|
||||||
|
AssertEqual(t, user3.NamedPet.ID, 0)
|
||||||
|
AssertEqual(t, user3.NamedPet.Name, "joins-args-db_pet_2")
|
||||||
|
|
||||||
|
// test select
|
||||||
|
onQuery4 := DB.Select("ID")
|
||||||
|
var user4 User
|
||||||
|
if err := DB.Joins("NamedPet", onQuery4).Where("users.name = ?", user.Name).First(&user4).Error; err != nil {
|
||||||
|
t.Fatalf("Failed to load with joins on, got error: %v", err)
|
||||||
|
}
|
||||||
|
if user4.NamedPet.ID == 0 {
|
||||||
|
t.Fatal("Pet ID can not be empty")
|
||||||
|
}
|
||||||
|
AssertEqual(t, user4.NamedPet.Name, "")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue