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  }