gomog/internal/engine/crud_batch2_test.go

250 lines
5.9 KiB
Go

package engine
import (
"testing"
"git.kingecg.top/kingecg/gomog/pkg/types"
)
// TestApplyUpdateSetOnInsert 测试 $setOnInsert 更新操作符
func TestApplyUpdateSetOnInsert(t *testing.T) {
tests := []struct {
name string
data map[string]interface{}
update types.Update
isUpsertInsert bool
expected map[string]interface{}
}{
{
name: "setOnInsert with upsert insert",
data: map[string]interface{}{},
update: types.Update{
Set: map[string]interface{}{
"status": "active",
},
SetOnInsert: map[string]interface{}{
"createdAt": "2024-01-01T00:00:00Z",
"createdBy": "system",
},
},
isUpsertInsert: true,
expected: map[string]interface{}{
"status": "active",
"createdAt": "2024-01-01T00:00:00Z",
"createdBy": "system",
},
},
{
name: "setOnInsert without upsert insert",
data: map[string]interface{}{
"_id": "existing",
"status": "inactive",
},
update: types.Update{
Set: map[string]interface{}{
"status": "active",
},
SetOnInsert: map[string]interface{}{
"createdAt": "2024-01-01T00:00:00Z",
},
},
isUpsertInsert: false,
expected: map[string]interface{}{
"_id": "existing",
"status": "active",
// createdAt should NOT be set
},
},
{
name: "setOnInsert only applies on insert",
data: map[string]interface{}{},
update: types.Update{
SetOnInsert: map[string]interface{}{
"initialValue": 100,
},
},
isUpsertInsert: true,
expected: map[string]interface{}{
"initialValue": 100,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := applyUpdateWithFilters(tt.data, tt.update, tt.isUpsertInsert, nil)
for k, v := range tt.expected {
if result[k] != v {
t.Errorf("applyUpdateWithFilters()[%s] = %v, want %v", k, result[k], v)
}
}
// Verify setOnInsert doesn't appear when not in upsert insert mode
if !tt.isUpsertInsert {
if _, exists := result["createdAt"]; exists {
t.Error("setOnInsert should not apply when isUpsertInsert is false")
}
}
})
}
}
// TestArrayPositionalOperators 测试数组位置操作符
func TestArrayPositionalOperators(t *testing.T) {
tests := []struct {
name string
data map[string]interface{}
field string
value interface{}
filters []map[string]interface{}
expected map[string]interface{}
}{
{
name: "$[] update all elements",
data: map[string]interface{}{
"scores": []interface{}{80, 90, 100},
},
field: "scores.$[]",
value: 95,
expected: map[string]interface{}{
"scores": []interface{}{95, 95, 95},
},
},
{
name: "$[identifier] with filter",
data: map[string]interface{}{
"students": []interface{}{
map[string]interface{}{"name": "Alice", "score": 85},
map[string]interface{}{"name": "Bob", "score": 95},
map[string]interface{}{"name": "Charlie", "score": 75},
},
},
field: "students.$[elem].grade",
value: "A",
filters: []map[string]interface{}{
{
"identifier": "elem",
"score": map[string]interface{}{"$gte": float64(90)},
},
},
expected: map[string]interface{}{
"students": []interface{}{
map[string]interface{}{"name": "Alice", "score": 85},
map[string]interface{}{"name": "Bob", "score": 95, "grade": "A"},
map[string]interface{}{"name": "Charlie", "score": 75},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
updateArrayElement(tt.data, tt.field, tt.value, tt.filters)
for k, v := range tt.expected {
if result := getNestedValue(tt.data, k); !compareEq(result, v) {
t.Errorf("updateArrayElement()[%s] = %v, want %v", k, result, v)
}
}
})
}
}
// TestUpdateArrayAtPath 测试数组路径更新
func TestUpdateArrayAtPath(t *testing.T) {
tests := []struct {
name string
data map[string]interface{}
parts []string
index int
value interface{}
filters []map[string]interface{}
success bool
expected interface{}
}{
{
name: "$[] operator updates all",
data: map[string]interface{}{
"items": []interface{}{1, 2, 3},
},
parts: []string{"items", "$[]"},
index: 1,
value: 100,
success: true,
expected: []interface{}{100, 100, 100},
},
{
name: "$ operator updates first (simplified)",
data: map[string]interface{}{
"tags": []interface{}{"a", "b", "c"},
},
parts: []string{"tags", "$"},
index: 1,
value: "updated",
success: true,
expected: []interface{}{"updated", "b", "c"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := updateArrayAtPath(tt.data, tt.parts, tt.index, tt.value, tt.filters)
if result != tt.success {
t.Errorf("updateArrayAtPath() success = %v, want %v", result, tt.success)
}
if tt.success {
arrField := tt.parts[0]
if arr := getNestedValue(tt.data, arrField); !compareEq(arr, tt.expected) {
t.Errorf("updateArrayAtPath() array = %v, want %v", arr, tt.expected)
}
}
})
}
}
// TestConvertFiltersToMaps 测试过滤器转换
func TestConvertFiltersToMaps(t *testing.T) {
tests := []struct {
name string
filters []types.Filter
expected int
}{
{
name: "nil filters",
filters: nil,
expected: 0,
},
{
name: "empty filters",
filters: []types.Filter{},
expected: 0,
},
{
name: "single filter",
filters: []types.Filter{
{"score": map[string]interface{}{"$gte": 90}},
},
expected: 1,
},
{
name: "multiple filters",
filters: []types.Filter{
{"score": map[string]interface{}{"$gte": 90}},
{"grade": map[string]interface{}{"$eq": "A"}},
},
expected: 2,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := convertFiltersToMaps(tt.filters)
if len(result) != tt.expected {
t.Errorf("convertFiltersToMaps() length = %d, want %d", len(result), tt.expected)
}
})
}
}