feat(canvas): 画布同步 - 新增操作事务、预演保存与并发恢复能力

This commit is contained in:
ddcat666
2026-10-11 22:19:20 +08:00
parent 6dedc5973c
commit 5f359f2b1d
63 changed files with 3235 additions and 6193 deletions

View File

@@ -55,6 +55,14 @@ func (r *Repository) WithContext(ctx context.Context) *Repository {
return &Repository{db: r.db.WithContext(ctx)}
}
// Transaction exposes a repository scoped to one database transaction. Domain
// services use it when a canvas mutation and its receipt must commit together.
func (r *Repository) Transaction(fn func(*Repository) error) error {
return r.db.Transaction(func(tx *gorm.DB) error {
return fn(New(tx))
})
}
func (r *Repository) Dialect() string {
return r.db.Dialector.Name()
}
@@ -95,6 +103,26 @@ func (r *Repository) UserStorageUsage(userID string) (UserStorageUsage, error) {
return usage, err
}
// UserStructuredStorageUsage reads only the counters and payload bytes used by
// asset/canvas structured-data quotas. Keeping task and API-log accounting out of
// this path avoids scanning unrelated large history rows on every canvas write.
func (r *Repository) UserStructuredStorageUsage(userID string) (UserStorageUsage, error) {
var usage UserStorageUsage
query := `
SELECT
(SELECT COUNT(*) FROM assets WHERE user_id = ?) AS asset_count,
(SELECT COALESCE(SUM(length(CAST(COALESCE(payload_json, '') AS BLOB))), 0) FROM assets WHERE user_id = ?) AS asset_bytes,
(SELECT COUNT(*) FROM canvas_projects WHERE user_id = ?) AS canvas_count,
(SELECT COALESCE(SUM(length(CAST(COALESCE(payload_json, '') AS BLOB))), 0) FROM canvas_projects WHERE user_id = ?) AS canvas_bytes
`
if r.Dialect() == "postgres" {
query = strings.ReplaceAll(query, "length(CAST(COALESCE(", "octet_length(COALESCE(")
query = strings.ReplaceAll(query, ", '') AS BLOB))", ", ''))")
}
err := r.db.Raw(query, userID, userID, userID, userID).Scan(&usage).Error
return usage, err
}
// Create 是低层兼容入口;业务写路径应优先使用带领域约束的显式方法。
func (r *Repository) Create(value any) error {
return r.db.Create(value).Error