From b510fc584f361a42cd9df19c887a45fc88863bb1 Mon Sep 17 00:00:00 2001 From: Kazuhiro Oinuma Date: Mon, 3 Nov 2014 22:03:12 +0900 Subject: [PATCH] Add softdelete feature --- engine.go | 9 +++++++++ session.go | 36 +++++++++++++++++++++++++++++++++--- statement.go | 7 +++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/engine.go b/engine.go index cc498441..81eae28a 100644 --- a/engine.go +++ b/engine.go @@ -45,6 +45,7 @@ type Engine struct { TZLocation *time.Location disableGlobalCache bool + unscoped bool } func (engine *Engine) SetDisableGlobalCache(disable bool) { @@ -796,6 +797,8 @@ func (engine *Engine) mapType(v reflect.Value) *core.Table { if !hasNoCacheTag { hasNoCacheTag = true } + case k == "SOFTDELETE": + col.IsSoftDelete = true case k == "NOT": default: if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") { @@ -1414,3 +1417,9 @@ func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{} } return } + +// Disable soft delete +func (engine *Engine) Unscoped() *Engine { + engine.unscoped = true + return engine +} diff --git a/session.go b/session.go index 9af02bfe..c6002b5c 100644 --- a/session.go +++ b/session.go @@ -3402,13 +3402,39 @@ func (session *Session) Delete(bean interface{}) (int64, error) { return 0, ErrNeedDeletedCond } - sqlStr := fmt.Sprintf("DELETE FROM %v WHERE %v", - session.Engine.Quote(session.Statement.TableName()), condition) + sqlStr, sqlStrForCache := "", "" + argsForCache := make([]interface{}, 0, len(args) * 2) + if session.Engine.unscoped || table.SoftDeleteColumn() == nil { // softdelete is disabled + sqlStr = fmt.Sprintf("DELETE FROM %v WHERE %v", + session.Engine.Quote(session.Statement.TableName()), condition) + + sqlStrForCache = sqlStr + copy(argsForCache, args) + argsForCache = append(session.Statement.Params, argsForCache...) + } else { + // !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache. + sqlStrForCache = fmt.Sprintf("DELETE FROM %v WHERE %v", + session.Engine.Quote(session.Statement.TableName()), condition) + copy(argsForCache, args) + argsForCache = append(session.Statement.Params, argsForCache...) + + softDeleteCol := table.SoftDeleteColumn() + sqlStr = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v", + session.Engine.Quote(session.Statement.TableName()), + session.Engine.Quote(softDeleteCol.Name), + condition) + + // !oinume! Insert NowTime to the head of session.Statement.Params + session.Statement.Params = append(session.Statement.Params, "") + paramsLen := len(session.Statement.Params) + copy(session.Statement.Params[1:paramsLen], session.Statement.Params[0:paramsLen-1]) + session.Statement.Params[0] = session.Engine.NowTime(softDeleteCol.SQLType.Name) + } args = append(session.Statement.Params, args...) if cacher := session.Engine.getCacher2(session.Statement.RefTable); cacher != nil && session.Statement.UseCache { - session.cacheDelete(sqlStr, args...) + session.cacheDelete(sqlStrForCache, argsForCache...) } res, err := session.exec(sqlStr, args...) @@ -3651,6 +3677,10 @@ func genCols(table *core.Table, session *Session, bean interface{}, useCol bool, } } + if col.IsSoftDelete { + continue + } + if session.Statement.ColumnStr != "" { if _, ok := session.Statement.columnMap[lColName]; !ok { continue diff --git a/statement.go b/statement.go index 7391629d..ade939f5 100644 --- a/statement.go +++ b/statement.go @@ -286,6 +286,9 @@ func buildUpdates(engine *Engine, table *core.Table, bean interface{}, if !includeAutoIncr && col.IsAutoIncrement { continue } + if col.IsSoftDelete { + continue + } if engine.dialect.DBType() == core.MSSQL && col.SQLType.Name == core.Text { continue @@ -490,6 +493,10 @@ func buildConditions(engine *Engine, table *core.Table, bean interface{}, continue } + if col.IsSoftDelete && !engine.unscoped { // softdelete enabled + colNames = append(colNames, fmt.Sprintf("%v IS NULL", engine.Quote(col.Name))) + } + fieldValue := *fieldValuePtr if fieldValue.Interface() == nil { continue