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 }