github.com/erda-project/erda-infra@v1.0.9/providers/mysql/v2/plugins/fields/soft_delete_stamp.go (about) 1 // Copyright (c) 2021 Terminus, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fields 16 17 import ( 18 "database/sql" 19 "database/sql/driver" 20 "encoding/json" 21 "reflect" 22 "strings" 23 24 "gorm.io/gorm" 25 "gorm.io/gorm/clause" 26 "gorm.io/gorm/schema" 27 ) 28 29 // DeletedAtStamp is the field type for soft deleting with BIGINT type. 30 // 0 or null presents not deleted, an UnixMilli timestamp presents deleted. 31 type DeletedAtStamp sql.NullInt64 32 33 // Scan . 34 func (n *DeletedAtStamp) Scan(value interface{}) error { 35 return (*sql.NullInt64)(n).Scan(value) 36 } 37 38 // Value . 39 func (n DeletedAtStamp) Value() (driver.Value, error) { 40 return (sql.NullInt64)(n).Value() 41 } 42 43 // MarshalJSON . 44 func (n DeletedAtStamp) MarshalJSON() ([]byte, error) { 45 if n.Valid { 46 return json.Marshal(n.Int64) 47 } 48 return json.Marshal(nil) 49 } 50 51 // UnmarshalJSON . 52 func (n *DeletedAtStamp) UnmarshalJSON(b []byte) error { 53 bs := string(b) 54 if strings.EqualFold(bs, "null") { 55 n.Valid = false 56 return nil 57 } 58 err := json.Unmarshal(b, &n.Int64) 59 n.Valid = err == nil 60 return err 61 62 } 63 64 // GormDataType . 65 func (DeletedAtStamp) GormDataType() string { 66 return "BIGINT(20)" 67 } 68 69 // QueryClauses . 70 func (DeletedAtStamp) QueryClauses(f *schema.Field) []clause.Interface { 71 return []clause.Interface{DeletedatstampQueryclause{Field: f}} 72 } 73 74 // UpdateClauses . 75 func (DeletedAtStamp) UpdateClauses(f *schema.Field) []clause.Interface { 76 return []clause.Interface{DeletedAtStampUpdateClause{Field: f}} 77 } 78 79 // DeleteClauses . 80 func (DeletedAtStamp) DeleteClauses(f *schema.Field) []clause.Interface { 81 return []clause.Interface{DeletedAtStampDeleteClause{Field: f}} 82 } 83 84 // CreateClauses . 85 func (DeletedAtStamp) CreateClauses(f *schema.Field) []clause.Interface { 86 return []clause.Interface{DeletedAtStampCreateClause{Field: f}} 87 } 88 89 type baseClause struct { 90 softDeletedMode string 91 } 92 93 // Name . 94 func (baseClause) Name() string { 95 return "" 96 } 97 98 // Build . 99 func (baseClause) Build(_ clause.Builder) {} 100 101 // MergeClause . 102 func (baseClause) MergeClause(_ *clause.Clause) {} 103 104 // DeletedatstampQueryclause . 105 type DeletedatstampQueryclause struct { 106 baseClause 107 108 Field *schema.Field 109 } 110 111 // ModifyStatement . 112 func (qc DeletedatstampQueryclause) ModifyStatement(stmt *gorm.Statement) { 113 if _, ok := stmt.Clauses["soft_delete_enabled"]; !ok && !stmt.Statement.Unscoped { 114 if c, ok := stmt.Clauses["WHERE"]; ok { 115 if where, ok := c.Expression.(clause.Where); ok && len(where.Exprs) >= 1 { 116 for _, expr := range where.Exprs { 117 if orCond, ok := expr.(clause.OrConditions); ok && len(orCond.Exprs) == 1 { 118 where.Exprs = []clause.Expression{clause.And(where.Exprs...)} 119 c.Expression = where 120 stmt.Clauses["WHERE"] = c 121 break 122 } 123 } 124 } 125 } 126 127 stmt.AddClause(clause.Where{Exprs: []clause.Expression{ 128 clause.Or( 129 clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: qc.Field.DBName}, Value: 0}, 130 clause.Eq{Column: clause.Column{Table: clause.CurrentTable, Name: qc.Field.DBName}, Value: nil}, 131 ), 132 }}) 133 stmt.Clauses["soft_delete_enabled"] = clause.Clause{} 134 } 135 } 136 137 // DeletedAtStampUpdateClause . 138 type DeletedAtStampUpdateClause struct { 139 baseClause 140 141 Field *schema.Field 142 } 143 144 // ModifyStatement . 145 func (qc DeletedAtStampUpdateClause) ModifyStatement(stmt *gorm.Statement) { 146 if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped { 147 DeletedatstampQueryclause(qc).ModifyStatement(stmt) 148 } 149 } 150 151 // DeletedAtStampDeleteClause . 152 type DeletedAtStampDeleteClause struct { 153 baseClause 154 155 Field *schema.Field 156 } 157 158 // ModifyStatement . 159 func (sd DeletedAtStampDeleteClause) ModifyStatement(stmt *gorm.Statement) { 160 if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped { 161 curTime := stmt.DB.NowFunc().UnixMilli() 162 stmt.AddClause(clause.Set{{Column: clause.Column{Name: sd.Field.DBName}, Value: curTime}}) 163 stmt.SetColumn(sd.Field.DBName, curTime, true) 164 165 if stmt.Schema != nil { 166 _, queryValues := schema.GetIdentityFieldValuesMap(stmt.Context, stmt.ReflectValue, stmt.Schema.PrimaryFields) 167 column, values := schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues) 168 169 if len(values) > 0 { 170 stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}}) 171 } 172 173 if stmt.ReflectValue.CanAddr() && stmt.Dest != stmt.Model && stmt.Model != nil { 174 _, queryValues = schema.GetIdentityFieldValuesMap(stmt.Context, reflect.ValueOf(stmt.Model), stmt.Schema.PrimaryFields) 175 column, values = schema.ToQueryValues(stmt.Table, stmt.Schema.PrimaryFieldDBNames, queryValues) 176 177 if len(values) > 0 { 178 stmt.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}}) 179 } 180 } 181 } 182 183 DeletedatstampQueryclause(sd).ModifyStatement(stmt) 184 stmt.AddClauseIfNotExists(clause.Update{}) 185 stmt.Build(stmt.DB.Callback().Update().Clauses...) 186 } 187 } 188 189 // DeletedAtStampCreateClause . 190 type DeletedAtStampCreateClause struct { 191 baseClause 192 193 Field *schema.Field 194 } 195 196 // ModifyStatement . 197 func (c DeletedAtStampCreateClause) ModifyStatement(stmt *gorm.Statement) { 198 if stmt.SQL.Len() == 0 && !stmt.Statement.Unscoped { 199 stmt.SetColumn(c.Field.Name, sql.NullInt64{Int64: 0, Valid: true}) 200 } 201 }