package gorm import ( "database/sql" "database/sql/driver" "reflect" "gorm.io/gorm/clause" "gorm.io/gorm/schema" ) 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 (DeletedAt) QueryClauses(f *schema.Field) []clause.Interface { return []clause.Interface{ clause.Where{Exprs: []clause.Expression{ clause.Eq{ Column: clause.Column{Table: clause.CurrentTable, Name: f.DBName}, Value: nil, }, }}, } } 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 { 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{} } } func (DeletedAt) DeleteClauses(f *schema.Field) []clause.Interface { return []clause.Interface{SoftDeleteDeleteClause{Field: f}} } 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() == "" { stmt.AddClause(clause.Set{{Column: clause.Column{Name: sd.Field.DBName}, Value: stmt.DB.NowFunc()}}) 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) return } stmt.AddClauseIfNotExists(clause.Update{}) stmt.Build("UPDATE", "SET", "WHERE") } }