代码拉取完成,页面将自动刷新
// 版权归GoFrame作者(https://goframe.org)所有。保留所有权利。
//
// 本源代码形式受MIT许可证条款约束。
// 如果未随本文件一同分发MIT许可证副本,
// 您可以在https://github.com/gogf/gf处获取。
// md5:a9832f33b234e3f3
package db类
import (
"context"
"fmt"
"strings"
garray "gitee.com/go_888/goframe/container/garray"
gcode "gitee.com/go_888/goframe/errors/gcode"
gerror "gitee.com/go_888/goframe/errors/gerror"
"gitee.com/go_888/goframe/internal/intlog"
gcache "gitee.com/go_888/goframe/os/gcache"
gtime "gitee.com/go_888/goframe/os/gtime"
gregex "gitee.com/go_888/goframe/text/gregex"
gstr "gitee.com/go_888/goframe/text/gstr"
gconv "gitee.com/go_888/goframe/util/gconv"
gutil "gitee.com/go_888/goframe/util/gutil"
)
// SoftTimeType自定义定义软时间字段类型。 md5:dac7cb3a21ca2d1d
type SoftTimeType int
const (
X常量_SoftTimeTypeAuto SoftTimeType = 0 // (默认)根据表字段类型自动检测字段类型。 md5:92b9309fac6f4d09
X常量_SoftTimeTypeTime SoftTimeType = 1 // 使用日期时间作为字段值。 md5:fb9be1cf84e4192e
X常量_SoftTimeTypeTimestamp SoftTimeType = 2 // In unix seconds.
X常量_SoftTimeTypeTimestampMilli SoftTimeType = 3 // In unix milliseconds.
X常量_SoftTimeTypeTimestampMicro SoftTimeType = 4 // In unix microseconds.
X常量_SoftTimeTypeTimestampNano SoftTimeType = 5 // In unix nanoseconds.
)
// X结构_SoftTimeOption 是用于自定义 Model 的软时间功能的选项。 md5:fcc19f5ef8ad45e7
type X结构_SoftTimeOption struct {
SoftTimeType SoftTimeType // 软时间字段的值类型。 md5:472088e64d8a928f
}
type softTimeMaintainer struct {
*X结构_Model
}
type iSoftTimeMaintainer interface {
GetFieldNameAndTypeForCreate(
ctx context.Context, schema string, table string,
) (fieldName string, fieldType X类型_LocalType)
GetFieldNameAndTypeForUpdate(
ctx context.Context, schema string, table string,
) (fieldName string, fieldType X类型_LocalType)
GetFieldNameAndTypeForDelete(
ctx context.Context, schema string, table string,
) (fieldName string, fieldType X类型_LocalType)
GetValueByFieldTypeForCreateOrUpdate(
ctx context.Context, fieldType X类型_LocalType, isDeletedField bool,
) (dataValue any)
GetDataByFieldNameAndTypeForDelete(
ctx context.Context, fieldPrefix, fieldName string, fieldType X类型_LocalType,
) (dataHolder string, dataValue any)
GetWhereConditionForDelete(ctx context.Context) string
}
// getSoftFieldNameAndTypeCacheItem 是用于存储创建/更新/删除字段的内部结构体。 md5:df4233b79c5f6dad
type getSoftFieldNameAndTypeCacheItem struct {
FieldName string
FieldType X类型_LocalType
}
var (
// 当创建记录时,用于自动填充的表的默认字段名称。 md5:58c0524feef22203
createdFieldNames = []string{"created_at", "create_at"}
// 用于记录更新时自动填充的表默认字段名称。 md5:dfaf612ced6164b4
updatedFieldNames = []string{"updated_at", "update_at"}
// 默认的表字段名,用于自动填充记录删除。 md5:82caa57d9d8aac21
deletedFieldNames = []string{"deleted_at", "delete_at"}
)
// SoftTime 设置 SoftTimeOption 以自定义 Model 的软时间功能。 md5:6c4368abcd89e6b0
func (m *X结构_Model) SoftTime(option X结构_SoftTimeOption) *X结构_Model {
model := m.getModel()
model.softTimeOption = option
return model
}
// Unscoped禁用插入、更新和删除操作的软时间特性。 md5:0fc4af29459bd61e
func (m *X结构_Model) Unscoped() *X结构_Model {
model := m.getModel()
model.unscoped = true
return model
}
func (m *X结构_Model) softTimeMaintainer() iSoftTimeMaintainer {
return &softTimeMaintainer{
m,
}
}
// GetFieldNameAndTypeForCreate 检查并返回用于记录创建时间的字段名。
// 如果没有用于存储创建时间的字段名,它将返回一个空字符串。
// 它会检查键名,无论大小写或包含字符 '-'、'_'、'.'、' '。
// md5:c03150380846ea77
func (m *softTimeMaintainer) GetFieldNameAndTypeForCreate(
ctx context.Context, schema string, table string,
) (fieldName string, fieldType X类型_LocalType) {
// 检查是否禁用了此功能。 md5:413ae315bebe927f
if m.db.X取当前节点配置().TimeMaintainDisabled {
return "", X常量_LocalTypeUndefined
}
tableName := ""
if table != "" {
tableName = table
} else {
tableName = m.tablesInit
}
config := m.db.X取当前节点配置()
if config.CreatedAt != "" {
return m.getSoftFieldNameAndType(
ctx, schema, tableName, []string{config.CreatedAt},
)
}
return m.getSoftFieldNameAndType(
ctx, schema, tableName, createdFieldNames,
)
}
// GetFieldNameAndTypeForUpdate 检查并返回用于更新时间的字段名。如果没有用于存储更新时间的字段名,它将返回空字符串。它会检查带有或不带大小写、字符 '-'/'_'/'.'/' 的键。
// md5:220eb56737359035
func (m *softTimeMaintainer) GetFieldNameAndTypeForUpdate(
ctx context.Context, schema string, table string,
) (fieldName string, fieldType X类型_LocalType) {
// 检查是否禁用了此功能。 md5:413ae315bebe927f
if m.db.X取当前节点配置().TimeMaintainDisabled {
return "", X常量_LocalTypeUndefined
}
tableName := ""
if table != "" {
tableName = table
} else {
tableName = m.tablesInit
}
config := m.db.X取当前节点配置()
if config.UpdatedAt != "" {
return m.getSoftFieldNameAndType(
ctx, schema, tableName, []string{config.UpdatedAt},
)
}
return m.getSoftFieldNameAndType(
ctx, schema, tableName, updatedFieldNames,
)
}
// GetFieldNameAndTypeForDelete 检查并返回记录删除时间的字段名。如果没有用于存储删除时间的字段名,它将返回空字符串。它会检查大小写敏感或不敏感,以及使用 '-'、'_'、'.' 或 ' ' 作为分隔符的键。
// md5:f7c6b45838b970b0
func (m *softTimeMaintainer) GetFieldNameAndTypeForDelete(
ctx context.Context, schema string, table string,
) (fieldName string, fieldType X类型_LocalType) {
// 检查是否禁用了此功能。 md5:413ae315bebe927f
if m.db.X取当前节点配置().TimeMaintainDisabled {
return "", X常量_LocalTypeUndefined
}
tableName := ""
if table != "" {
tableName = table
} else {
tableName = m.tablesInit
}
config := m.db.X取当前节点配置()
if config.DeletedAt != "" {
return m.getSoftFieldNameAndType(
ctx, schema, tableName, []string{config.DeletedAt},
)
}
return m.getSoftFieldNameAndType(
ctx, schema, tableName, deletedFieldNames,
)
}
// getSoftFieldName 获取并返回表中可能键的字段名。 md5:e32e19240070c456
func (m *softTimeMaintainer) getSoftFieldNameAndType(
ctx context.Context,
schema string, table string, checkFiledNames []string,
) (fieldName string, fieldType X类型_LocalType) {
var (
cacheKey = fmt.Sprintf(`getSoftFieldNameAndType:%s#%s#%s`, schema, table, strings.Join(checkFiledNames, "_"))
cacheDuration = gcache.X常量_持续时间_无期限
cacheFunc = func(ctx context.Context) (value interface{}, err error) {
// 忽略TableFields函数的错误。 md5:b488d48f86ec5aea
fieldsMap, _ := m.X取表字段信息Map(table, schema)
if len(fieldsMap) > 0 {
for _, checkFiledName := range checkFiledNames {
fieldName, _ = gutil.Map查找并忽略大小写与符号(
gconv.X取Map(fieldsMap), checkFiledName,
)
if fieldName != "" {
fieldType, _ = m.db.X底层CheckLocalTypeForField(
ctx, fieldsMap[fieldName].X类型, nil,
)
var cacheItem = getSoftFieldNameAndTypeCacheItem{
FieldName: fieldName,
FieldType: fieldType,
}
return cacheItem, nil
}
}
}
return
}
)
result, err := gcache.X取值或设置值_函数(ctx, cacheKey, cacheFunc, cacheDuration)
if err != nil {
intlog.Error(ctx, err)
}
if result != nil {
var cacheItem getSoftFieldNameAndTypeCacheItem
if err = result.X取结构或结构数组(&cacheItem); err != nil {
return "", ""
}
fieldName = cacheItem.FieldName
fieldType = cacheItem.FieldType
}
return
}
// GetWhereConditionForDelete 用于检索并返回软删除的条件字符串。它支持多表字符串,例如:
// "user u, user_detail ud" - "用户 u 和 user_detail ud"
// "user u LEFT JOIN user_detail ud ON(ud.uid=u.uid)" - "用户 u 左连接 user_detail ud,连接条件为 ud.uid 等于 u.uid"
// "user LEFT JOIN user_detail ON(user_detail.uid=user.uid)" - "用户左连接 user_detail,连接条件为 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)" - "用户 u 先左连接 user_detail ud,再连接 user_stats us,连接条件为 us.uid 等于 u.uid"
// md5:f2c849c59f2ab188
func (m *softTimeMaintainer) GetWhereConditionForDelete(ctx context.Context) string {
if m.unscoped {
return ""
}
conditionArray := garray.X创建文本()
if gstr.X是否包含(m.tables, " JOIN ") {
// Base table.
tableMatch, _ := gregex.X匹配文本(`(.+?) [A-Z]+ JOIN`, m.tables)
conditionArray.X弃用_Append(m.getConditionOfTableStringForSoftDeleting(ctx, tableMatch[1]))
// 多个连接的表,排除包含字符'('和')'的子查询SQL。 md5:a9edf50410c73b2c
tableMatches, _ := gregex.X匹配全部文本(`JOIN ([^()]+?) ON`, m.tables)
for _, match := range tableMatches {
conditionArray.X弃用_Append(m.getConditionOfTableStringForSoftDeleting(ctx, match[1]))
}
}
if conditionArray.X取成员数() == 0 && gstr.X是否包含(m.tables, ",") {
// Multiple base tables.
for _, s := range gstr.X分割并忽略空值(m.tables, ",") {
conditionArray.X弃用_Append(m.getConditionOfTableStringForSoftDeleting(ctx, s))
}
}
conditionArray.X删除所有空值()
if conditionArray.X取成员数() > 0 {
return conditionArray.X连接(" AND ")
}
// Only one table.
fieldName, fieldType := m.GetFieldNameAndTypeForDelete(ctx, "", m.tablesInit)
if fieldName != "" {
return m.getConditionByFieldNameAndTypeForSoftDeleting(ctx, "", fieldName, fieldType)
}
return ""
}
// getConditionOfTableStringForSoftDeleting 的功能如其名称所述。
// `s` 的示例包括:
// - `test`.`demo` as b
// - `test`.`demo` b
// - `demo`
// - demo
// md5:ffb3e23129e1b6db
func (m *softTimeMaintainer) getConditionOfTableStringForSoftDeleting(ctx context.Context, s string) string {
var (
table string
schema string
array1 = gstr.X分割并忽略空值(s, " ")
array2 = gstr.X分割并忽略空值(array1[0], ".")
)
if len(array2) >= 2 {
table = array2[1]
schema = array2[0]
} else {
table = array2[0]
}
fieldName, fieldType := m.GetFieldNameAndTypeForDelete(ctx, schema, table)
if fieldName == "" {
return ""
}
if len(array1) >= 3 {
return m.getConditionByFieldNameAndTypeForSoftDeleting(ctx, array1[2], fieldName, fieldType)
}
if len(array1) >= 2 {
return m.getConditionByFieldNameAndTypeForSoftDeleting(ctx, array1[1], fieldName, fieldType)
}
return m.getConditionByFieldNameAndTypeForSoftDeleting(ctx, table, fieldName, fieldType)
}
// GetDataByFieldNameAndTypeForDelete 用于在软删除场景下,根据指定的字段名和类型创建并返回占位符和值。
// md5:276be24343264681
func (m *softTimeMaintainer) GetDataByFieldNameAndTypeForDelete(
ctx context.Context, fieldPrefix, fieldName string, fieldType X类型_LocalType,
) (dataHolder string, dataValue any) {
var (
quotedFieldPrefix = m.db.X取Core对象().X底层QuoteWord(fieldPrefix)
quotedFieldName = m.db.X取Core对象().X底层QuoteWord(fieldName)
)
if quotedFieldPrefix != "" {
quotedFieldName = fmt.Sprintf(`%s.%s`, quotedFieldPrefix, quotedFieldName)
}
dataHolder = fmt.Sprintf(`%s=?`, quotedFieldName)
dataValue = m.GetValueByFieldTypeForCreateOrUpdate(ctx, fieldType, false)
return
}
func (m *softTimeMaintainer) getConditionByFieldNameAndTypeForSoftDeleting(
ctx context.Context, fieldPrefix, fieldName string, fieldType X类型_LocalType,
) string {
var (
quotedFieldPrefix = m.db.X取Core对象().X底层QuoteWord(fieldPrefix)
quotedFieldName = m.db.X取Core对象().X底层QuoteWord(fieldName)
)
if quotedFieldPrefix != "" {
quotedFieldName = fmt.Sprintf(`%s.%s`, quotedFieldPrefix, quotedFieldName)
}
switch m.softTimeOption.SoftTimeType {
case X常量_SoftTimeTypeAuto:
switch fieldType {
case X常量_LocalTypeDate, X常量_LocalTypeDatetime:
return fmt.Sprintf(`%s IS NULL`, quotedFieldName)
case X常量_LocalTypeInt, X常量_LocalTypeUint, X常量_LocalTypeInt64, X常量_LocalTypeUint64, X常量_LocalTypeBool:
return fmt.Sprintf(`%s=0`, quotedFieldName)
default:
intlog.Errorf(
ctx,
`软删除条件中,无效的字段类型 "%s",字段名 "%s",前缀 "%s"`,
fieldType, fieldName, fieldPrefix,
)
}
case X常量_SoftTimeTypeTime:
return fmt.Sprintf(`%s IS NULL`, quotedFieldName)
default:
return fmt.Sprintf(`%s=0`, quotedFieldName)
}
return ""
}
// GetValueByFieldTypeForCreateOrUpdate 为创建或更新操作创建并返回指定字段类型的值。
// md5:263c89f2a7abf2da
func (m *softTimeMaintainer) GetValueByFieldTypeForCreateOrUpdate(
ctx context.Context, fieldType X类型_LocalType, isDeletedField bool,
) any {
var value any
if isDeletedField {
switch fieldType {
case X常量_LocalTypeDate, X常量_LocalTypeDatetime:
value = nil
default:
value = 0
}
return value
}
switch m.softTimeOption.SoftTimeType {
case X常量_SoftTimeTypeAuto:
switch fieldType {
case X常量_LocalTypeDate, X常量_LocalTypeDatetime:
value = gtime.X创建并按当前时间()
case X常量_LocalTypeInt, X常量_LocalTypeUint, X常量_LocalTypeInt64, X常量_LocalTypeUint64:
value = gtime.X取时间戳秒()
case X常量_LocalTypeBool:
value = 1
default:
intlog.Errorf(
ctx,
`用于软删除数据的字段类型 "%s" 无效`,
fieldType,
)
}
default:
switch fieldType {
case X常量_LocalTypeBool:
value = 1
default:
value = m.createValueBySoftTimeOption(isDeletedField)
}
}
return value
}
func (m *softTimeMaintainer) createValueBySoftTimeOption(isDeletedField bool) any {
var value any
if isDeletedField {
switch m.softTimeOption.SoftTimeType {
case X常量_SoftTimeTypeTime:
value = nil
default:
value = 0
}
return value
}
switch m.softTimeOption.SoftTimeType {
case X常量_SoftTimeTypeTime:
value = gtime.X创建并按当前时间()
case X常量_SoftTimeTypeTimestamp:
value = gtime.X取时间戳秒()
case X常量_SoftTimeTypeTimestampMilli:
value = gtime.X取时间戳毫秒()
case X常量_SoftTimeTypeTimestampMicro:
value = gtime.X取时间戳微秒()
case X常量_SoftTimeTypeTimestampNano:
value = gtime.X取时间戳纳秒()
default:
panic(gerror.X创建错误码并格式化(
gcode.X变量_CodeInternalPanic,
`无法识别的 SoftTimeType: "%d"`, m.softTimeOption.SoftTimeType,
))
}
return value
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。