mirror of
https://gitee.com/johng/gf
synced 2026-07-08 14:39:50 +08:00
add unit testing case for auto time and soft deleting features for package gdb
This commit is contained in:
@ -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.
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()
|
||||
|
||||
149
database/gdb/gdb_unit_z_mysql_time_test.go
Normal file
149
database/gdb/gdb_unit_z_mysql_time_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user