2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2020-04-08 21:26:14 +08:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
|
|
|
|
import (
|
2020-04-11 09:09:25 +08:00
|
|
|
"fmt"
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/container/garray"
|
|
|
|
"github.com/gogf/gf/v2/text/gregex"
|
|
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
|
|
"github.com/gogf/gf/v2/util/gutil"
|
2020-04-08 21:26:14 +08:00
|
|
|
)
|
|
|
|
|
2020-10-20 21:01:39 +08:00
|
|
|
var (
|
|
|
|
createdFiledNames = []string{"created_at", "create_at"} // Default filed names of table for automatic-filled created datetime.
|
|
|
|
updatedFiledNames = []string{"updated_at", "update_at"} // Default filed names of table for automatic-filled updated datetime.
|
2020-10-27 10:40:47 +08:00
|
|
|
deletedFiledNames = []string{"deleted_at", "delete_at"} // Default filed names of table for automatic-filled deleted datetime.
|
2020-04-08 21:26:14 +08:00
|
|
|
)
|
|
|
|
|
2020-09-27 23:37:40 +08:00
|
|
|
// Unscoped disables the auto-update time feature for insert, update and delete options.
|
|
|
|
func (m *Model) Unscoped() *Model {
|
|
|
|
model := m.getModel()
|
|
|
|
model.unscoped = true
|
|
|
|
return model
|
|
|
|
}
|
|
|
|
|
2020-04-08 21:26:14 +08:00
|
|
|
// getSoftFieldNameCreate checks and returns the field name for record creating time.
|
|
|
|
// If there's no field name for storing creating time, it returns an empty string.
|
|
|
|
// It checks the key with or without cases or chars '-'/'_'/'.'/' '.
|
2020-10-20 21:01:39 +08:00
|
|
|
func (m *Model) getSoftFieldNameCreated(table ...string) string {
|
2020-11-27 13:28:18 +08:00
|
|
|
// It checks whether this feature disabled.
|
|
|
|
if m.db.GetConfig().TimeMaintainDisabled {
|
|
|
|
return ""
|
|
|
|
}
|
2020-04-26 21:31:55 +08:00
|
|
|
tableName := ""
|
2020-04-11 09:09:25 +08:00
|
|
|
if len(table) > 0 {
|
2020-04-26 21:31:55 +08:00
|
|
|
tableName = table[0]
|
2020-04-11 09:09:25 +08:00
|
|
|
} else {
|
2021-07-06 20:59:09 +08:00
|
|
|
tableName = m.tablesInit
|
2020-04-08 21:26:14 +08:00
|
|
|
}
|
2020-10-20 21:01:39 +08:00
|
|
|
config := m.db.GetConfig()
|
|
|
|
if config.CreatedAt != "" {
|
2020-11-26 20:17:24 +08:00
|
|
|
return m.getSoftFieldName(tableName, []string{config.CreatedAt})
|
2020-10-20 21:01:39 +08:00
|
|
|
}
|
|
|
|
return m.getSoftFieldName(tableName, createdFiledNames)
|
2020-04-08 21:26:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// getSoftFieldNameUpdate checks and returns the field name for record updating time.
|
|
|
|
// If there's no field name for storing updating time, it returns an empty string.
|
|
|
|
// It checks the key with or without cases or chars '-'/'_'/'.'/' '.
|
2020-10-20 21:01:39 +08:00
|
|
|
func (m *Model) getSoftFieldNameUpdated(table ...string) (field string) {
|
2020-11-27 13:28:18 +08:00
|
|
|
// It checks whether this feature disabled.
|
|
|
|
if m.db.GetConfig().TimeMaintainDisabled {
|
|
|
|
return ""
|
|
|
|
}
|
2020-04-26 21:31:55 +08:00
|
|
|
tableName := ""
|
2020-04-11 09:09:25 +08:00
|
|
|
if len(table) > 0 {
|
2020-04-26 21:31:55 +08:00
|
|
|
tableName = table[0]
|
2020-04-11 09:09:25 +08:00
|
|
|
} else {
|
2021-07-06 20:59:09 +08:00
|
|
|
tableName = m.tablesInit
|
2020-04-08 21:26:14 +08:00
|
|
|
}
|
2020-10-20 21:01:39 +08:00
|
|
|
config := m.db.GetConfig()
|
|
|
|
if config.UpdatedAt != "" {
|
2020-11-26 20:17:24 +08:00
|
|
|
return m.getSoftFieldName(tableName, []string{config.UpdatedAt})
|
2020-10-20 21:01:39 +08:00
|
|
|
}
|
|
|
|
return m.getSoftFieldName(tableName, updatedFiledNames)
|
2020-04-08 21:26:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// getSoftFieldNameDelete checks and returns the field name for record deleting time.
|
|
|
|
// If there's no field name for storing deleting time, it returns an empty string.
|
|
|
|
// It checks the key with or without cases or chars '-'/'_'/'.'/' '.
|
2020-10-20 21:01:39 +08:00
|
|
|
func (m *Model) getSoftFieldNameDeleted(table ...string) (field string) {
|
2020-11-27 13:28:18 +08:00
|
|
|
// It checks whether this feature disabled.
|
|
|
|
if m.db.GetConfig().TimeMaintainDisabled {
|
|
|
|
return ""
|
|
|
|
}
|
2020-04-26 21:31:55 +08:00
|
|
|
tableName := ""
|
2020-04-11 09:09:25 +08:00
|
|
|
if len(table) > 0 {
|
2020-04-26 21:31:55 +08:00
|
|
|
tableName = table[0]
|
2020-04-11 09:09:25 +08:00
|
|
|
} else {
|
2021-07-06 20:59:09 +08:00
|
|
|
tableName = m.tablesInit
|
2020-04-11 09:09:25 +08:00
|
|
|
}
|
2020-10-20 21:01:39 +08:00
|
|
|
config := m.db.GetConfig()
|
|
|
|
if config.UpdatedAt != "" {
|
2020-11-26 20:17:24 +08:00
|
|
|
return m.getSoftFieldName(tableName, []string{config.DeletedAt})
|
2020-10-20 21:01:39 +08:00
|
|
|
}
|
|
|
|
return m.getSoftFieldName(tableName, deletedFiledNames)
|
2020-04-11 09:09:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// getSoftFieldName retrieves and returns the field name of the table for possible key.
|
2020-10-20 21:01:39 +08:00
|
|
|
func (m *Model) getSoftFieldName(table string, keys []string) (field string) {
|
2021-04-04 12:01:22 +08:00
|
|
|
fieldsMap, _ := m.TableFields(table)
|
2020-04-08 21:26:14 +08:00
|
|
|
if len(fieldsMap) > 0 {
|
2020-10-20 21:01:39 +08:00
|
|
|
for _, key := range keys {
|
|
|
|
field, _ = gutil.MapPossibleItemByKey(
|
|
|
|
gconv.Map(fieldsMap), key,
|
|
|
|
)
|
|
|
|
if field != "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2020-04-08 21:26:14 +08:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-04-11 09:09:25 +08:00
|
|
|
|
|
|
|
// getConditionForSoftDeleting retrieves and returns the condition string for soft deleting.
|
|
|
|
// It supports multiple tables string like:
|
|
|
|
// "user u, user_detail ud"
|
|
|
|
// "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid)"
|
|
|
|
// "user LEFT JOIN user_detail ON(user_detail.uid=user.uid)"
|
|
|
|
// "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid) LEFT JOIN user_stats us ON(us.uid=u.uid)"
|
|
|
|
func (m *Model) getConditionForSoftDeleting() string {
|
2020-04-11 10:14:49 +08:00
|
|
|
if m.unscoped {
|
|
|
|
return ""
|
|
|
|
}
|
2020-04-11 09:09:25 +08:00
|
|
|
conditionArray := garray.NewStrArray()
|
|
|
|
if gstr.Contains(m.tables, " JOIN ") {
|
|
|
|
// Base table.
|
|
|
|
match, _ := gregex.MatchString(`(.+?) [A-Z]+ JOIN`, m.tables)
|
|
|
|
conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
|
2020-09-03 21:57:58 +08:00
|
|
|
// Multiple joined tables, exclude the sub query sql which contains char '(' and ')'.
|
|
|
|
matches, _ := gregex.MatchAllString(`JOIN ([^()]+?) ON`, m.tables)
|
2020-04-11 09:09:25 +08:00
|
|
|
for _, match := range matches {
|
|
|
|
conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(match[1]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if conditionArray.Len() == 0 && gstr.Contains(m.tables, ",") {
|
|
|
|
// Multiple base tables.
|
|
|
|
for _, s := range gstr.SplitAndTrim(m.tables, ",") {
|
|
|
|
conditionArray.Append(m.getConditionOfTableStringForSoftDeleting(s))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conditionArray.FilterEmpty()
|
|
|
|
if conditionArray.Len() > 0 {
|
|
|
|
return conditionArray.Join(" AND ")
|
|
|
|
}
|
|
|
|
// Only one table.
|
2020-10-20 21:01:39 +08:00
|
|
|
if fieldName := m.getSoftFieldNameDeleted(); fieldName != "" {
|
2021-05-21 13:25:53 +08:00
|
|
|
return fmt.Sprintf(`%s IS NULL`, m.db.GetCore().QuoteWord(fieldName))
|
2020-04-11 09:09:25 +08:00
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// getConditionOfTableStringForSoftDeleting does something as its name describes.
|
|
|
|
func (m *Model) getConditionOfTableStringForSoftDeleting(s string) string {
|
|
|
|
var (
|
|
|
|
field = ""
|
|
|
|
table = ""
|
|
|
|
array1 = gstr.SplitAndTrim(s, " ")
|
|
|
|
array2 = gstr.SplitAndTrim(array1[0], ".")
|
|
|
|
)
|
|
|
|
if len(array2) >= 2 {
|
|
|
|
table = array2[1]
|
|
|
|
} else {
|
|
|
|
table = array2[0]
|
|
|
|
}
|
2020-10-20 21:01:39 +08:00
|
|
|
field = m.getSoftFieldNameDeleted(table)
|
2020-04-11 09:09:25 +08:00
|
|
|
if field == "" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
if len(array1) >= 3 {
|
2021-05-21 13:25:53 +08:00
|
|
|
return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(array1[2]), m.db.GetCore().QuoteWord(field))
|
2020-04-11 09:09:25 +08:00
|
|
|
}
|
|
|
|
if len(array1) >= 2 {
|
2021-05-21 13:25:53 +08:00
|
|
|
return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(array1[1]), m.db.GetCore().QuoteWord(field))
|
2020-04-11 09:09:25 +08:00
|
|
|
}
|
2021-05-21 13:25:53 +08:00
|
|
|
return fmt.Sprintf(`%s.%s IS NULL`, m.db.GetCore().QuoteWord(table), m.db.GetCore().QuoteWord(field))
|
2020-04-11 09:09:25 +08:00
|
|
|
}
|