Scopes are not processed when evaluating Join conditions
Playground Pull Request Link
https://github.com/go-gorm/playground/pull/743
Description
When using Joins/InnerJoins, there is an inconsistency about how the join clause is processed.
My application uses a number of preprepared filters, including some generated dynamically. When used as Scopes() for normal queries, they work fine, but when they are used as a clause in a Join() or InnerJoin() they are ignored
db.Find(&User{})SELECT
*
FROM
`users`
WHERE
`users`.`deleted_at` IS NULLdb.Joins("Group").Find(&User{})SELECT
`users`.`id`,
`users`.`created_at`,
`users`.`updated_at`,
`users`.`deleted_at`,
`users`.`name`,
`users`.`group_id`,
`Group`.`id` AS `Group__id`,
`Group`.`created_at` AS `Group__created_at`,
`Group`.`updated_at` AS `Group__updated_at`,
`Group`.`deleted_at` AS `Group__deleted_at`,
`Group`.`name` AS `Group__name`
FROM
`users`
LEFT JOIN `groups` `Group` ON `users`.`group_id` = `Group`.`id`
AND `Group`.`deleted_at` IS NULL
WHERE
`users`.`deleted_at` IS NULLdb.Joins("Group", db.Where(&Group{Model: &gorm.Model{ID: 2}})).Find(&User{})Note the "AND Group.id = 2" - this is as expected.
SELECT
`users`.`id`,
`users`.`created_at`,
`users`.`updated_at`,
`users`.`deleted_at`,
`users`.`name`,
`users`.`group_id`,
`Group`.`id` AS `Group__id`,
`Group`.`created_at` AS `Group__created_at`,
`Group`.`updated_at` AS `Group__updated_at`,
`Group`.`deleted_at` AS `Group__deleted_at`,
`Group`.`name` AS `Group__name`
FROM
`users`
LEFT JOIN `groups` `Group` ON `users`.`group_id` = `Group`.`id`
AND (
`Group`.`deleted_at` IS NULL
AND `Group`.`id` = 2
)
WHERE
`users`.`deleted_at` IS NULLGroupFilter := func(id uint) func(*gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Where(&Group{Model: &gorm.Model{ID: id}})
}
}
db.Joins("Group", db.Scopes(GroupFilter(2))).Find(&User{})In this case the parameter is checked, and isnt a simple "Where" clause, so it is ignored.
SELECT
`users`.`id`,
`users`.`created_at`,
`users`.`updated_at`,
`users`.`deleted_at`,
`users`.`name`,
`users`.`group_id`,
`Group`.`id` AS `Group__id`,
`Group`.`created_at` AS `Group__created_at`,
`Group`.`updated_at` AS `Group__updated_at`,
`Group`.`deleted_at` AS `Group__deleted_at`,
`Group`.`name` AS `Group__name`
FROM
`users`
LEFT JOIN `groups` `Group` ON `users`.`group_id` = `Group`.`id`
AND `Group`.`deleted_at` IS NULL
WHERE
`users`.`deleted_at` IS NULLIf "chainable_api.go" included a call to db.executeScopes() before checking
if where, ok := db.Statement.Clauses["WHERE"].Expression.(clause.Where); ok {
j.On = &where
}This would work.
(Ps, I'm new to gorm playground, and I couldn't get past the gorm.io/gen/examples/dal: cannot find module providing package gorm.io/gen/examples/dal error)
git clone --depth 1 -b master https://github.com/go-gorm/gorm.git
Cloning into 'gorm'...
remote: Enumerating objects: 180, done.
remote: Counting objects: 100% (180/180), done.
remote: Compressing objects: 100% (172/172), done.
remote: Total 180 (delta 13), reused 52 (delta 6), pack-reused 0
Receiving objects: 100% (180/180), 233.63 KiB | 3.49 MiB/s, done.
Resolving deltas: 100% (13/13), done.
gorm.io/playground imports
gorm.io/gen/examples/dal: cannot find module providing package gorm.io/gen/examples/dalpackage main
import (
"log"
"os"
"time"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
type User struct {
*gorm.Model
Name string
GroupID uint
Group Group
}
type Group struct {
*gorm.Model
Name string
}
func main() {
dbDriver := sqlite.Open("test.db")
db, _ := gorm.Open(dbDriver, &gorm.Config{})
err := db.AutoMigrate(
&User{},
&Group{},
)
db = db.Debug()
if err != nil {
panic(err)
}
db.Find(&User{})
db.Joins("Group").Find(&User{})
db.Joins("Group", db.Where(&Group{Model: &gorm.Model{ID: 2}})).Find(&User{})
GroupFilter := func(id uint) func(*gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Where(&Group{Model: &gorm.Model{ID: id}})
}
}
db.Joins("Group", db.Scopes(GroupFilter(2))).Find(&User{})
}Edit: formatting
Source: go-gorm/gorm