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