From 056cecc97e9ef3f5fd216944a495c41aa98f4e4a Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Mon, 20 Feb 2023 07:17:35 +0800 Subject: [PATCH] Add `Truncate` method (#2220) This PR adds a `Truncate` method which allows to delete all existing rows in a table. The current `Delete` implementation enforces conditions to prevent accidental data deletion. Co-authored-by: KN4CK3R Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2220 Reviewed-by: Lunny Xiao Co-authored-by: KN4CK3R Co-committed-by: KN4CK3R --- engine.go | 9 +++++++++ integrations/session_delete_test.go | 27 ++++++++++++++++++++++++++- interface.go | 1 + session_delete.go | 13 ++++++++++++- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/engine.go b/engine.go index f10e30d3..fb19176e 100644 --- a/engine.go +++ b/engine.go @@ -1233,12 +1233,21 @@ func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64 } // Delete records, bean's non-empty fields are conditions +// At least one condition must be set. func (engine *Engine) Delete(beans ...interface{}) (int64, error) { session := engine.NewSession() defer session.Close() return session.Delete(beans...) } +// Truncate records, bean's non-empty fields are conditions +// In contrast to Delete this method allows deletes without conditions. +func (engine *Engine) Truncate(beans ...interface{}) (int64, error) { + session := engine.NewSession() + defer session.Close() + return session.Truncate(beans...) +} + // Get retrieve one record from table, bean's non-empty fields // are conditions func (engine *Engine) Get(beans ...interface{}) (bool, error) { diff --git a/integrations/session_delete_test.go b/integrations/session_delete_test.go index b4e40edb..680c3215 100644 --- a/integrations/session_delete_test.go +++ b/integrations/session_delete_test.go @@ -208,7 +208,7 @@ func TestUnscopeDelete(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 1, cnt) - var nowUnix = time.Now().Unix() + nowUnix := time.Now().Unix() var s UnscopeDeleteStruct cnt, err = testEngine.ID(1).Delete(&s) assert.NoError(t, err) @@ -266,3 +266,28 @@ func TestDelete2(t *testing.T) { assert.NoError(t, err) assert.False(t, has) } + +func TestTruncate(t *testing.T) { + assert.NoError(t, PrepareEngine()) + + type TruncateUser struct { + Uid int64 `xorm:"id pk not null autoincr"` + } + + assert.NoError(t, testEngine.Sync(new(TruncateUser))) + + cnt, err := testEngine.Insert(&TruncateUser{}) + assert.NoError(t, err) + assert.EqualValues(t, 1, cnt) + + _, err = testEngine.Delete(&TruncateUser{}) + assert.Error(t, err) + + _, err = testEngine.Truncate(&TruncateUser{}) + assert.NoError(t, err) + + user2 := TruncateUser{} + has, err := testEngine.ID(1).Get(&user2) + assert.NoError(t, err) + assert.False(t, has) +} diff --git a/interface.go b/interface.go index 6ad0577a..d10abe9e 100644 --- a/interface.go +++ b/interface.go @@ -31,6 +31,7 @@ type Interface interface { Decr(column string, arg ...interface{}) *Session Desc(...string) *Session Delete(...interface{}) (int64, error) + Truncate(...interface{}) (int64, error) Distinct(columns ...string) *Session DropIndexes(bean interface{}) error Exec(sqlOrArgs ...interface{}) (sql.Result, error) diff --git a/session_delete.go b/session_delete.go index 322d5a44..d36b9e52 100644 --- a/session_delete.go +++ b/session_delete.go @@ -91,7 +91,18 @@ func (session *Session) cacheDelete(table *schemas.Table, tableName, sqlStr stri } // Delete records, bean's non-empty fields are conditions +// At least one condition must be set. func (session *Session) Delete(beans ...interface{}) (int64, error) { + return session.delete(beans, true) +} + +// Truncate records, bean's non-empty fields are conditions +// In contrast to Delete this method allows deletes without conditions. +func (session *Session) Truncate(beans ...interface{}) (int64, error) { + return session.delete(beans, false) +} + +func (session *Session) delete(beans []interface{}, mustHaveConditions bool) (int64, error) { if session.isAutoClose { defer session.Close() } @@ -127,7 +138,7 @@ func (session *Session) Delete(beans ...interface{}) (int64, error) { } pLimitN := session.statement.LimitN - if condWriter.Len() == 0 && (pLimitN == nil || *pLimitN == 0) { + if mustHaveConditions && condWriter.Len() == 0 && (pLimitN == nil || *pLimitN == 0) { return 0, ErrNeedDeletedCond }