315 lines
6.9 KiB
Go
315 lines
6.9 KiB
Go
package engine
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"git.kingecg.top/kingecg/gomog/pkg/types"
|
|
)
|
|
|
|
// applyUpdate 应用更新操作到文档数据
|
|
func applyUpdate(data map[string]interface{}, update types.Update) map[string]interface{} {
|
|
// 深拷贝原数据
|
|
result := deepCopyMap(data)
|
|
|
|
// 处理 $set
|
|
for field, value := range update.Set {
|
|
setNestedValue(result, field, value)
|
|
}
|
|
|
|
// 处理 $unset
|
|
for field := range update.Unset {
|
|
removeNestedValue(result, field)
|
|
}
|
|
|
|
// 处理 $inc
|
|
for field, value := range update.Inc {
|
|
incNestedValue(result, field, value)
|
|
}
|
|
|
|
// 处理 $mul
|
|
for field, value := range update.Mul {
|
|
mulNestedValue(result, field, value)
|
|
}
|
|
|
|
// 处理 $push
|
|
for field, value := range update.Push {
|
|
pushNestedValue(result, field, value)
|
|
}
|
|
|
|
// 处理 $pull
|
|
for field, value := range update.Pull {
|
|
pullNestedValue(result, field, value)
|
|
}
|
|
|
|
// 处理 $min - 仅当值小于当前值时更新
|
|
for field, value := range update.Min {
|
|
current := getNestedValue(result, field)
|
|
if current == nil || compareNumbers(current, value) > 0 {
|
|
setNestedValue(result, field, value)
|
|
}
|
|
}
|
|
|
|
// 处理 $max - 仅当值大于当前值时更新
|
|
for field, value := range update.Max {
|
|
current := getNestedValue(result, field)
|
|
if current == nil || compareNumbers(current, value) < 0 {
|
|
setNestedValue(result, field, value)
|
|
}
|
|
}
|
|
|
|
// 处理 $rename - 重命名字段
|
|
for oldName, newName := range update.Rename {
|
|
value := getNestedValue(result, oldName)
|
|
if value != nil {
|
|
removeNestedValue(result, oldName)
|
|
setNestedValue(result, newName, value)
|
|
}
|
|
}
|
|
|
|
// 处理 $currentDate - 设置为当前时间
|
|
for field, spec := range update.CurrentDate {
|
|
var currentTime interface{} = time.Now()
|
|
|
|
// 检查是否指定了类型
|
|
if specMap, ok := spec.(map[string]interface{}); ok {
|
|
if typeVal, exists := specMap["$type"]; exists {
|
|
if typeStr, ok := typeVal.(string); ok && typeStr == "timestamp" {
|
|
currentTime = time.Now().UnixMilli()
|
|
}
|
|
}
|
|
}
|
|
|
|
setNestedValue(result, field, currentTime)
|
|
}
|
|
|
|
// 处理 $addToSet - 添加唯一元素到数组
|
|
for field, value := range update.AddToSet {
|
|
current := getNestedValue(result, field)
|
|
var arr []interface{}
|
|
if current != nil {
|
|
if a, ok := current.([]interface{}); ok {
|
|
arr = a
|
|
}
|
|
}
|
|
if arr == nil {
|
|
arr = make([]interface{}, 0)
|
|
}
|
|
|
|
// 检查是否已存在
|
|
exists := false
|
|
for _, item := range arr {
|
|
if compareEq(item, value) {
|
|
exists = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !exists {
|
|
arr = append(arr, value)
|
|
setNestedValue(result, field, arr)
|
|
}
|
|
}
|
|
|
|
// 处理 $pop - 移除数组首/尾元素
|
|
for field, pos := range update.Pop {
|
|
current := getNestedValue(result, field)
|
|
if arr, ok := current.([]interface{}); ok && len(arr) > 0 {
|
|
if pos >= 0 {
|
|
// 移除最后一个元素
|
|
arr = arr[:len(arr)-1]
|
|
} else {
|
|
// 移除第一个元素
|
|
arr = arr[1:]
|
|
}
|
|
setNestedValue(result, field, arr)
|
|
}
|
|
}
|
|
|
|
// 处理 $pullAll - 从数组中移除多个值
|
|
for field, values := range update.PullAll {
|
|
current := getNestedValue(result, field)
|
|
if arr, ok := current.([]interface{}); ok {
|
|
filtered := make([]interface{}, 0, len(arr))
|
|
for _, item := range arr {
|
|
keep := true
|
|
for _, removeVal := range values {
|
|
if compareEq(item, removeVal) {
|
|
keep = false
|
|
break
|
|
}
|
|
}
|
|
if keep {
|
|
filtered = append(filtered, item)
|
|
}
|
|
}
|
|
setNestedValue(result, field, filtered)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// deepCopyMap 深拷贝 map
|
|
func deepCopyMap(m map[string]interface{}) map[string]interface{} {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
|
|
result := make(map[string]interface{})
|
|
for k, v := range m {
|
|
switch val := v.(type) {
|
|
case map[string]interface{}:
|
|
result[k] = deepCopyMap(val)
|
|
case []interface{}:
|
|
result[k] = deepCopySlice(val)
|
|
default:
|
|
result[k] = v
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// deepCopySlice 深拷贝 slice
|
|
func deepCopySlice(s []interface{}) []interface{} {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
|
|
result := make([]interface{}, len(s))
|
|
for i, v := range s {
|
|
switch val := v.(type) {
|
|
case map[string]interface{}:
|
|
result[i] = deepCopyMap(val)
|
|
case []interface{}:
|
|
result[i] = deepCopySlice(val)
|
|
default:
|
|
result[i] = v
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// setNestedValue 设置嵌套字段值
|
|
func setNestedValue(data map[string]interface{}, field string, value interface{}) {
|
|
parts := splitFieldPath(field)
|
|
|
|
current := data
|
|
for i, part := range parts {
|
|
if i == len(parts)-1 {
|
|
// 最后一个部分,设置值
|
|
current[part] = value
|
|
return
|
|
}
|
|
|
|
// 中间部分,确保是 map
|
|
if current[part] == nil {
|
|
current[part] = make(map[string]interface{})
|
|
}
|
|
|
|
if m, ok := current[part].(map[string]interface{}); ok {
|
|
current = m
|
|
} else {
|
|
// 类型不匹配,创建新 map
|
|
newMap := make(map[string]interface{})
|
|
current[part] = newMap
|
|
current = newMap
|
|
}
|
|
}
|
|
}
|
|
|
|
// removeNestedValue 删除嵌套字段
|
|
func removeNestedValue(data map[string]interface{}, field string) {
|
|
parts := splitFieldPath(field)
|
|
|
|
current := data
|
|
for i, part := range parts {
|
|
if i == len(parts)-1 {
|
|
delete(current, part)
|
|
return
|
|
}
|
|
|
|
if m, ok := current[part].(map[string]interface{}); ok {
|
|
current = m
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// incNestedValue 递增嵌套字段值
|
|
func incNestedValue(data map[string]interface{}, field string, increment interface{}) {
|
|
current := getNestedValue(data, field)
|
|
if current == nil {
|
|
setNestedValue(data, field, increment)
|
|
return
|
|
}
|
|
|
|
newValue := toFloat64(current) + toFloat64(increment)
|
|
setNestedValue(data, field, newValue)
|
|
}
|
|
|
|
// mulNestedValue 乘以嵌套字段值
|
|
func mulNestedValue(data map[string]interface{}, field string, multiplier interface{}) {
|
|
current := getNestedValue(data, field)
|
|
if current == nil {
|
|
return
|
|
}
|
|
|
|
newValue := toFloat64(current) * toFloat64(multiplier)
|
|
setNestedValue(data, field, newValue)
|
|
}
|
|
|
|
// pushNestedValue 推入数组
|
|
func pushNestedValue(data map[string]interface{}, field string, value interface{}) {
|
|
current := getNestedValue(data, field)
|
|
|
|
var arr []interface{}
|
|
if current != nil {
|
|
if a, ok := current.([]interface{}); ok {
|
|
arr = a
|
|
}
|
|
}
|
|
|
|
if arr == nil {
|
|
arr = make([]interface{}, 0)
|
|
}
|
|
|
|
arr = append(arr, value)
|
|
setNestedValue(data, field, arr)
|
|
}
|
|
|
|
// pullNestedValue 从数组中移除
|
|
func pullNestedValue(data map[string]interface{}, field string, value interface{}) {
|
|
current := getNestedValue(data, field)
|
|
if current == nil {
|
|
return
|
|
}
|
|
|
|
arr, ok := current.([]interface{})
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
// 过滤掉匹配的值
|
|
filtered := make([]interface{}, 0, len(arr))
|
|
for _, item := range arr {
|
|
if !compareEq(item, value) {
|
|
filtered = append(filtered, item)
|
|
}
|
|
}
|
|
|
|
setNestedValue(data, field, filtered)
|
|
}
|
|
|
|
// splitFieldPath 分割字段路径(支持 "a.b.c" 格式)
|
|
func splitFieldPath(field string) []string {
|
|
// 简单实现,不考虑转义情况
|
|
return strings.Split(field, ".")
|
|
}
|
|
|
|
// generateID 生成唯一 ID
|
|
func generateID() string {
|
|
return time.Now().Format("20060102150405.000000000")
|
|
}
|