fix(canvas): 画布 - 防止旧内容覆盖并支持版本历史恢复

This commit is contained in:
kinoko
2026-09-17 18:40:42 +08:00
parent b6bae4f957
commit 35ebed3097
69 changed files with 3575 additions and 294 deletions

View File

@@ -135,10 +135,14 @@ func primaryKeyColumn[T any](db *gorm.DB) (string, error) {
if err := statement.Parse(new(T)); err != nil {
return "", err
}
if len(statement.Schema.PrimaryFields) != 1 {
return "", fmt.Errorf("表 %s 必须有且只有一个主键", statement.Schema.Table)
if len(statement.Schema.PrimaryFields) == 0 {
return "", fmt.Errorf("表 %s 必须有主键", statement.Schema.Table)
}
return statement.Schema.PrimaryFields[0].DBName, nil
columns := make([]string, 0, len(statement.Schema.PrimaryFields))
for _, field := range statement.Schema.PrimaryFields {
columns = append(columns, field.DBName)
}
return strings.Join(columns, ", "), nil
}
var timeType = reflect.TypeOf(time.Time{})
@@ -279,6 +283,8 @@ func migrations() []tableMigration {
migrateTable[model.WorkflowStepTask]("workflow_step_tasks"),
migrateTable[model.ProductionTaskLink]("production_task_links"),
migrateTable[model.CanvasProject]("canvas_projects"),
migrateTable[model.CanvasSnapshot]("canvas_snapshots"),
migrateTable[model.CanvasSnapshotResource]("canvas_snapshot_resources"),
migrateTable[model.CanvasShare]("canvas_shares"),
migrateTable[model.PromptTemplate]("prompt_templates"),
migrateTable[model.UserPromptCustomization]("user_prompt_customizations"),

View File

@@ -5,7 +5,9 @@ import (
"testing"
"infinite-canvas/backend/internal/database"
"infinite-canvas/backend/internal/model"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
@@ -34,3 +36,30 @@ func TestMigrationListCoversSchemaModels(t *testing.T) {
}
}
}
func TestCanvasHistoryCompositeKeyMigration(t *testing.T) {
source, err := database.Open(database.Config{Driver: "sqlite", DSN: "file:history-migration-source?mode=memory&cache=shared"})
if err != nil {
t.Fatal(err)
}
target, err := database.Open(database.Config{Driver: "sqlite", DSN: "file:history-migration-target?mode=memory&cache=shared"})
if err != nil {
t.Fatal(err)
}
for _, db := range []*gorm.DB{source, target} {
if err := db.AutoMigrate(&model.Resource{}, &model.CanvasSnapshotResource{}); err != nil {
t.Fatal(err)
}
if err := db.Create(&model.Resource{ID: "resource"}).Error; err != nil {
t.Fatal(err)
}
}
refs := []model.CanvasSnapshotResource{{SnapshotID: "b", ResourceID: "resource"}, {SnapshotID: "a", ResourceID: "resource"}}
if err := source.Create(&refs).Error; err != nil {
t.Fatal(err)
}
count, err := migrateTable[model.CanvasSnapshotResource]("canvas_snapshot_resources").run(source, target, true)
if err != nil || count != 2 {
t.Fatalf("history refs not copied/verified: %d %v", count, err)
}
}