github.com/wfusion/gofusion@v1.1.14/db/softdelete/timestamp.go (about)

     1  package softdelete
     2  
     3  import (
     4  	"database/sql"
     5  	"database/sql/driver"
     6  	"strconv"
     7  
     8  	"gorm.io/gorm"
     9  	"gorm.io/gorm/clause"
    10  	"gorm.io/gorm/schema"
    11  
    12  	"github.com/wfusion/gofusion/common/utils"
    13  	"github.com/wfusion/gofusion/common/utils/serialize/json"
    14  )
    15  
    16  type Timestamp sql.NullInt64
    17  
    18  // Scan implements the Scanner interface.
    19  func (t *Timestamp) Scan(value any) error {
    20  	return (*sql.NullInt64)(t).Scan(value)
    21  }
    22  
    23  // Value implements the driver Valuer interface.
    24  func (t Timestamp) Value() (driver.Value, error) {
    25  	if !t.Valid {
    26  		return nil, nil
    27  	}
    28  	return t.Int64, nil
    29  }
    30  
    31  func (t Timestamp) MarshalJSON() ([]byte, error) {
    32  	if t.Valid {
    33  		return json.Marshal(t.Int64)
    34  	}
    35  	return json.Marshal(nil)
    36  }
    37  func (t *Timestamp) UnmarshalJSON(bs []byte) error {
    38  	if string(bs) == "null" {
    39  		t.Valid = false
    40  		return nil
    41  	}
    42  	err := json.Unmarshal(bs, &t.Int64)
    43  	if err == nil {
    44  		t.Valid = true
    45  	}
    46  	return err
    47  }
    48  
    49  func (Timestamp) QueryClauses(f *schema.Field) []clause.Interface {
    50  	return []clause.Interface{TimestampQueryClause{Field: f, ZeroValue: parseTimestampZeroValueTag(f)}}
    51  }
    52  
    53  type TimestampQueryClause struct {
    54  	ZeroValue sql.NullInt64
    55  	Field     *schema.Field
    56  }
    57  
    58  func (t TimestampQueryClause) Name() string {
    59  	return ""
    60  }
    61  func (t TimestampQueryClause) Build(clause.Builder) {
    62  }
    63  func (t TimestampQueryClause) MergeClause(*clause.Clause) {
    64  }
    65  func (t TimestampQueryClause) ModifyStatement(stmt *gorm.Statement) {
    66  	if _, ok := stmt.Clauses[timestampEnabledFlag]; ok || stmt.Statement.Unscoped {
    67  		return
    68  	}
    69  	if c, ok := stmt.Clauses["WHERE"]; ok {
    70  		if where, ok := c.Expression.(clause.Where); ok && len(where.Exprs) >= 1 {
    71  			for _, expr := range where.Exprs {
    72  				if orCond, ok := expr.(clause.OrConditions); ok && len(orCond.Exprs) == 1 {
    73  					where.Exprs = []clause.Expression{clause.And(where.Exprs...)}
    74  					c.Expression = where
    75  					stmt.Clauses["WHERE"] = c
    76  					break
    77  				}
    78  			}
    79  		}
    80  	}
    81  
    82  	stmt.AddClause(clause.Where{Exprs: []clause.Expression{
    83  		clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: t.Field.DBName}, Value: t.ZeroValue},
    84  	}})
    85  	stmt.Clauses[timestampEnabledFlag] = clause.Clause{}
    86  }
    87  
    88  func (Timestamp) UpdateClauses(f *schema.Field) []clause.Interface {
    89  	return []clause.Interface{TimestampUpdateClause{Field: f, ZeroValue: parseTimestampZeroValueTag(f)}}
    90  }
    91  
    92  type TimestampUpdateClause struct {
    93  	ZeroValue sql.NullInt64
    94  	Field     *schema.Field
    95  }
    96  
    97  func (t TimestampUpdateClause) Name() string {
    98  	return ""
    99  }
   100  func (t TimestampUpdateClause) Build(clause.Builder) {
   101  }
   102  func (t TimestampUpdateClause) MergeClause(*clause.Clause) {
   103  }
   104  func (t TimestampUpdateClause) ModifyStatement(stmt *gorm.Statement) {
   105  	if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped {
   106  		TimestampQueryClause(t).ModifyStatement(stmt)
   107  	}
   108  }
   109  
   110  func (Timestamp) DeleteClauses(f *schema.Field) []clause.Interface {
   111  	return []clause.Interface{TimestampDeleteClause{Field: f, ZeroValue: parseTimestampZeroValueTag(f)}}
   112  }
   113  
   114  type TimestampDeleteClause struct {
   115  	ZeroValue sql.NullInt64
   116  	Field     *schema.Field
   117  }
   118  
   119  func (t TimestampDeleteClause) Name() string {
   120  	return ""
   121  }
   122  func (t TimestampDeleteClause) Build(clause.Builder) {
   123  }
   124  func (t TimestampDeleteClause) MergeClause(*clause.Clause) {
   125  }
   126  func (t TimestampDeleteClause) ModifyStatement(stmt *gorm.Statement) {
   127  	if stmt.Statement.Unscoped || stmt.SQL.Len() > 0 {
   128  		return
   129  	}
   130  
   131  	curTimestamp := utils.GetTimeStamp(stmt.DB.NowFunc())
   132  	setClauses := clause.Set{{Column: clause.Column{Name: t.Field.DBName}, Value: curTimestamp}}
   133  	if clauses, ok := stmt.Clauses[setClauses.Name()]; ok {
   134  		if exprClauses, ok := clauses.Expression.(clause.Set); ok {
   135  			setClauses = append(setClauses, exprClauses...)
   136  		}
   137  	}
   138  	stmt.AddClause(setClauses)
   139  	stmt.SetColumn(t.Field.DBName, curTimestamp, true)
   140  
   141  	TimestampQueryClause(t).ModifyStatement(stmt)
   142  }
   143  
   144  func parseTimestampZeroValueTag(f *schema.Field) sql.NullInt64 {
   145  	if v, ok := f.TagSettings["ZEROVALUE"]; ok {
   146  		if vv, err := strconv.ParseInt(v, 10, 64); err == nil {
   147  			return sql.NullInt64{Int64: vv, Valid: true}
   148  		}
   149  	}
   150  	return sql.NullInt64{Valid: false}
   151  }