feat: support unique
This commit is contained in:
parent
3a8c250180
commit
c6511a0dc6
@ -26,7 +26,7 @@ func (onConflict OnConflict) Build(builder Builder) {
|
|||||||
}
|
}
|
||||||
builder.WriteString(`) `)
|
builder.WriteString(`) `)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(onConflict.TargetWhere.Exprs) > 0 {
|
if len(onConflict.TargetWhere.Exprs) > 0 {
|
||||||
builder.WriteString(" WHERE ")
|
builder.WriteString(" WHERE ")
|
||||||
onConflict.TargetWhere.Build(builder)
|
onConflict.TargetWhere.Build(builder)
|
||||||
|
7
model.go
7
model.go
@ -13,3 +13,10 @@ type Model struct {
|
|||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
DeletedAt DeletedAt `gorm:"index"`
|
DeletedAt DeletedAt `gorm:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ModelSupportUnique struct {
|
||||||
|
ID uint `gorm:"primarykey"`
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
DeletedFlag DeletedFlag `gorm:"type:BIGINT UNSIGNED NOT NULL DEFAULT 0" json:"deleted_flag"`
|
||||||
|
}
|
||||||
|
@ -51,6 +51,26 @@ func (schema *Schema) ParseIndexes() map[string]Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
idx.Fields = append(idx.Fields, index.Fields...)
|
idx.Fields = append(idx.Fields, index.Fields...)
|
||||||
|
|
||||||
|
// create combined index for unique
|
||||||
|
if index.Class == "UNIQUE" {
|
||||||
|
if df := schema.LookUpField("deleted_flag"); df != nil {
|
||||||
|
var exists bool
|
||||||
|
for _, f := range idx.Fields {
|
||||||
|
if f.Field.Name == df.Name {
|
||||||
|
exists = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
idx.Fields = append(idx.Fields, IndexOption{
|
||||||
|
Field: df,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sort.Slice(idx.Fields, func(i, j int) bool {
|
sort.Slice(idx.Fields, func(i, j int) bool {
|
||||||
return idx.Fields[i].priority < idx.Fields[j].priority
|
return idx.Fields[i].priority < idx.Fields[j].priority
|
||||||
})
|
})
|
||||||
|
80
soft_delete_unique.go
Normal file
80
soft_delete_unique.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package gorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeletedFlag uint
|
||||||
|
|
||||||
|
// // Scan implements the Scanner interface.
|
||||||
|
// func (n *DeletedFlag) Scan(value interface{}) error {
|
||||||
|
// return (*sql.NullTime)(n).Scan(value)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Value implements the driver Valuer interface.
|
||||||
|
// func (n DeletedFlag) Value() (driver.Value, error) {
|
||||||
|
// if !n.Valid {
|
||||||
|
// return nil, nil
|
||||||
|
// }
|
||||||
|
// return n.Time, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n DeletedFlag) MarshalJSON() ([]byte, error) {
|
||||||
|
// if n.Valid {
|
||||||
|
// return json.Marshal(n.Time)
|
||||||
|
// }
|
||||||
|
// return json.Marshal(nil)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// func (n *DeletedFlag) UnmarshalJSON(b []byte) error {
|
||||||
|
// if string(b) == "null" {
|
||||||
|
// n.Valid = false
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// err := json.Unmarshal(b, &n.Time)
|
||||||
|
// if err == nil {
|
||||||
|
// n.Valid = true
|
||||||
|
// }
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
func (DeletedFlag) QueryClauses(f *schema.Field) []clause.Interface {
|
||||||
|
return []clause.Interface{SoftDeleteQueryClause{Field: f}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DeletedFlag) DeleteClauses(f *schema.Field) []clause.Interface {
|
||||||
|
return []clause.Interface{SoftDeleteUniqueDeleteClause{Field: f}}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SoftDeleteUniqueDeleteClause struct {
|
||||||
|
Field *schema.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sd SoftDeleteUniqueDeleteClause) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sd SoftDeleteUniqueDeleteClause) Build(clause.Builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sd SoftDeleteUniqueDeleteClause) MergeClause(*clause.Clause) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sd SoftDeleteUniqueDeleteClause) ModifyStatement(stmt *Statement) {
|
||||||
|
re := regexp.MustCompile(`UPDATE (.*) WHERE `)
|
||||||
|
if sql := stmt.SQL.String(); sql != "" {
|
||||||
|
setClause := re.FindStringSubmatch(sql)[1]
|
||||||
|
if setClause == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newSetClause := fmt.Sprintf("%s, %s = `%s`.`id`", setClause, sd.Field.DBName, stmt.Table)
|
||||||
|
stmt.SQL.Reset()
|
||||||
|
stmt.SQL.WriteString(strings.Replace(sql, setClause, newSetClause, 1))
|
||||||
|
}
|
||||||
|
}
|
@ -440,7 +440,7 @@ func TestNot(t *testing.T) {
|
|||||||
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* IS NOT NULL").MatchString(result.Statement.SQL.String()) {
|
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* IS NOT NULL").MatchString(result.Statement.SQL.String()) {
|
||||||
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
|
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
result = dryDB.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&User{})
|
result = dryDB.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&User{})
|
||||||
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* NOT IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) {
|
if !regexp.MustCompile("SELECT \\* FROM .*users.* WHERE .*name.* NOT IN \\(.+,.+\\)").MatchString(result.Statement.SQL.String()) {
|
||||||
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
|
t.Fatalf("Build NOT condition, but got %v", result.Statement.SQL.String())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user