add unit testing case for auto time and soft deleting features for package gdb

This commit is contained in:
John
2020-04-09 22:48:21 +08:00
parent 53aba2d4b8
commit ef286b0c15
8 changed files with 181 additions and 18 deletions

View File

@ -37,7 +37,7 @@ type Model struct {
cacheEnabled bool // Enable sql result cache feature.
cacheDuration time.Duration // Cache TTL duration.
cacheName string // Cache name for custom operation.
force bool // Force select/delete without soft operation features.
unscoped bool // Disables soft deleting features when select/delete operations.
safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model.
}

View File

@ -12,13 +12,13 @@ import (
"github.com/gogf/gf/os/gtime"
)
// Force enables/disables the soft deleting feature.
func (m *Model) Force(force ...bool) *Model {
// Unscoped enables/disables the soft deleting feature.
func (m *Model) Unscoped(unscoped ...bool) *Model {
model := m.getModel()
if len(force) > 0 {
model.force = force[0]
if len(unscoped) > 0 {
model.unscoped = unscoped[0]
} else {
model.force = true
model.unscoped = true
}
return model
}
@ -40,7 +40,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) {
conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false)
)
// Soft deleting.
if !m.force && fieldNameDelete != "" {
if !m.unscoped && fieldNameDelete != "" {
return m.db.DoUpdate(
m.getLink(true),
m.tables,

View File

@ -157,7 +157,7 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql.
batch = m.batch
}
// Automatic handling for creating/updating time.
if !m.force && (fieldNameCreate != "" || fieldNameUpdate != "") {
if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") {
for k, v := range list {
if fieldNameCreate != "" && !gutil.MapContainsPossibleKey(v, fieldNameCreate) {
v[fieldNameCreate] = nowString
@ -179,7 +179,7 @@ func (m *Model) doInsertWithOption(option int, data ...interface{}) (result sql.
// Single operation.
if data, ok := m.data.(Map); ok {
// Automatic handling for creating/updating time.
if !m.force && (fieldNameCreate != "" || fieldNameUpdate != "") {
if !m.unscoped && (fieldNameCreate != "" || fieldNameUpdate != "") {
if fieldNameCreate != "" && !gutil.MapContainsPossibleKey(data, fieldNameCreate) {
data[fieldNameCreate] = nowString
}

View File

@ -34,8 +34,10 @@ func (m *Model) All(where ...interface{}) (Result, error) {
fieldNameDelete = m.getSoftFieldNameDelete()
conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false)
)
if !m.force && fieldNameDelete != "" {
if conditionWhere != "" {
if !m.unscoped && fieldNameDelete != "" {
if conditionWhere == "" {
conditionWhere = " WHERE"
} else {
conditionWhere += " AND"
}
conditionWhere += fmt.Sprintf(` %s IS NULL`, m.db.QuoteWord(fieldNameDelete))
@ -244,7 +246,19 @@ func (m *Model) Count(where ...interface{}) (int, error) {
if m.fields != "" && m.fields != "*" {
countFields = fmt.Sprintf(`COUNT(%s)`, m.fields)
}
conditionWhere, conditionExtra, conditionArgs := m.formatCondition(false)
var (
fieldNameDelete = m.getSoftFieldNameDelete()
conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false)
)
if !m.unscoped && fieldNameDelete != "" {
if conditionWhere == "" {
conditionWhere = " WHERE"
} else {
conditionWhere += " AND"
}
conditionWhere += fmt.Sprintf(` %s IS NULL`, m.db.QuoteWord(fieldNameDelete))
}
s := fmt.Sprintf("SELECT %s FROM %s %s", countFields, m.tables, conditionWhere+conditionExtra)
if len(m.groupBy) > 0 {
s = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", s)

View File

@ -46,7 +46,7 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro
conditionWhere, conditionExtra, conditionArgs = m.formatCondition(false)
)
// Automatically update the record updating time.
if !m.force && fieldNameUpdate != "" {
if !m.unscoped && fieldNameUpdate != "" {
var (
refValue = reflect.ValueOf(m.data)
refKind = refValue.Kind()

View File

@ -0,0 +1,149 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gdb_test
import (
"fmt"
"github.com/gogf/gf/os/gtime"
"testing"
"time"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/test/gtest"
)
func Test_CreateUpdateDeleteTime(t *testing.T) {
table := "time_test_table"
if _, err := db.Exec(fmt.Sprintf(`
CREATE TABLE %s (
id int(11) NOT NULL,
name varchar(45) DEFAULT NULL,
create_at datetime DEFAULT NULL,
update_at datetime DEFAULT NULL,
delete_at datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`, table)); err != nil {
gtest.Error(err)
}
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
// Insert
dataInsert := g.Map{
"id": 1,
"name": "name_1",
}
r, err := db.Table(table).Data(dataInsert).Insert()
t.Assert(err, nil)
n, _ := r.RowsAffected()
t.Assert(n, 1)
oneInsert, err := db.Table(table).FindOne(1)
t.Assert(err, nil)
t.Assert(oneInsert["id"].Int(), 1)
t.Assert(oneInsert["name"].String(), "name_1")
t.Assert(oneInsert["delete_at"].String(), "")
t.AssertGE(oneInsert["create_at"].GTime().Timestamp(), gtime.Timestamp()-2)
t.AssertGE(oneInsert["update_at"].GTime().Timestamp(), gtime.Timestamp())
time.Sleep(2 * time.Second)
// Save
dataSave := g.Map{
"id": 1,
"name": "name_10",
}
r, err = db.Table(table).Data(dataSave).Save()
t.Assert(err, nil)
n, _ = r.RowsAffected()
t.Assert(n, 2)
oneSave, err := db.Table(table).FindOne(1)
t.Assert(err, nil)
t.Assert(oneSave["id"].Int(), 1)
t.Assert(oneSave["name"].String(), "name_10")
t.Assert(oneSave["delete_at"].String(), "")
t.Assert(oneSave["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp())
t.AssertNE(oneSave["update_at"].GTime().Timestamp(), oneInsert["update_at"].GTime().Timestamp())
t.AssertGE(oneSave["update_at"].GTime().Timestamp(), gtime.Now().Timestamp()-2)
time.Sleep(2 * time.Second)
// Update
dataUpdate := g.Map{
"id": 1,
"name": "name_1000",
}
r, err = db.Table(table).Data(dataUpdate).WherePri(1).Update()
t.Assert(err, nil)
n, _ = r.RowsAffected()
t.Assert(n, 1)
oneUpdate, err := db.Table(table).FindOne(1)
t.Assert(err, nil)
t.Assert(oneUpdate["id"].Int(), 1)
t.Assert(oneUpdate["name"].String(), "name_1000")
t.Assert(oneUpdate["delete_at"].String(), "")
t.Assert(oneUpdate["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp())
t.AssertGE(oneUpdate["update_at"].GTime().Timestamp(), gtime.Now().Timestamp()-2)
// Replace
dataReplace := g.Map{
"id": 1,
"name": "name_100",
}
r, err = db.Table(table).Data(dataReplace).Replace()
t.Assert(err, nil)
n, _ = r.RowsAffected()
t.Assert(n, 2)
oneReplace, err := db.Table(table).FindOne(1)
t.Assert(err, nil)
t.Assert(oneReplace["id"].Int(), 1)
t.Assert(oneReplace["name"].String(), "name_100")
t.Assert(oneReplace["delete_at"].String(), "")
t.AssertGE(oneReplace["create_at"].GTime().Timestamp(), oneInsert["create_at"].GTime().Timestamp())
t.AssertGE(oneReplace["update_at"].GTime().Timestamp(), oneInsert["update_at"].GTime().Timestamp())
time.Sleep(2 * time.Second)
// Delete
r, err = db.Table(table).Delete("id", 1)
t.Assert(err, nil)
n, _ = r.RowsAffected()
t.Assert(n, 1)
// Delete Select
one4, err := db.Table(table).FindOne(1)
t.Assert(err, nil)
t.Assert(len(one4), 0)
one5, err := db.Table(table).Unscoped().FindOne(1)
t.Assert(err, nil)
t.Assert(one5["id"].Int(), 1)
t.AssertGE(one5["delete_at"].GTime().Timestamp(), gtime.Now().Timestamp()-2)
// Delete Count
i, err := db.Table(table).FindCount()
t.Assert(err, nil)
t.Assert(i, 0)
i, err = db.Table(table).Unscoped().FindCount()
t.Assert(err, nil)
t.Assert(i, 1)
// Delete Unscoped
r, err = db.Table(table).Unscoped().Delete("id", 1)
t.Assert(err, nil)
n, _ = r.RowsAffected()
t.Assert(n, 1)
one6, err := db.Table(table).Unscoped().FindOne(1)
t.Assert(err, nil)
t.Assert(len(one6), 0)
i, err = db.Table(table).Unscoped().FindCount()
t.Assert(err, nil)
t.Assert(i, 0)
})
}