mirror of https://github.com/go-gorm/gorm.git
Merge branch 'master' into v1.0_dev
This commit is contained in:
commit
f0364a0fb5
|
@ -595,7 +595,7 @@ db.Model(&user).Related(&profile)
|
||||||
### Has Many
|
### Has Many
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// User belongs to a profile, ProfileID is the foreign key
|
// User has many emails, UserID is the foreign key
|
||||||
type User struct {
|
type User struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Emails []Email
|
Emails []Email
|
||||||
|
|
|
@ -297,13 +297,16 @@ func (association *Association) Clear() *Association {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (association *Association) Count() int {
|
func (association *Association) Count() int {
|
||||||
count := -1
|
var (
|
||||||
relationship := association.Field.Relationship
|
count = 0
|
||||||
scope := association.Scope
|
relationship = association.Field.Relationship
|
||||||
newScope := scope.New(association.Field.Field.Interface())
|
scope = association.Scope
|
||||||
|
fieldValue = association.Field.Field.Interface()
|
||||||
|
newScope = scope.New(fieldValue)
|
||||||
|
)
|
||||||
|
|
||||||
if relationship.Kind == "many_to_many" {
|
if relationship.Kind == "many_to_many" {
|
||||||
relationship.JoinTableHandler.JoinWith(relationship.JoinTableHandler, scope.NewDB(), association.Scope.Value).Table(newScope.TableName()).Count(&count)
|
relationship.JoinTableHandler.JoinWith(relationship.JoinTableHandler, scope.DB(), association.Scope.Value).Model(fieldValue).Count(&count)
|
||||||
} else if relationship.Kind == "has_many" || relationship.Kind == "has_one" {
|
} else if relationship.Kind == "has_many" || relationship.Kind == "has_one" {
|
||||||
query := scope.DB()
|
query := scope.DB()
|
||||||
for idx, foreignKey := range relationship.ForeignDBNames {
|
for idx, foreignKey := range relationship.ForeignDBNames {
|
||||||
|
@ -316,16 +319,16 @@ func (association *Association) Count() int {
|
||||||
if relationship.PolymorphicType != "" {
|
if relationship.PolymorphicType != "" {
|
||||||
query = query.Where(fmt.Sprintf("%v.%v = ?", newScope.QuotedTableName(), newScope.Quote(relationship.PolymorphicDBName)), scope.TableName())
|
query = query.Where(fmt.Sprintf("%v.%v = ?", newScope.QuotedTableName(), newScope.Quote(relationship.PolymorphicDBName)), scope.TableName())
|
||||||
}
|
}
|
||||||
query.Table(newScope.TableName()).Count(&count)
|
query.Model(fieldValue).Count(&count)
|
||||||
} else if relationship.Kind == "belongs_to" {
|
} else if relationship.Kind == "belongs_to" {
|
||||||
query := scope.DB()
|
query := scope.DB()
|
||||||
for idx, foreignKey := range relationship.ForeignDBNames {
|
for idx, primaryKey := range relationship.AssociationForeignDBNames {
|
||||||
if field, ok := scope.FieldByName(relationship.AssociationForeignDBNames[idx]); ok {
|
if field, ok := scope.FieldByName(relationship.ForeignDBNames[idx]); ok {
|
||||||
query = query.Where(fmt.Sprintf("%v.%v = ?", newScope.QuotedTableName(), scope.Quote(foreignKey)),
|
query = query.Where(fmt.Sprintf("%v.%v = ?", newScope.QuotedTableName(), scope.Quote(primaryKey)),
|
||||||
field.Field.Interface())
|
field.Field.Interface())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
query.Table(newScope.TableName()).Count(&count)
|
query.Model(fieldValue).Count(&count)
|
||||||
}
|
}
|
||||||
|
|
||||||
return count
|
return count
|
||||||
|
|
|
@ -19,7 +19,7 @@ func TestBelongsTo(t *testing.T) {
|
||||||
t.Errorf("Got errors when save post", err.Error())
|
t.Errorf("Got errors when save post", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if post.Category.Id == 0 || post.MainCategory.Id == 0 {
|
if post.Category.ID == 0 || post.MainCategory.ID == 0 {
|
||||||
t.Errorf("Category's primary key should be updated")
|
t.Errorf("Category's primary key should be updated")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +46,11 @@ func TestBelongsTo(t *testing.T) {
|
||||||
t.Errorf("Query belongs to relations with Related")
|
t.Errorf("Query belongs to relations with Related")
|
||||||
}
|
}
|
||||||
|
|
||||||
if DB.Model(&post).Association("Category").Count() == 1 {
|
if DB.Model(&post).Association("Category").Count() != 1 {
|
||||||
t.Errorf("Post's category count should be 1")
|
t.Errorf("Post's category count should be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
if DB.Model(&post).Association("MainCategory").Count() == 1 {
|
if DB.Model(&post).Association("MainCategory").Count() != 1 {
|
||||||
t.Errorf("Post's main category count should be 1")
|
t.Errorf("Post's main category count should be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func TestBelongsTo(t *testing.T) {
|
||||||
}
|
}
|
||||||
DB.Model(&post).Association("Category").Append(&category2)
|
DB.Model(&post).Association("Category").Append(&category2)
|
||||||
|
|
||||||
if category2.Id == 0 {
|
if category2.ID == 0 {
|
||||||
t.Errorf("Category should has ID when created with Append")
|
t.Errorf("Category should has ID when created with Append")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func TestBelongsTo(t *testing.T) {
|
||||||
t.Errorf("Category should be updated with Append")
|
t.Errorf("Category should be updated with Append")
|
||||||
}
|
}
|
||||||
|
|
||||||
if DB.Model(&post).Association("Category").Count() == 1 {
|
if DB.Model(&post).Association("Category").Count() != 1 {
|
||||||
t.Errorf("Post's category count should be 1")
|
t.Errorf("Post's category count should be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ func TestBelongsTo(t *testing.T) {
|
||||||
}
|
}
|
||||||
DB.Model(&post).Association("Category").Replace(&category3)
|
DB.Model(&post).Association("Category").Replace(&category3)
|
||||||
|
|
||||||
if category3.Id == 0 {
|
if category3.ID == 0 {
|
||||||
t.Errorf("Category should has ID when created with Replace")
|
t.Errorf("Category should has ID when created with Replace")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ func TestBelongsTo(t *testing.T) {
|
||||||
t.Errorf("Category should be updated with Replace")
|
t.Errorf("Category should be updated with Replace")
|
||||||
}
|
}
|
||||||
|
|
||||||
if DB.Model(&post).Association("Category").Count() == 1 {
|
if DB.Model(&post).Association("Category").Count() != 1 {
|
||||||
t.Errorf("Post's category count should be 1")
|
t.Errorf("Post's category count should be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +117,8 @@ func TestBelongsTo(t *testing.T) {
|
||||||
t.Errorf("Category should be deleted with Delete")
|
t.Errorf("Category should be deleted with Delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
if DB.Model(&post).Association("Category").Count() == 0 {
|
if count := DB.Model(&post).Association("Category").Count(); count != 0 {
|
||||||
t.Errorf("Post's category count should be 0 after Delete")
|
t.Errorf("Post's category count should be 0 after Delete, but got %v", count)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear
|
// Clear
|
||||||
|
@ -144,8 +144,36 @@ func TestBelongsTo(t *testing.T) {
|
||||||
t.Errorf("Should not find any category after Clear")
|
t.Errorf("Should not find any category after Clear")
|
||||||
}
|
}
|
||||||
|
|
||||||
if DB.Model(&post).Association("Category").Count() == 0 {
|
if count := DB.Model(&post).Association("Category").Count(); count != 0 {
|
||||||
t.Errorf("Post's category count should be 0 after Clear")
|
t.Errorf("Post's category count should be 0 after Clear, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Association mode with soft delete
|
||||||
|
category6 := Category{
|
||||||
|
Name: "Category 6",
|
||||||
|
}
|
||||||
|
DB.Model(&post).Association("Category").Append(&category6)
|
||||||
|
|
||||||
|
if count := DB.Model(&post).Association("Category").Count(); count != 1 {
|
||||||
|
t.Errorf("Post's category count should be 1 after Append, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
DB.Delete(&category6)
|
||||||
|
|
||||||
|
if count := DB.Model(&post).Association("Category").Count(); count != 0 {
|
||||||
|
t.Errorf("Post's category count should be 0 after the category has been deleted, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DB.Model(&post).Association("Category").Find(&Category{}).Error; err == nil {
|
||||||
|
t.Errorf("Post's category is not findable after Delete")
|
||||||
|
}
|
||||||
|
|
||||||
|
if count := DB.Unscoped().Model(&post).Association("Category").Count(); count != 1 {
|
||||||
|
t.Errorf("Post's category count should be 1 when query with Unscoped, but got %v", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DB.Unscoped().Model(&post).Association("Category").Find(&Category{}).Error; err != nil {
|
||||||
|
t.Errorf("Post's category should be findable when query with Unscoped, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,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) {
|
||||||
|
@ -374,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) {
|
||||||
|
@ -472,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) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ func (*PersonAddress) Delete(handler gorm.JoinTableHandlerInterface, db *gorm.DB
|
||||||
|
|
||||||
func (pa *PersonAddress) JoinWith(handler gorm.JoinTableHandlerInterface, db *gorm.DB, source interface{}) *gorm.DB {
|
func (pa *PersonAddress) JoinWith(handler gorm.JoinTableHandlerInterface, db *gorm.DB, source interface{}) *gorm.DB {
|
||||||
table := pa.Table(db)
|
table := pa.Table(db)
|
||||||
return db.Table(table).Joins("INNER JOIN person_addresses ON person_addresses.address_id = addresses.id").Where(fmt.Sprintf("%v.deleted_at IS NULL OR %v.deleted_at <= '0001-01-02'", table, table))
|
return db.Joins("INNER JOIN person_addresses ON person_addresses.address_id = addresses.id").Where(fmt.Sprintf("%v.deleted_at IS NULL OR %v.deleted_at <= '0001-01-02'", table, table))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJoinTable(t *testing.T) {
|
func TestJoinTable(t *testing.T) {
|
||||||
|
|
2
main.go
2
main.go
|
@ -434,7 +434,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
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,9 @@ func init() {
|
||||||
|
|
||||||
// DB.SetLogger(Logger{log.New(os.Stdout, "\r\n", 0)})
|
// DB.SetLogger(Logger{log.New(os.Stdout, "\r\n", 0)})
|
||||||
// DB.SetLogger(log.New(os.Stdout, "\r\n", 0))
|
// DB.SetLogger(log.New(os.Stdout, "\r\n", 0))
|
||||||
// DB.LogMode(true)
|
if os.Getenv("DEBUG") == "true" {
|
||||||
DB.LogMode(false)
|
DB.LogMode(true)
|
||||||
|
}
|
||||||
|
|
||||||
DB.DB().SetMaxIdleConns(10)
|
DB.DB().SetMaxIdleConns(10)
|
||||||
|
|
||||||
|
|
|
@ -604,9 +604,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) {
|
||||||
|
@ -662,11 +660,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
|
||||||
|
|
|
@ -6,6 +6,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -64,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;"`
|
||||||
}
|
}
|
||||||
|
@ -154,12 +156,12 @@ type Post struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Category struct {
|
type Category struct {
|
||||||
Id int64
|
gorm.Model
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Comment struct {
|
type Comment struct {
|
||||||
Id int64
|
gorm.Model
|
||||||
PostId int64
|
PostId int64
|
||||||
Content string
|
Content string
|
||||||
Post Post
|
Post Post
|
||||||
|
|
Loading…
Reference in New Issue