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

     1  package callbacks
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  
     7  	"github.com/systematiccaos/gorm"
     8  	"github.com/systematiccaos/gorm/clause"
     9  	"github.com/systematiccaos/gorm/schema"
    10  	"github.com/systematiccaos/gorm/utils"
    11  )
    12  
    13  func BeforeDelete(db *gorm.DB) {
    14  	if db.Error == nil && db.Statement.Schema != nil && !db.Statement.SkipHooks && db.Statement.Schema.BeforeDelete {
    15  		callMethod(db, func(value interface{}, tx *gorm.DB) bool {
    16  			if i, ok := value.(BeforeDeleteInterface); ok {
    17  				db.AddError(i.BeforeDelete(tx))
    18  				return true
    19  			}
    20  
    21  			return false
    22  		})
    23  	}
    24  }
    25  
    26  func DeleteBeforeAssociations(db *gorm.DB) {
    27  	if db.Error == nil && db.Statement.Schema != nil {
    28  		selectColumns, restricted := db.Statement.SelectAndOmitColumns(true, false)
    29  		if !restricted {
    30  			return
    31  		}
    32  
    33  		for column, v := range selectColumns {
    34  			if !v {
    35  				continue
    36  			}
    37  
    38  			rel, ok := db.Statement.Schema.Relationships.Relations[column]
    39  			if !ok {
    40  				continue
    41  			}
    42  
    43  			switch rel.Type {
    44  			case schema.HasOne, schema.HasMany:
    45  				queryConds := rel.ToQueryConditions(db.Statement.ReflectValue)
    46  				modelValue := reflect.New(rel.FieldSchema.ModelType).Interface()
    47  				tx := db.Session(&gorm.Session{NewDB: true}).Model(modelValue)
    48  				withoutConditions := false
    49  				if db.Statement.Unscoped {
    50  					tx = tx.Unscoped()
    51  				}
    52  
    53  				if len(db.Statement.Selects) > 0 {
    54  					selects := make([]string, 0, len(db.Statement.Selects))
    55  					for _, s := range db.Statement.Selects {
    56  						if s == clause.Associations {
    57  							selects = append(selects, s)
    58  						} else if columnPrefix := column + "."; strings.HasPrefix(s, columnPrefix) {
    59  							selects = append(selects, strings.TrimPrefix(s, columnPrefix))
    60  						}
    61  					}
    62  
    63  					if len(selects) > 0 {
    64  						tx = tx.Select(selects)
    65  					}
    66  				}
    67  
    68  				for _, cond := range queryConds {
    69  					if c, ok := cond.(clause.IN); ok && len(c.Values) == 0 {
    70  						withoutConditions = true
    71  						break
    72  					}
    73  				}
    74  
    75  				if !withoutConditions && db.AddError(tx.Clauses(clause.Where{Exprs: queryConds}).Delete(modelValue).Error) != nil {
    76  					return
    77  				}
    78  			case schema.Many2Many:
    79  				var (
    80  					queryConds     = make([]clause.Expression, 0, len(rel.References))
    81  					foreignFields  = make([]*schema.Field, 0, len(rel.References))
    82  					relForeignKeys = make([]string, 0, len(rel.References))
    83  					modelValue     = reflect.New(rel.JoinTable.ModelType).Interface()
    84  					table          = rel.JoinTable.Table
    85  					tx             = db.Session(&gorm.Session{NewDB: true}).Model(modelValue).Table(table)
    86  				)
    87  
    88  				for _, ref := range rel.References {
    89  					if ref.OwnPrimaryKey {
    90  						foreignFields = append(foreignFields, ref.PrimaryKey)
    91  						relForeignKeys = append(relForeignKeys, ref.ForeignKey.DBName)
    92  					} else if ref.PrimaryValue != "" {
    93  						queryConds = append(queryConds, clause.Eq{
    94  							Column: clause.Column{Table: rel.JoinTable.Table, Name: ref.ForeignKey.DBName},
    95  							Value:  ref.PrimaryValue,
    96  						})
    97  					}
    98  				}
    99  
   100  				_, foreignValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, foreignFields)
   101  				column, values := schema.ToQueryValues(table, relForeignKeys, foreignValues)
   102  				queryConds = append(queryConds, clause.IN{Column: column, Values: values})
   103  
   104  				if db.AddError(tx.Clauses(clause.Where{Exprs: queryConds}).Delete(modelValue).Error) != nil {
   105  					return
   106  				}
   107  			}
   108  		}
   109  
   110  	}
   111  }
   112  
   113  func Delete(config *Config) func(db *gorm.DB) {
   114  	supportReturning := utils.Contains(config.DeleteClauses, "RETURNING")
   115  
   116  	return func(db *gorm.DB) {
   117  		if db.Error != nil {
   118  			return
   119  		}
   120  
   121  		if db.Statement.SQL.Len() == 0 {
   122  			db.Statement.SQL.Grow(100)
   123  			db.Statement.AddClauseIfNotExists(clause.Delete{})
   124  
   125  			if db.Statement.Schema != nil {
   126  				_, queryValues := schema.GetIdentityFieldValuesMap(db.Statement.ReflectValue, db.Statement.Schema.PrimaryFields)
   127  				column, values := schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
   128  
   129  				if len(values) > 0 {
   130  					db.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
   131  				}
   132  
   133  				if db.Statement.ReflectValue.CanAddr() && db.Statement.Dest != db.Statement.Model && db.Statement.Model != nil {
   134  					_, queryValues = schema.GetIdentityFieldValuesMap(reflect.ValueOf(db.Statement.Model), db.Statement.Schema.PrimaryFields)
   135  					column, values = schema.ToQueryValues(db.Statement.Table, db.Statement.Schema.PrimaryFieldDBNames, queryValues)
   136  
   137  					if len(values) > 0 {
   138  						db.Statement.AddClause(clause.Where{Exprs: []clause.Expression{clause.IN{Column: column, Values: values}}})
   139  					}
   140  				}
   141  			}
   142  
   143  			db.Statement.AddClauseIfNotExists(clause.From{})
   144  		}
   145  
   146  		if db.Statement.Schema != nil {
   147  			for _, c := range db.Statement.Schema.DeleteClauses {
   148  				db.Statement.AddClause(c)
   149  			}
   150  		}
   151  
   152  		if db.Statement.SQL.Len() == 0 {
   153  			db.Statement.Build(db.Statement.BuildClauses...)
   154  		}
   155  
   156  		if _, ok := db.Statement.Clauses["WHERE"]; !db.AllowGlobalUpdate && !ok && db.Error == nil {
   157  			db.AddError(gorm.ErrMissingWhereClause)
   158  			return
   159  		}
   160  
   161  		if !db.DryRun && db.Error == nil {
   162  			ok, mode := hasReturning(db, supportReturning)
   163  			if !ok {
   164  				result, err := db.Statement.ConnPool.ExecContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...)
   165  				if db.AddError(err) == nil {
   166  					db.RowsAffected, _ = result.RowsAffected()
   167  				}
   168  
   169  				return
   170  			}
   171  
   172  			if rows, err := db.Statement.ConnPool.QueryContext(db.Statement.Context, db.Statement.SQL.String(), db.Statement.Vars...); db.AddError(err) == nil {
   173  				gorm.Scan(rows, db, mode)
   174  				db.AddError(rows.Close())
   175  			}
   176  		}
   177  	}
   178  }
   179  
   180  func AfterDelete(db *gorm.DB) {
   181  	if db.Error == nil && db.Statement.Schema != nil && !db.Statement.SkipHooks && db.Statement.Schema.AfterDelete {
   182  		callMethod(db, func(value interface{}, tx *gorm.DB) bool {
   183  			if i, ok := value.(AfterDeleteInterface); ok {
   184  				db.AddError(i.AfterDelete(tx))
   185  				return true
   186  			}
   187  			return false
   188  		})
   189  	}
   190  }