Merge branch 'master' into refactor-some-if
This commit is contained in:
commit
fc3075afe8
@ -147,6 +147,21 @@ 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
exprs = append(exprs, clause.Expr{SQL: onSQL, Vars: vars})
|
||||||
|
}
|
||||||
|
|
||||||
joins = append(joins, clause.Join{
|
joins = append(joins, clause.Join{
|
||||||
Type: clause.LeftJoin,
|
Type: clause.LeftJoin,
|
||||||
Table: clause.Table{Name: relation.FieldSchema.Table, Alias: tableAliasName},
|
Table: clause.Table{Name: relation.FieldSchema.Table, Alias: tableAliasName},
|
||||||
|
@ -171,8 +171,19 @@ 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("Account").Find(&user)
|
||||||
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
|
// 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) > 0 {
|
||||||
|
if db, ok := args[0].(*DB); ok {
|
||||||
|
if where, ok := db.Statement.Clauses["WHERE"].Expression.(clause.Where); ok {
|
||||||
|
tx.Statement.Joins = append(tx.Statement.Joins, join{Name: query, Conds: args[1:], On: &where})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tx.Statement.Joins = append(tx.Statement.Joins, join{Name: query, Conds: args})
|
tx.Statement.Joins = append(tx.Statement.Joins, join{Name: query, Conds: args})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -119,20 +119,13 @@ func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error)
|
|||||||
// When the schema initialization is completed, the channel will be closed
|
// When the schema initialization is completed, the channel will be closed
|
||||||
defer close(schema.initialized)
|
defer close(schema.initialized)
|
||||||
|
|
||||||
if v, loaded := cacheStore.LoadOrStore(modelType, schema); loaded {
|
if v, loaded := cacheStore.Load(modelType); loaded {
|
||||||
s := v.(*Schema)
|
s := v.(*Schema)
|
||||||
// Wait for the initialization of other goroutines to complete
|
// Wait for the initialization of other goroutines to complete
|
||||||
<-s.initialized
|
<-s.initialized
|
||||||
return s, s.err
|
return s, s.err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if schema.err != nil {
|
|
||||||
logger.Default.Error(context.Background(), schema.err.Error())
|
|
||||||
cacheStore.Delete(modelType)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for i := 0; i < modelType.NumField(); i++ {
|
for i := 0; i < modelType.NumField(); i++ {
|
||||||
if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) {
|
if fieldStruct := modelType.Field(i); ast.IsExported(fieldStruct.Name) {
|
||||||
if field := schema.ParseField(fieldStruct); field.EmbeddedSchema != nil {
|
if field := schema.ParseField(fieldStruct); field.EmbeddedSchema != nil {
|
||||||
@ -233,6 +226,20 @@ func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if v, loaded := cacheStore.LoadOrStore(modelType, schema); loaded {
|
||||||
|
s := v.(*Schema)
|
||||||
|
// Wait for the initialization of other goroutines to complete
|
||||||
|
<-s.initialized
|
||||||
|
return s, s.err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if schema.err != nil {
|
||||||
|
logger.Default.Error(context.Background(), schema.err.Error())
|
||||||
|
cacheStore.Delete(modelType)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if _, embedded := schema.cacheStore.Load(embeddedCacheKey); !embedded {
|
if _, embedded := schema.cacheStore.Load(embeddedCacheKey); !embedded {
|
||||||
for _, field := range schema.Fields {
|
for _, field := range schema.Fields {
|
||||||
if field.DataType == "" && (field.Creatable || field.Updatable || field.Readable) {
|
if field.DataType == "" && (field.Creatable || field.Updatable || field.Readable) {
|
||||||
|
@ -50,6 +50,7 @@ type Statement struct {
|
|||||||
type join struct {
|
type join struct {
|
||||||
Name string
|
Name string
|
||||||
Conds []interface{}
|
Conds []interface{}
|
||||||
|
On *clause.Where
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatementModifier statement modifier interface
|
// StatementModifier statement modifier interface
|
||||||
|
@ -9,7 +9,7 @@ require (
|
|||||||
gorm.io/driver/mysql v1.1.2
|
gorm.io/driver/mysql v1.1.2
|
||||||
gorm.io/driver/postgres v1.1.0
|
gorm.io/driver/postgres v1.1.0
|
||||||
gorm.io/driver/sqlite v1.1.4
|
gorm.io/driver/sqlite v1.1.4
|
||||||
gorm.io/driver/sqlserver v1.0.8
|
gorm.io/driver/sqlserver v1.0.9
|
||||||
gorm.io/gorm v1.21.14
|
gorm.io/gorm v1.21.14
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -104,6 +104,27 @@ func TestJoinConds(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJoinOn(t *testing.T) {
|
||||||
|
var user = *GetUser("joins-on", Config{Pets: 2})
|
||||||
|
DB.Save(&user)
|
||||||
|
|
||||||
|
var user1 User
|
||||||
|
onQuery := DB.Where(&Pet{Name: "joins-on_pet_1"})
|
||||||
|
|
||||||
|
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-on_pet_1")
|
||||||
|
|
||||||
|
onQuery2 := DB.Where(&Pet{Name: "joins-on_pet_2"})
|
||||||
|
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.Name, "joins-on_pet_2")
|
||||||
|
}
|
||||||
|
|
||||||
func TestJoinsWithSelect(t *testing.T) {
|
func TestJoinsWithSelect(t *testing.T) {
|
||||||
type result struct {
|
type result struct {
|
||||||
ID uint
|
ID uint
|
||||||
|
@ -642,6 +642,40 @@ func TestSave(t *testing.T) {
|
|||||||
if !regexp.MustCompile("WHERE .id. = [^ ]+$").MatchString(stmt.SQL.String()) {
|
if !regexp.MustCompile("WHERE .id. = [^ ]+$").MatchString(stmt.SQL.String()) {
|
||||||
t.Fatalf("invalid updating SQL, got %v", stmt.SQL.String())
|
t.Fatalf("invalid updating SQL, got %v", stmt.SQL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user3 := *GetUser("save3", Config{})
|
||||||
|
DB.Create(&user3)
|
||||||
|
|
||||||
|
if err := DB.First(&User{}, "name = ?", "save3").Error; err != nil {
|
||||||
|
t.Fatalf("failed to find created user")
|
||||||
|
}
|
||||||
|
|
||||||
|
user3.Name = "save3_"
|
||||||
|
if err := DB.Model(User{Model: user3.Model}).Save(&user3).Error; err != nil {
|
||||||
|
t.Fatalf("failed to save user, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result2 User
|
||||||
|
if err := DB.First(&result2, "name = ?", "save3_").Error; err != nil || result2.ID != user3.ID {
|
||||||
|
t.Fatalf("failed to find updated user, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := DB.Model(User{Model: user3.Model}).Save(&struct {
|
||||||
|
gorm.Model
|
||||||
|
Placeholder string
|
||||||
|
Name string
|
||||||
|
}{
|
||||||
|
Model: user3.Model,
|
||||||
|
Placeholder: "placeholder",
|
||||||
|
Name: "save3__",
|
||||||
|
}).Error; err != nil {
|
||||||
|
t.Fatalf("failed to update user, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result3 User
|
||||||
|
if err := DB.First(&result3, "name = ?", "save3__").Error; err != nil || result3.ID != user3.ID {
|
||||||
|
t.Fatalf("failed to find updated user")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSaveWithPrimaryValue(t *testing.T) {
|
func TestSaveWithPrimaryValue(t *testing.T) {
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
// He works in a Company (belongs to), he has a Manager (belongs to - single-table), and also managed a Team (has many - single-table)
|
// He works in a Company (belongs to), he has a Manager (belongs to - single-table), and also managed a Team (has many - single-table)
|
||||||
// He speaks many languages (many to many) and has many friends (many to many - single-table)
|
// He speaks many languages (many to many) and has many friends (many to many - single-table)
|
||||||
// His pet also has one Toy (has one - polymorphic)
|
// His pet also has one Toy (has one - polymorphic)
|
||||||
|
// NamedPet is a reference to a Named `Pets` (has many)
|
||||||
type User struct {
|
type User struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Name string
|
Name string
|
||||||
@ -18,6 +19,7 @@ type User struct {
|
|||||||
Birthday *time.Time
|
Birthday *time.Time
|
||||||
Account Account
|
Account Account
|
||||||
Pets []*Pet
|
Pets []*Pet
|
||||||
|
NamedPet *Pet
|
||||||
Toys []Toy `gorm:"polymorphic:Owner"`
|
Toys []Toy `gorm:"polymorphic:Owner"`
|
||||||
CompanyID *int
|
CompanyID *int
|
||||||
Company Company
|
Company Company
|
||||||
|
Loading…
x
Reference in New Issue
Block a user