github.com/systematiccaos/gorm@v1.22.6/soft_delete.go (about)

     1  package gorm
     2  
     3  import (
     4  	"database/sql"
     5  	"database/sql/driver"
     6  	"encoding/json"
     7  	"reflect"
     8  
     9  	"github.com/systematiccaos/gorm/clause"
    10  	"github.com/systematiccaos/gorm/schema"
    11  )
    12  
    13  type DeletedAt sql.NullTime
    14  
    15  // Scan implements the Scanner interface.
    16  func (n *DeletedAt) Scan(value interface{}) error {
    17  	return (*sql.NullTime)(n).Scan(value)
    18  }
    19  
    20  // Value implements the driver Valuer interface.
    21  func (n DeletedAt) Value() (driver.Value, error) {
    22  	if !n.Valid {
    23  		return nil, nil
    24  	}
    25  	return n.Time, nil
    26  }
    27  
    28  func (n DeletedAt) MarshalJSON() ([]byte, error) {
    29  	if n.Valid {
    30  		return json.Marshal(n.Time)
    31  	}
    32  	return json.Marshal(nil)
    33  }
    34  
    35  func (n *DeletedAt) UnmarshalJSON(b []byte) error {
    36  	if string(b) == "null" {
    37  		n.Valid = false
    38  		return nil
    39  	}
    40  	err := json.Unmarshal(b, &n.Time)
    41  	if err == nil {
    42  		n.Valid = true
    43  	}
    44  	return err
    45  }
    46  
    47  func (DeletedAt) QueryClauses(f *schema.Field) []clause.Interface {
    48  	return []clause.Interface{SoftDeleteQueryClause{Field: f}}
    49  }
    50  
    51  type SoftDeleteQueryClause struct {
    52  	Field *schema.Field
    53  }
    54  
    55  func (sd SoftDeleteQueryClause) Name() string {
    56  	return ""
    57  }
    58  
    59  func (sd SoftDeleteQueryClause) Build(clause.Builder) {
    60  }
    61  
    62  func (sd SoftDeleteQueryClause) MergeClause(*clause.Clause) {
    63  }
    64  
    65  func (sd SoftDeleteQueryClause) ModifyStatement(stmt *Statement) {
    66  	if _, ok := stmt.Clauses["soft_delete_enabled"]; !ok && !stmt.Statement.Unscoped {
    67  		if c, ok := stmt.Clauses["WHERE"]; ok {
    68  			if where, ok := c.Expression.(clause.Where); ok && len(where.Exprs) > 1 {
    69  				for _, expr := range where.Exprs {
    70  					if orCond, ok := expr.(clause.OrConditions); ok && len(orCond.Exprs) == 1 {
    71  						where.Exprs = []clause.Expression{clause.And(where.Exprs...)}
    72  						c.Expression = where
    73  						stmt.Clauses["WHERE"] = c
    74  						break
    75  					}
    76  				}
    77  			}
    78  		}
    79  
    80  		stmt.AddClause(clause.Where{Exprs: []clause.Expression{
    81  			clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: sd.Field.DBName}, Value: nil},
    82  		}})
    83  		stmt.Clauses["soft_delete_enabled"] = clause.Clause{}
    84  	}
    85  }
    86  
    87  func (DeletedAt) UpdateClauses(f *schema.Field) []clause.Interface {
    88  	return []clause.Interface{SoftDeleteUpdateClause{Field: f}}
    89  }
    90  
    91  type SoftDeleteUpdateClause struct {
    92  	Field *schema.Field
    93  }
    94  
    95  func (sd SoftDeleteUpdateClause) Name() string {
    96  	return ""
    97  }
    98  
    99  func (sd SoftDeleteUpdateClause) Build(clause.Builder) {
   100  }
   101  
   102  func (sd SoftDeleteUpdateClause) MergeClause(*clause.Clause) {
   103  }
   104  
   105  func (sd SoftDeleteUpdateClause) ModifyStatement(stmt *Statement) {
   106  	if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped {
   107  		if _, ok := stmt.Clauses["WHERE"]; stmt.DB.AllowGlobalUpdate || ok {
   108  			SoftDeleteQueryClause(sd).ModifyStatement(stmt)
   109  		}
   110  	}
   111  }
   112  
   113  func (DeletedAt) DeleteClauses(f *schema.Field) []clause.Interface {
   114  	return []clause.Interface{SoftDeleteDeleteClause{Field: f}}
   115  }
   116  
   117  type SoftDeleteDeleteClause struct {
   118  	Field *schema.Field
   119  }
   120  
   121  func (sd SoftDeleteDeleteClause) Name() string {
   122  	return ""
   123  }
   124  
   125  func (sd SoftDeleteDeleteClause) Build(clause.Builder) {
   126  }
   127  
   128  func (sd SoftDeleteDeleteClause) MergeClause(*clause.Clause) {
   129  }
   130  
   131  func (sd SoftDeleteDeleteClause) ModifyStatement(stmt *Statement) {
   132  	if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped {
   133  		curTime := stmt.DB.NowFunc()
   134  		stmt.AddClause(clause.Set{{Column: clause.Column{Name: sd.Field.DBName}, Value: curTime}})
   135  		stmt.SetColumn(sd.Field.DBName, curTime, true)
   136  
   137  		if stmt.Schema != nil {
   138  			_, queryValues := schema.GetIdentityFieldValuesMap(stmt.ReflectValue, stmt.Schema.PrimaryFields)
   139  			column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
   140  
   141  			if len(values) > 0 {
   142  				stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
   143  			}
   144  
   145  			if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil {
   146  				_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields)
   147  				column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues)
   148  
   149  				if len(values) > 0 {
   150  					stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
   151  				}
   152  			}
   153  		}
   154  
   155  		if _, ok := stmt.Clauses["WHERE"]; !stmt.DB.AllowGlobalUpdate && !ok {
   156  			stmt.DB.AddError(ErrMissingWhereClause)
   157  		} else {
   158  			SoftDeleteQueryClause(sd).ModifyStatement(stmt)
   159  		}
   160  
   161  		stmt.AddClauseIfNotExists(clause.Update{})
   162  		stmt.Build(stmt.DB.Callback().Update().Clauses...)
   163  	}
   164  }