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 }