fix: replace MySQL NOW() with SQLite-compatible datetime('now')
- Set function: use GORM clause.OnConflict for cross-database upsert
- BatchSet function: replace NOW() with datetime('now')
- Add tests for Set and BatchSet (both now 100%/85.7% covered)
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
|
||||||
"github.com/user-management-system/internal/domain"
|
"github.com/user-management-system/internal/domain"
|
||||||
)
|
)
|
||||||
@@ -85,11 +86,15 @@ func NewUserCustomFieldValueRepository(db *gorm.DB) *UserCustomFieldValueReposit
|
|||||||
|
|
||||||
// Set 为用户设置自定义字段值(upsert)
|
// Set 为用户设置自定义字段值(upsert)
|
||||||
func (r *UserCustomFieldValueRepository) Set(ctx context.Context, userID int64, fieldID int64, fieldKey, value string) error {
|
func (r *UserCustomFieldValueRepository) Set(ctx context.Context, userID int64, fieldID int64, fieldKey, value string) error {
|
||||||
return r.db.WithContext(ctx).Exec(`
|
return r.db.WithContext(ctx).Clauses(clause.OnConflict{
|
||||||
INSERT INTO user_custom_field_values (user_id, field_id, field_key, value, created_at, updated_at)
|
Columns: []clause.Column{{Name: "user_id"}, {Name: "field_id"}},
|
||||||
VALUES (?, ?, ?, ?, NOW(), NOW())
|
DoUpdates: clause.AssignmentColumns([]string{"value", "updated_at"}),
|
||||||
ON CONFLICT(user_id, field_id) DO UPDATE SET value = ?, updated_at = NOW()
|
}).Create(&domain.UserCustomFieldValue{
|
||||||
`, userID, fieldID, fieldKey, value, value).Error
|
UserID: userID,
|
||||||
|
FieldID: fieldID,
|
||||||
|
FieldKey: fieldKey,
|
||||||
|
Value: value,
|
||||||
|
}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByUserID 获取用户的所有自定义字段值
|
// GetByUserID 获取用户的所有自定义字段值
|
||||||
@@ -130,6 +135,7 @@ func (r *UserCustomFieldValueRepository) BatchSet(ctx context.Context, userID in
|
|||||||
|
|
||||||
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||||
for fieldKey, value := range values {
|
for fieldKey, value := range values {
|
||||||
|
// 使用 SQLite 兼容的 datetime('now') 而非 MySQL 的 NOW()
|
||||||
if err := tx.Exec(`
|
if err := tx.Exec(`
|
||||||
INSERT INTO user_custom_field_values (user_id, field_id, field_key, value, created_at, updated_at)
|
INSERT INTO user_custom_field_values (user_id, field_id, field_key, value, created_at, updated_at)
|
||||||
VALUES (
|
VALUES (
|
||||||
@@ -137,10 +143,10 @@ func (r *UserCustomFieldValueRepository) BatchSet(ctx context.Context, userID in
|
|||||||
(SELECT id FROM custom_fields WHERE field_key = ? LIMIT 1),
|
(SELECT id FROM custom_fields WHERE field_key = ? LIMIT 1),
|
||||||
?,
|
?,
|
||||||
?,
|
?,
|
||||||
NOW(),
|
datetime('now'),
|
||||||
NOW()
|
datetime('now')
|
||||||
)
|
)
|
||||||
ON CONFLICT(user_id, field_id) DO UPDATE SET value = ?, updated_at = NOW()
|
ON CONFLICT(user_id, field_id) DO UPDATE SET value = ?, updated_at = datetime('now')
|
||||||
`, userID, fieldKey, fieldKey, value, value).Error; err != nil {
|
`, userID, fieldKey, fieldKey, value, value).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,3 +330,87 @@ func TestUserCustomFieldValueRepository_DeleteByUserID(t *testing.T) {
|
|||||||
t.Errorf("用户2的字段值应该保留, got %d", len(values2))
|
t.Errorf("用户2的字段值应该保留, got %d", len(values2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestUserCustomFieldValueRepository_Set 测试设置用户字段值(upsert)
|
||||||
|
func TestUserCustomFieldValueRepository_Set(t *testing.T) {
|
||||||
|
db := setupCustomFieldTestDB(t)
|
||||||
|
fieldRepo := NewCustomFieldRepository(db)
|
||||||
|
valueRepo := NewUserCustomFieldValueRepository(db)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// 先创建字段
|
||||||
|
field := &domain.CustomField{
|
||||||
|
Name: "user-field",
|
||||||
|
FieldKey: "user_field_key",
|
||||||
|
Type: domain.CustomFieldTypeString,
|
||||||
|
}
|
||||||
|
fieldRepo.Create(ctx, field)
|
||||||
|
|
||||||
|
// 设置用户字段值
|
||||||
|
err := valueRepo.Set(ctx, 1, field.ID, field.FieldKey, "test_value")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Set() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证值已设置
|
||||||
|
found, err := valueRepo.GetByUserIDAndFieldKey(ctx, 1, "user_field_key")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetByUserIDAndFieldKey() error = %v", err)
|
||||||
|
}
|
||||||
|
if found.Value != "test_value" {
|
||||||
|
t.Errorf("Value = %v, want test_value", found.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 upsert(更新已存在的值)
|
||||||
|
err = valueRepo.Set(ctx, 1, field.ID, field.FieldKey, "updated_value")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Set() upsert error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
found2, _ := valueRepo.GetByUserIDAndFieldKey(ctx, 1, "user_field_key")
|
||||||
|
if found2.Value != "updated_value" {
|
||||||
|
t.Errorf("Value after upsert = %v, want updated_value", found2.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserCustomFieldValueRepository_BatchSet 测试批量设置用户字段值
|
||||||
|
func TestUserCustomFieldValueRepository_BatchSet(t *testing.T) {
|
||||||
|
db := setupCustomFieldTestDB(t)
|
||||||
|
fieldRepo := NewCustomFieldRepository(db)
|
||||||
|
valueRepo := NewUserCustomFieldValueRepository(db)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// 先创建字段
|
||||||
|
field1 := &domain.CustomField{Name: "batch1", FieldKey: "batch_key1", Type: domain.CustomFieldTypeString}
|
||||||
|
field2 := &domain.CustomField{Name: "batch2", FieldKey: "batch_key2", Type: domain.CustomFieldTypeNumber}
|
||||||
|
fieldRepo.Create(ctx, field1)
|
||||||
|
fieldRepo.Create(ctx, field2)
|
||||||
|
|
||||||
|
values := map[string]string{
|
||||||
|
"batch_key1": "batch_value1",
|
||||||
|
"batch_key2": "batch_value2",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := valueRepo.BatchSet(ctx, 1, values)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BatchSet() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1, _ := valueRepo.GetByUserIDAndFieldKey(ctx, 1, "batch_key1")
|
||||||
|
v2, _ := valueRepo.GetByUserIDAndFieldKey(ctx, 1, "batch_key2")
|
||||||
|
if v1.Value != "batch_value1" || v2.Value != "batch_value2" {
|
||||||
|
t.Error("BatchSet values not set correctly")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUserCustomFieldValueRepository_BatchSet_Empty 测试空批量设置
|
||||||
|
func TestUserCustomFieldValueRepository_BatchSet_Empty(t *testing.T) {
|
||||||
|
db := setupCustomFieldTestDB(t)
|
||||||
|
valueRepo := NewUserCustomFieldValueRepository(db)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
err := valueRepo.BatchSet(ctx, 1, map[string]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BatchSet() error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user