diff --git a/callbacks/query.go b/callbacks/query.go index 04f35c7e..c4c80406 100644 --- a/callbacks/query.go +++ b/callbacks/query.go @@ -145,19 +145,33 @@ func BuildQuerySQL(db *gorm.DB) { } } - if join.On != nil { - onStmt := gorm.Statement{Table: tableAliasName, DB: db} - join.On.Build(&onStmt) - onSQL := onStmt.SQL.String() - vars := onStmt.Vars - for idx, v := range onStmt.Vars { - bindvar := strings.Builder{} - onStmt.Vars = vars[0 : idx+1] - db.Dialector.BindVarTo(&bindvar, &onStmt, v) - onSQL = strings.Replace(onSQL, bindvar.String(), "?", 1) + { + onStmt := gorm.Statement{Table: tableAliasName, DB: db, Clauses: map[string]clause.Clause{}} + for _, c := range relation.FieldSchema.QueryClauses { + onStmt.AddClause(c) } - exprs = append(exprs, clause.Expr{SQL: onSQL, Vars: vars}) + if join.On != nil { + onStmt.AddClause(join.On) + } + + if cs, ok := onStmt.Clauses["WHERE"]; ok { + if where, ok := cs.Expression.(clause.Where); ok { + where.Build(&onStmt) + + if onSQL := onStmt.SQL.String(); onSQL != "" { + vars := onStmt.Vars + for idx, v := range vars { + bindvar := strings.Builder{} + onStmt.Vars = vars[0 : idx+1] + db.Dialector.BindVarTo(&bindvar, &onStmt, v) + onSQL = strings.Replace(onSQL, bindvar.String(), "?", 1) + } + + exprs = append(exprs, clause.Expr{SQL: onSQL, Vars: vars}) + } + } + } } joins = append(joins, clause.Join{ @@ -172,8 +186,8 @@ func BuildQuerySQL(db *gorm.DB) { } } - db.Statement.Joins = nil db.Statement.AddClause(clause.From{Joins: joins}) + db.Statement.Joins = nil } else { db.Statement.AddClauseIfNotExists(clause.From{}) } diff --git a/tests/helper_test.go b/tests/helper_test.go index eee34e99..7ee2a576 100644 --- a/tests/helper_test.go +++ b/tests/helper_test.go @@ -19,6 +19,7 @@ type Config struct { Team int Languages int Friends int + NamedPet bool } func GetUser(name string, config Config) *User { @@ -65,6 +66,10 @@ func GetUser(name string, config Config) *User { user.Friends = append(user.Friends, GetUser(name+"_friend_"+strconv.Itoa(i+1), Config{})) } + if config.NamedPet { + user.NamedPet = &Pet{Name: name + "_namepet"} + } + return &user } diff --git a/tests/joins_test.go b/tests/joins_test.go index 4c9cffae..0f02f3f9 100644 --- a/tests/joins_test.go +++ b/tests/joins_test.go @@ -200,3 +200,34 @@ func TestJoinCount(t *testing.T) { t.Fatalf("result's id, %d, doesn't match user's id, %d", result.ID, user.ID) } } + +func TestJoinWithSoftDeleted(t *testing.T) { + DB = DB.Debug() + + user := GetUser("TestJoinWithSoftDeletedUser", Config{Account: true, NamedPet: true}) + DB.Create(&user) + + var user1 User + DB.Model(&User{}).Joins("NamedPet").Joins("Account").First(&user1, user.ID) + if user1.NamedPet == nil || user1.Account.ID == 0 { + t.Fatalf("joins NamedPet and Account should not empty:%v", user1) + } + + // Account should empty + DB.Delete(&user1.Account) + + var user2 User + DB.Model(&User{}).Joins("NamedPet").Joins("Account").First(&user2, user.ID) + if user2.NamedPet == nil || user2.Account.ID != 0 { + t.Fatalf("joins Account should not empty:%v", user2) + } + + // NamedPet should empty + DB.Delete(&user1.NamedPet) + + var user3 User + DB.Model(&User{}).Joins("NamedPet").Joins("Account").First(&user3, user.ID) + if user3.NamedPet != nil || user2.Account.ID != 0 { + t.Fatalf("joins NamedPet and Account should not empty:%v", user2) + } +}