forked from mirror/gorm
Fix Association Count with Soft Delete
This commit is contained in:
parent
801a271d07
commit
43e9035dad
|
@ -293,6 +293,34 @@ func TestHasOne(t *testing.T) {
|
||||||
if DB.Model(&user).Association("CreditCard").Count() != 0 {
|
if DB.Model(&user).Association("CreditCard").Count() != 0 {
|
||||||
t.Errorf("User's credit card count should be 0 after Clear")
|
t.Errorf("User's credit card count should be 0 after Clear")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check Association mode with soft delete
|
||||||
|
var creditcard6 = CreditCard{
|
||||||
|
Number: "411111111116",
|
||||||
|
}
|
||||||
|
DB.Model(&user).Association("CreditCard").Append(&creditcard6)
|
||||||
|
|
||||||
|
if count := DB.Model(&user).Association("CreditCard").Count(); count != 1 {
|
||||||
|
t.Errorf("User's credit card count should be 1 after Append, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.Delete(&creditcard6)
|
||||||
|
|
||||||
|
if count := DB.Model(&user).Association("CreditCard").Count(); count != 0 {
|
||||||
|
t.Errorf("User's credit card count should be 0 after credit card deleted, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DB.Model(&user).Association("CreditCard").Find(&CreditCard{}).Error; err == nil {
|
||||||
|
t.Errorf("User's creditcard is not findable after Delete")
|
||||||
|
}
|
||||||
|
|
||||||
|
if count := DB.Unscoped().Model(&user).Association("CreditCard").Count(); count != 1 {
|
||||||
|
t.Errorf("User's credit card count should be 1 when query with Unscoped, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DB.Unscoped().Model(&user).Association("CreditCard").Find(&CreditCard{}).Error; err != nil {
|
||||||
|
t.Errorf("User's creditcard should be findable when query with Unscoped, got %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHasMany(t *testing.T) {
|
func TestHasMany(t *testing.T) {
|
||||||
|
@ -402,6 +430,36 @@ func TestHasMany(t *testing.T) {
|
||||||
if len(comments51) != 0 {
|
if len(comments51) != 0 {
|
||||||
t.Errorf("Clear has many relations")
|
t.Errorf("Clear has many relations")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check Association mode with soft delete
|
||||||
|
var comment6 = Comment{
|
||||||
|
Content: "comment 6",
|
||||||
|
}
|
||||||
|
DB.Model(&post).Association("Comments").Append(&comment6)
|
||||||
|
|
||||||
|
if count := DB.Model(&post).Association("Comments").Count(); count != 1 {
|
||||||
|
t.Errorf("post's comments count should be 1 after Append, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.Delete(&comment6)
|
||||||
|
|
||||||
|
if count := DB.Model(&post).Association("Comments").Count(); count != 0 {
|
||||||
|
t.Errorf("post's comments count should be 0 after comment been deleted, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
var comments6 []Comment
|
||||||
|
if DB.Model(&post).Association("Comments").Find(&comments6); len(comments6) != 0 {
|
||||||
|
t.Errorf("post's comments count should be 0 when find with Find, but got %v", len(comments6))
|
||||||
|
}
|
||||||
|
|
||||||
|
if count := DB.Unscoped().Model(&post).Association("Comments").Count(); count != 1 {
|
||||||
|
t.Errorf("post's comments count should be 1 when query with Unscoped, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
var comments61 []Comment
|
||||||
|
if DB.Unscoped().Model(&post).Association("Comments").Find(&comments61); len(comments61) != 1 {
|
||||||
|
t.Errorf("post's comments count should be 1 when query with Unscoped, but got %v", len(comments61))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestManyToMany(t *testing.T) {
|
func TestManyToMany(t *testing.T) {
|
||||||
|
@ -500,6 +558,36 @@ func TestManyToMany(t *testing.T) {
|
||||||
if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
|
if len(user.Languages) != 0 || DB.Model(&user).Association("Languages").Count() != 0 {
|
||||||
t.Errorf("Relations should be cleared")
|
t.Errorf("Relations should be cleared")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check Association mode with soft delete
|
||||||
|
var language6 = Language{
|
||||||
|
Name: "language 6",
|
||||||
|
}
|
||||||
|
DB.Model(&user).Association("Languages").Append(&language6)
|
||||||
|
|
||||||
|
if count := DB.Model(&user).Association("Languages").Count(); count != 1 {
|
||||||
|
t.Errorf("user's languages count should be 1 after Append, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.Delete(&language6)
|
||||||
|
|
||||||
|
if count := DB.Model(&user).Association("Languages").Count(); count != 0 {
|
||||||
|
t.Errorf("user's languages count should be 0 after language been deleted, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
var languages6 []Language
|
||||||
|
if DB.Model(&user).Association("Languages").Find(&languages6); len(languages6) != 0 {
|
||||||
|
t.Errorf("user's languages count should be 0 when find with Find, but got %v", len(languages6))
|
||||||
|
}
|
||||||
|
|
||||||
|
if count := DB.Unscoped().Model(&user).Association("Languages").Count(); count != 1 {
|
||||||
|
t.Errorf("user's languages count should be 1 when query with Unscoped, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
var languages61 []Language
|
||||||
|
if DB.Unscoped().Model(&user).Association("Languages").Find(&languages61); len(languages61) != 1 {
|
||||||
|
t.Errorf("user's languages count should be 1 when query with Unscoped, but got %v", len(languages61))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRelated(t *testing.T) {
|
func TestRelated(t *testing.T) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ func BeforeDelete(scope *Scope) {
|
||||||
|
|
||||||
func Delete(scope *Scope) {
|
func Delete(scope *Scope) {
|
||||||
if !scope.HasError() {
|
if !scope.HasError() {
|
||||||
if !scope.Search.Unscoped && scope.HasColumn("DeletedAt") {
|
if !scope.db.unscoped && scope.HasColumn("DeletedAt") {
|
||||||
scope.Raw(
|
scope.Raw(
|
||||||
fmt.Sprintf("UPDATE %v SET deleted_at=%v %v",
|
fmt.Sprintf("UPDATE %v SET deleted_at=%v %v",
|
||||||
scope.QuotedTableName(),
|
scope.QuotedTableName(),
|
||||||
|
|
7
main.go
7
main.go
|
@ -28,6 +28,7 @@ type DB struct {
|
||||||
parent *DB
|
parent *DB
|
||||||
search *search
|
search *search
|
||||||
logMode int
|
logMode int
|
||||||
|
unscoped bool
|
||||||
logger logger
|
logger logger
|
||||||
dialect Dialect
|
dialect Dialect
|
||||||
singularTable bool
|
singularTable bool
|
||||||
|
@ -186,7 +187,9 @@ func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) Unscoped() *DB {
|
func (s *DB) Unscoped() *DB {
|
||||||
return s.clone().search.unscoped().db
|
clone := s.clone()
|
||||||
|
clone.unscoped = true
|
||||||
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) Attrs(attrs ...interface{}) *DB {
|
func (s *DB) Attrs(attrs ...interface{}) *DB {
|
||||||
|
@ -434,7 +437,7 @@ func (s *DB) DropColumn(column string) *DB {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) AddIndex(indexName string, column ...string) *DB {
|
func (s *DB) AddIndex(indexName string, column ...string) *DB {
|
||||||
scope := s.clone().NewScope(s.Value)
|
scope := s.Unscoped().NewScope(s.Value)
|
||||||
scope.addIndex(false, indexName, column...)
|
scope.addIndex(false, indexName, column...)
|
||||||
return scope.db
|
return scope.db
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package gorm
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func (s *DB) clone() *DB {
|
func (s *DB) clone() *DB {
|
||||||
db := DB{db: s.db, parent: s.parent, logger: s.logger, logMode: s.logMode, values: map[string]interface{}{}, Value: s.Value, Error: s.Error}
|
db := DB{db: s.db, parent: s.parent, logger: s.logger, logMode: s.logMode, unscoped: s.unscoped, values: map[string]interface{}{}, Value: s.Value, Error: s.Error}
|
||||||
|
|
||||||
for key, value := range s.values {
|
for key, value := range s.values {
|
||||||
db.values[key] = value
|
db.values[key] = value
|
||||||
|
|
|
@ -161,7 +161,7 @@ func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string)
|
||||||
func (scope *Scope) whereSql() (sql string) {
|
func (scope *Scope) whereSql() (sql string) {
|
||||||
var primaryConditions, andConditions, orConditions []string
|
var primaryConditions, andConditions, orConditions []string
|
||||||
|
|
||||||
if !scope.Search.Unscoped && scope.Fields()["deleted_at"] != nil {
|
if !scope.db.unscoped && scope.Fields()["deleted_at"] != nil {
|
||||||
sql := fmt.Sprintf("(%v.deleted_at IS NULL OR %v.deleted_at <= '0001-01-02')", scope.QuotedTableName(), scope.QuotedTableName())
|
sql := fmt.Sprintf("(%v.deleted_at IS NULL OR %v.deleted_at <= '0001-01-02')", scope.QuotedTableName(), scope.QuotedTableName())
|
||||||
primaryConditions = append(primaryConditions, sql)
|
primaryConditions = append(primaryConditions, sql)
|
||||||
}
|
}
|
||||||
|
@ -601,9 +601,7 @@ func (scope *Scope) addIndex(unique bool, indexName string, column ...string) {
|
||||||
sqlCreate = "CREATE UNIQUE INDEX"
|
sqlCreate = "CREATE UNIQUE INDEX"
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Search.Unscoped = true
|
|
||||||
scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexName, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSql())).Exec()
|
scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexName, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSql())).Exec()
|
||||||
scope.Search.Unscoped = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
|
func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
|
||||||
|
@ -659,11 +657,11 @@ func (scope *Scope) autoIndex() *Scope {
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, columns := range indexes {
|
for name, columns := range indexes {
|
||||||
scope.addIndex(false, name, columns...)
|
scope.NewDB().Model(scope.Value).AddIndex(name, columns...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, columns := range uniqueIndexes {
|
for name, columns := range uniqueIndexes {
|
||||||
scope.addIndex(true, name, columns...)
|
scope.NewDB().Model(scope.Value).AddUniqueIndex(name, columns...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope
|
return scope
|
||||||
|
|
|
@ -20,7 +20,6 @@ type search struct {
|
||||||
group string
|
group string
|
||||||
tableName string
|
tableName string
|
||||||
raw bool
|
raw bool
|
||||||
Unscoped bool
|
|
||||||
countingQuery bool
|
countingQuery bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,11 +123,6 @@ func (s *search) Raw(b bool) *search {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *search) unscoped() *search {
|
|
||||||
s.Unscoped = true
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *search) Table(name string) *search {
|
func (s *search) Table(name string) *search {
|
||||||
s.tableName = name
|
s.tableName = name
|
||||||
return s
|
return s
|
||||||
|
|
|
@ -66,7 +66,7 @@ type Address struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Language struct {
|
type Language struct {
|
||||||
Id int
|
gorm.Model
|
||||||
Name string
|
Name string
|
||||||
Users []User `gorm:"many2many:user_languages;"`
|
Users []User `gorm:"many2many:user_languages;"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue