本文主要研究一下gorm的DeletedAt
gorm.io/gorm@v1.20.10/soft_delete.go
type DeletedAt sql.NullTime // Scan implements the Scanner interface. func (n *DeletedAt) Scan(value interface{}) error { return (*sql.NullTime)(n).Scan(value) } // Value implements the driver Valuer interface. func (n DeletedAt) Value() (driver.Value, error) { if !n.Valid { return nil, nil } return n.Time, nil } func (n DeletedAt) MarshalJSON() ([]byte, error) { if n.Valid { return json.Marshal(n.Time) } return json.Marshal(nil) } func (n *DeletedAt) 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 (DeletedAt) QueryClauses(f *schema.Field) []clause.Interface { return []clause.Interface{SoftDeleteQueryClause{Field: f}} } func (DeletedAt) DeleteClauses(f *schema.Field) []clause.Interface { return []clause.Interface{SoftDeleteDeleteClause{Field: f}} }
DeletedAt为sql.NullTime类型,它实现了Scanner接口的Scan方法,实现了Valuer接口的Value方法;同时定义了MarshalJSON、UnmarshalJSON方法,还定义了QueryClauses方法,使用的是SoftDeleteQueryClause;DeleteClauses方法使用的是SoftDeleteDeleteClause
gorm.io/gorm@v1.20.10/soft_delete.go
type SoftDeleteQueryClause struct { Field *schema.Field } func (sd SoftDeleteQueryClause) Name() string { return "" } func (sd SoftDeleteQueryClause) Build(clause.Builder) { } func (sd SoftDeleteQueryClause) MergeClause(*clause.Clause) { } func (sd SoftDeleteQueryClause) ModifyStatement(stmt *Statement) { if _, ok := stmt.Clauses["soft_delete_enabled"]; !ok { if c, ok := stmt.Clauses["WHERE"]; ok { if where, ok := c.Expression.(clause.Where); ok && len(where.Exprs) > 1 { for _, expr := range where.Exprs { if orCond, ok := expr.(clause.OrConditions); ok && len(orCond.Exprs) == 1 { where.Exprs = []clause.Expression{clause.And(where.Exprs...)} c.Expression = where stmt.Clauses["WHERE"] = c break } } } } stmt.AddClause(clause.Where{Exprs: []clause.Expression{ clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: sd.Field.DBName}, Value: nil}, }}) stmt.Clauses["soft_delete_enabled"] = clause.Clause{} } }
SoftDeleteQueryClause的ModifyStatement方法会追加DeletedAt为nil的查询条件
gorm.io/gorm@v1.20.10/soft_delete.go
type SoftDeleteDeleteClause struct { Field *schema.Field } func (sd SoftDeleteDeleteClause) Name() string { return "" } func (sd SoftDeleteDeleteClause) Build(clause.Builder) { } func (sd SoftDeleteDeleteClause) MergeClause(*clause.Clause) { } func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) { if stmt.SQL.String() == "" { curTime := stmt.DB.NowFunc() stmt.AddClause(clause.Set{{Column: clause.Column{Name: sd.Field.DBName}, Value: curTime}}) stmt.SetColumn(sd.Field.DBName, curTime, true) if stmt.Schema != nil { _, queryValues := schema.GetIdentityFieldValuesMap(stmt.ReflectValue, stmt.Schema.PrimaryFields) column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues) if len(values) > 0 { stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}}) } if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil { _, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields) column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues) if len(values) > 0 { stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}}) } } } if _, ok := stmt.Clauses["WHERE"]; !stmt.DB.AllowGlobalUpdate && !ok { stmt.DB.AddError(ErrMissingWhereClause) } else { SoftDeleteQueryClause{Field: sd.Field}.ModifyStatement(stmt) } stmt.AddClauseIfNotExists(clause.Update{}) stmt.Build("UPDATE", "SET", "WHERE") } }
SoftDeleteDeleteClause的ModifyStatement方法会设置DeletedAt为当前时间
gorm.io/gorm@v1.20.10/schema/interfaces.go
type GormDataTypeInterface interface { GormDataType() string } type CreateClausesInterface interface { CreateClauses(*Field) []clause.Interface } type QueryClausesInterface interface { QueryClauses(*Field) []clause.Interface } type UpdateClausesInterface interface { UpdateClauses(*Field) []clause.Interface } type DeleteClausesInterface interface { DeleteClauses(*Field) []clause.Interface }
interfaces包定义了QueryClausesInterface、DeleteClausesInterface接口;schema的Parse方法会回调这些interface的对应方法
gorm的DeletedAt为sql.NullTime类型,它定义了QueryClauses方法,使用的是SoftDeleteQueryClause,它的ModifyStatement方法会追加DeletedAt为nil的查询条件;DeleteClauses方法使用的是SoftDeleteDeleteClause,它的ModifyStatement方法会设置DeletedAt为当前时间。