Files
ttstd-infinite-canvas/backend/internal/repository/repository_projects.go

576 lines
25 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 短剧项目、分集单元、项目素材库与画布-单元关联。
package repository
import (
"fmt"
"sort"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"infinite-canvas/backend/internal/model"
)
func (r *Repository) Projects(userID string) ([]model.Project, error) {
var projects []model.Project
err := r.db.Where("user_id = ?", userID).Order("updated_at desc").Find(&projects).Error
return projects, err
}
func (r *Repository) ProjectsPage(userID string, page int, pageSize int) ([]model.Project, int64, error) {
var projects []model.Project
var total int64
query := r.db.Model(&model.Project{}).Where("user_id = ?", userID)
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
if err := query.Order("updated_at desc").Offset((page - 1) * pageSize).Limit(pageSize).Find(&projects).Error; err != nil {
return nil, 0, err
}
return projects, total, nil
}
func (r *Repository) ProjectForUser(userID string, id string) (*model.Project, error) {
var project model.Project
if err := r.db.First(&project, "id = ? AND user_id = ?", id, userID).Error; err != nil {
return nil, err
}
return &project, nil
}
func (r *Repository) CreateProject(project *model.Project) error {
return r.db.Create(project).Error
}
func (r *Repository) UpdateProject(project *model.Project) error {
return r.db.Model(&model.Project{}).Where("id = ? AND user_id = ?", project.ID, project.UserID).Updates(map[string]any{
"name": project.Name, "type": project.Type, "aspect_ratio": project.AspectRatio, "source_type": project.SourceType,
"description": project.Description, "cover_resource_id": project.CoverResourceID,
"style_preset_id": project.StylePresetID, "style_profile_json": project.StyleProfileJSON,
"default_image_model": project.DefaultImageModel, "default_video_model": project.DefaultVideoModel,
"status": project.Status, "revision": project.Revision, "updated_at": project.UpdatedAt,
}).Error
}
func (r *Repository) DeleteProject(userID string, id string, canvasUpdates []model.CanvasProject) error {
return r.db.Transaction(func(tx *gorm.DB) error {
var canvasIDs []string
if err := tx.Model(&model.CanvasProject{}).
Where("user_id = ? AND project_id = ?", userID, id).
Pluck("id", &canvasIDs).Error; err != nil {
return err
}
projectScopeIDs := append([]string{id}, canvasIDs...)
var activeTaskCount int64
if err := tx.Model(&model.Task{}).
Where("user_id = ? AND project_id IN ? AND status IN ?", userID, projectScopeIDs, []model.TaskStatus{model.TaskStatusQueued, model.TaskStatusRunning}).
Count(&activeTaskCount).Error; err != nil {
return err
}
if activeTaskCount > 0 {
return ErrProjectHasActiveTasks
}
if err := tx.Where("user_id = ? AND project_id = ?", userID, id).Delete(&model.CanvasShare{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.CanvasUnitLink{}).Error; err != nil {
return err
}
for _, canvas := range canvasUpdates {
result := tx.Model(&model.CanvasProject{}).
Where("id = ? AND user_id = ? AND project_id = ? AND revision = ?", canvas.ID, userID, id, canvas.Revision).
Updates(map[string]any{"project_id": "", "payload_json": canvas.PayloadJSON, "updated_at": canvas.UpdatedAt, "revision": canvas.Revision + 1})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
}
var remainingCanvasCount int64
if err := tx.Model(&model.CanvasProject{}).Where("user_id = ? AND project_id = ?", userID, id).Count(&remainingCanvasCount).Error; err != nil {
return err
}
if remainingCanvasCount != 0 {
return fmt.Errorf("项目删除时仍有 %d 个画布关联未处理", remainingCanvasCount)
}
shotIDs := tx.Model(&model.Shot{}).Select("id").Where("project_id = ?", id)
if err := tx.Where("project_id = ?", id).Delete(&model.ProductionTaskLink{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.ShotArtifact{}).Error; err != nil {
return err
}
if err := tx.Where("shot_id IN (?)", shotIDs).Delete(&model.ShotRevision{}).Error; err != nil {
return err
}
if err := tx.Where("shot_id IN (?)", shotIDs).Delete(&model.ShotAssetReference{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.Shot{}).Error; err != nil {
return err
}
instanceIDs := tx.Model(&model.WorkflowInstance{}).Select("id").Where("project_id = ?", id)
stepIDs := tx.Model(&model.WorkflowStepInstance{}).Select("id").Where("workflow_instance_id IN (?)", instanceIDs)
if err := tx.Where("workflow_step_id IN (?)", stepIDs).Delete(&model.WorkflowStepTask{}).Error; err != nil {
return err
}
if err := tx.Where("workflow_instance_id IN (?)", instanceIDs).Delete(&model.WorkflowStepInstance{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.WorkflowInstance{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.ProjectAssetLink{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.ProjectAssetFolder{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.ProjectAssetCandidate{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ?", id).Delete(&model.ProjectUnit{}).Error; err != nil {
return err
}
if err := tx.Model(&model.Task{}).Where("user_id = ? AND project_id = ?", userID, id).Update("project_id", "").Error; err != nil {
return err
}
return tx.Delete(&model.Project{}, "id = ? AND user_id = ?", id, userID).Error
})
}
func (r *Repository) BumpProjectRevision(projectID string) error {
return r.db.Model(&model.Project{}).Where("id = ?", projectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
}
func (r *Repository) ProjectUnits(projectID string) ([]model.ProjectUnit, error) {
var units []model.ProjectUnit
err := r.db.Where("project_id = ?", projectID).Order("position asc, created_at asc").Find(&units).Error
return units, err
}
func (r *Repository) ProjectUnitSummaries(projectID string) ([]model.ProjectUnit, error) {
var units []model.ProjectUnit
err := r.db.Select("id", "project_id", "kind", "title", "word_count", "status", "position", "created_at", "updated_at").Where("project_id = ?", projectID).Order("position asc, created_at asc").Find(&units).Error
return units, err
}
func (r *Repository) ProjectAssetCount(projectID string) (int64, error) {
var count int64
err := r.db.Model(&model.ProjectAssetLink{}).Where("project_id = ?", projectID).Count(&count).Error
return count, err
}
func (r *Repository) CreateProjectUnit(unit *model.ProjectUnit) error {
return r.db.Create(unit).Error
}
func (r *Repository) ImportProjectUnits(projectID string, units []model.ProjectUnit) error {
return r.db.Transaction(func(tx *gorm.DB) error {
// 分批写入仍处于同一事务,避免两千章导入超过 SQLite/PostgreSQL 单语句参数上限。
if err := tx.CreateInBatches(&units, 100).Error; err != nil {
return err
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
})
}
func (r *Repository) ReorderProjectUnits(projectID string, unitIDs []string) error {
return r.db.Transaction(func(tx *gorm.DB) error {
now := time.Now()
for position, unitID := range unitIDs {
result := tx.Model(&model.ProjectUnit{}).Where("id = ? AND project_id = ?", unitID, projectID).Updates(map[string]any{"position": position, "updated_at": now})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": now}).Error
})
}
func (r *Repository) ProjectUnit(projectID string, id string) (*model.ProjectUnit, error) {
var unit model.ProjectUnit
if err := r.db.First(&unit, "id = ? AND project_id = ?", id, projectID).Error; err != nil {
return nil, err
}
return &unit, nil
}
func (r *Repository) UpdateProjectUnit(unit *model.ProjectUnit, invalidateWorkflow bool) error {
return r.db.Transaction(func(tx *gorm.DB) error {
result := tx.Model(&model.ProjectUnit{}).Where("id = ? AND project_id = ?", unit.ID, unit.ProjectID).Updates(map[string]any{
"parent_id": unit.ParentID, "title": unit.Title, "source_text": unit.SourceText, "word_count": unit.WordCount, "status": unit.Status, "position": unit.Position, "updated_at": unit.UpdatedAt,
})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
if invalidateWorkflow {
if err := tx.Model(&model.ShotArtifact{}).Where("project_id = ? AND unit_id = ? AND status NOT IN ?", unit.ProjectID, unit.ID, []string{"failed", "stale"}).Updates(map[string]any{"status": "stale", "selected": false, "updated_at": unit.UpdatedAt}).Error; err != nil {
return err
}
if err := invalidateUnitWorkflowTx(tx, unit.ProjectID, unit.ID, "story", unit.UpdatedAt); err != nil {
return err
}
}
return tx.Model(&model.Project{}).Where("id = ?", unit.ProjectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": unit.UpdatedAt}).Error
})
}
func (r *Repository) DeleteProjectUnit(projectID string, id string) error {
return r.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("project_id = ? AND unit_id = ?", projectID, id).Delete(&model.CanvasUnitLink{}).Error; err != nil {
return err
}
shotIDs := tx.Model(&model.Shot{}).Select("id").Where("project_id = ? AND unit_id = ?", projectID, id)
if err := tx.Where("project_id = ? AND unit_id = ?", projectID, id).Delete(&model.ProductionTaskLink{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ? AND unit_id = ?", projectID, id).Delete(&model.ShotArtifact{}).Error; err != nil {
return err
}
if err := tx.Where("shot_id IN (?)", shotIDs).Delete(&model.ShotRevision{}).Error; err != nil {
return err
}
if err := tx.Where("shot_id IN (?)", shotIDs).Delete(&model.ShotAssetReference{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ? AND unit_id = ?", projectID, id).Delete(&model.Shot{}).Error; err != nil {
return err
}
instanceIDs := tx.Model(&model.WorkflowInstance{}).Select("id").Where("project_id = ? AND unit_id = ?", projectID, id)
stepIDs := tx.Model(&model.WorkflowStepInstance{}).Select("id").Where("workflow_instance_id IN (?)", instanceIDs)
if err := tx.Where("workflow_step_id IN (?)", stepIDs).Delete(&model.WorkflowStepTask{}).Error; err != nil {
return err
}
if err := tx.Where("workflow_instance_id IN (?)", instanceIDs).Delete(&model.WorkflowStepInstance{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ? AND unit_id = ?", projectID, id).Delete(&model.WorkflowInstance{}).Error; err != nil {
return err
}
if err := tx.Where("project_id = ? AND unit_id = ?", projectID, id).Delete(&model.ProjectAssetCandidate{}).Error; err != nil {
return err
}
result := tx.Delete(&model.ProjectUnit{}, "id = ? AND project_id = ?", id, projectID)
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
})
}
func (r *Repository) CanvasUnitLink(projectID string, canvasID string, unitID string) (*model.CanvasUnitLink, error) {
var link model.CanvasUnitLink
if err := r.db.First(&link, "project_id = ? AND canvas_id = ? AND unit_id = ?", projectID, canvasID, unitID).Error; err != nil {
return nil, err
}
return &link, nil
}
func (r *Repository) UpsertCanvasUnitLink(link *model.CanvasUnitLink) error {
result := r.db.Model(&model.CanvasUnitLink{}).Where("project_id = ? AND canvas_id = ? AND unit_id = ?", link.ProjectID, link.CanvasID, link.UnitID).Updates(map[string]any{"role": link.Role})
if result.Error != nil || result.RowsAffected > 0 {
return result.Error
}
return r.db.Create(link).Error
}
func (r *Repository) ProjectCanvasSummaries(userID string, projectID string) ([]model.CanvasProject, error) {
var canvases []model.CanvasProject
err := r.db.Select("id", "user_id", "project_id", "title", "revision", "created_at", "updated_at").Where("user_id = ? AND project_id = ?", userID, projectID).Order("updated_at desc").Find(&canvases).Error
return canvases, err
}
func (r *Repository) ProjectCanvasDocuments(userID string, projectID string) ([]model.CanvasProject, error) {
var canvases []model.CanvasProject
err := r.db.Select("id", "title", "payload_json", "revision").Where("user_id = ? AND project_id = ?", userID, projectID).Find(&canvases).Error
return canvases, err
}
func (r *Repository) ProjectCanvasUnitLinks(projectID string) ([]model.CanvasUnitLink, error) {
var links []model.CanvasUnitLink
err := r.db.Where("project_id = ?", projectID).Order("created_at asc").Find(&links).Error
return links, err
}
func (r *Repository) DeleteCanvasUnitLink(projectID string, canvasID string, unitID string) error {
return r.db.Transaction(func(tx *gorm.DB) error {
result := tx.Delete(&model.CanvasUnitLink{}, "project_id = ? AND canvas_id = ? AND unit_id = ?", projectID, canvasID, unitID)
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
})
}
func (r *Repository) AssignCanvasToProject(userID string, canvasID string, projectID string) error {
return r.db.Model(&model.CanvasProject{}).Where("id = ? AND user_id = ?", canvasID, userID).Updates(map[string]any{"project_id": projectID, "revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
}
func (r *Repository) UnassignCanvasFromProject(userID string, projectID string, canvasID string, payloadJSON string, updatedAt time.Time, revision int64) error {
return r.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("project_id = ? AND canvas_id = ?", projectID, canvasID).Delete(&model.CanvasUnitLink{}).Error; err != nil {
return err
}
result := tx.Model(&model.CanvasProject{}).Where("id = ? AND user_id = ? AND project_id = ? AND revision = ?", canvasID, userID, projectID, revision).Updates(map[string]any{
"project_id": "", "payload_json": payloadJSON, "updated_at": updatedAt, "revision": revision + 1,
})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": updatedAt}).Error
})
}
func (r *Repository) ProjectAssets(userID string, projectID string) ([]model.Asset, error) {
var assets []model.Asset
err := r.db.Table("assets").Select("assets.*").Joins("JOIN project_asset_links ON project_asset_links.asset_id = assets.id").Where("assets.user_id = ? AND project_asset_links.project_id = ?", userID, projectID).Order("assets.updated_at desc").Scan(&assets).Error
return assets, err
}
func (r *Repository) ProjectAssetLinks(projectID string) ([]model.ProjectAssetLink, error) {
var links []model.ProjectAssetLink
err := r.db.Where("project_id = ?", projectID).Order("folder_id asc, position asc, created_at asc").Find(&links).Error
return links, err
}
func (r *Repository) ProjectAssetLink(projectID string, assetID string) (*model.ProjectAssetLink, error) {
var link model.ProjectAssetLink
if err := r.db.First(&link, "project_id = ? AND asset_id = ?", projectID, assetID).Error; err != nil {
return nil, err
}
return &link, nil
}
func (r *Repository) NextProjectAssetPosition(projectID string, folderID string) (int, error) {
var result struct{ Maximum int }
err := r.db.Model(&model.ProjectAssetLink{}).
Select("COALESCE(MAX(position), -1) AS maximum").
Where("project_id = ? AND folder_id = ?", projectID, folderID).
Scan(&result).Error
return result.Maximum + 1, err
}
func (r *Repository) MoveProjectAsset(projectID string, assetID string, folderID string, position int) error {
return r.db.Transaction(func(tx *gorm.DB) error {
result := tx.Model(&model.ProjectAssetLink{}).
Where("project_id = ? AND asset_id = ?", projectID, assetID).
Updates(map[string]any{"folder_id": folderID, "position": position})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).
Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
})
}
func (r *Repository) ProjectAssetFolders(projectID string) ([]model.ProjectAssetFolder, error) {
var folders []model.ProjectAssetFolder
err := r.db.Where("project_id = ?", projectID).Order("parent_id asc, position asc, created_at asc").Find(&folders).Error
return folders, err
}
func (r *Repository) ProjectAssetFolder(projectID string, folderID string) (*model.ProjectAssetFolder, error) {
var folder model.ProjectAssetFolder
if err := r.db.First(&folder, "id = ? AND project_id = ?", folderID, projectID).Error; err != nil {
return nil, err
}
return &folder, nil
}
func (r *Repository) CreateProjectAssetFolder(folder *model.ProjectAssetFolder) error {
return r.db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(folder).Error; err != nil {
return err
}
return tx.Model(&model.Project{}).Where("id = ?", folder.ProjectID).
Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": folder.UpdatedAt}).Error
})
}
func (r *Repository) UpdateProjectAssetFolder(folder *model.ProjectAssetFolder) error {
return r.db.Transaction(func(tx *gorm.DB) error {
result := tx.Model(&model.ProjectAssetFolder{}).
Where("id = ? AND project_id = ?", folder.ID, folder.ProjectID).
Updates(map[string]any{"parent_id": folder.ParentID, "name": folder.Name, "name_key": folder.NameKey, "style": folder.Style, "theme": folder.Theme, "position": folder.Position, "updated_at": folder.UpdatedAt})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", folder.ProjectID).
Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": folder.UpdatedAt}).Error
})
}
func (r *Repository) DeleteProjectAssetFolder(projectID string, folderID string) error {
return r.db.Transaction(func(tx *gorm.DB) error {
var childCount int64
if err := tx.Model(&model.ProjectAssetFolder{}).Where("project_id = ? AND parent_id = ?", projectID, folderID).Count(&childCount).Error; err != nil {
return err
}
var assetCount int64
if err := tx.Model(&model.ProjectAssetLink{}).Where("project_id = ? AND folder_id = ?", projectID, folderID).Count(&assetCount).Error; err != nil {
return err
}
if childCount > 0 || assetCount > 0 {
return ErrProjectAssetFolderNotEmpty
}
result := tx.Delete(&model.ProjectAssetFolder{}, "id = ? AND project_id = ?", folderID, projectID)
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", projectID).
Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
})
}
// LinkProjectAsset 将首版本、素材领域字段、项目引用和修订号原子提交,避免产生半关联资产。
// 资产首次入库也在此事务内完成(service 层只做内存构造,不预落库),
// 事务失败时资产一并回滚,不再留下“有资产无链接”的孤儿资产。
func (r *Repository) LinkProjectAsset(asset *model.Asset, version *model.AssetVersion, link *model.ProjectAssetLink) (bool, error) {
createdLink := false
err := r.db.Transaction(func(tx *gorm.DB) error {
// 资产可能尚未落库(首次导入)或已存在(并发/重试),冲突幂等跳过。
assetCreated := tx.Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "id"}}, DoNothing: true}).Create(asset)
if assetCreated.Error != nil {
return assetCreated.Error
}
created := tx.Clauses(clause.OnConflict{Columns: []clause.Column{{Name: "project_id"}, {Name: "asset_id"}}, DoNothing: true}).Create(link)
if created.Error != nil {
return created.Error
}
if created.RowsAffected == 0 {
return nil
}
createdLink = true
if version != nil {
if err := tx.Create(version).Error; err != nil {
return err
}
}
result := tx.Model(&model.Asset{}).Where("id = ? AND user_id = ?", asset.ID, asset.UserID).Updates(map[string]any{
"category": asset.Category, "status": asset.Status, "primary_version_id": asset.PrimaryVersionID, "updated_at": asset.UpdatedAt,
})
if result.Error != nil {
return result.Error
}
if result.RowsAffected != 1 {
return gorm.ErrRecordNotFound
}
return tx.Model(&model.Project{}).Where("id = ?", link.ProjectID).Updates(map[string]any{"revision": gorm.Expr("revision + 1"), "updated_at": time.Now()}).Error
})
return createdLink, err
}
func (r *Repository) DeleteProjectAssetLink(projectID string, assetID string) error {
return r.db.Delete(&model.ProjectAssetLink{}, "project_id = ? AND asset_id = ?", projectID, assetID).Error
}
func (r *Repository) ProjectAssetShotReferenceCount(projectID string, assetID string) (int64, error) {
var count int64
err := r.db.Table("shot_asset_references").
Joins("JOIN shots ON shots.id = shot_asset_references.shot_id").
Joins("JOIN asset_versions ON asset_versions.id = shot_asset_references.asset_version_id").
Where("shots.project_id = ? AND asset_versions.asset_id = ?", projectID, assetID).
Count(&count).Error
return count, err
}
func (r *Repository) ProjectAssetLinked(projectID string, assetID string) (bool, error) {
var count int64
err := r.db.Model(&model.ProjectAssetLink{}).Where("project_id = ? AND asset_id = ?", projectID, assetID).Count(&count).Error
return count > 0, err
}
func (r *Repository) AssetReferenceCount(assetID string) (int64, error) {
var projectLinks int64
if err := r.db.Model(&model.ProjectAssetLink{}).Where("asset_id = ?", assetID).Count(&projectLinks).Error; err != nil {
return 0, err
}
var shotLinks int64
err := r.db.Table("shot_asset_references").Joins("JOIN asset_versions ON asset_versions.id = shot_asset_references.asset_version_id").Where("asset_versions.asset_id = ?", assetID).Count(&shotLinks).Error
return projectLinks + shotLinks, err
}
func (r *Repository) UpdateAssetDomain(asset *model.Asset) error {
return r.db.Model(&model.Asset{}).Where("id = ? AND user_id = ?", asset.ID, asset.UserID).Updates(map[string]any{"category": asset.Category, "status": asset.Status, "primary_version_id": asset.PrimaryVersionID, "updated_at": asset.UpdatedAt}).Error
}
func (r *Repository) AssetVersions(assetID string) ([]model.AssetVersion, error) {
var versions []model.AssetVersion
err := r.db.Where("asset_id = ?", assetID).Order("version desc").Find(&versions).Error
return versions, err
}
func (r *Repository) ProjectAssetUsageRoles(projectID string, assetID string) ([]string, error) {
var shotRoles []string
if err := r.db.Table("shot_asset_references").
Distinct("shot_asset_references.role").
Joins("JOIN shots ON shots.id = shot_asset_references.shot_id").
Joins("JOIN asset_versions ON asset_versions.id = shot_asset_references.asset_version_id").
Where("shots.project_id = ? AND asset_versions.asset_id = ?", projectID, assetID).
Order("shot_asset_references.role asc").
Pluck("shot_asset_references.role", &shotRoles).Error; err != nil {
return nil, err
}
var representationRoles []string
if err := r.db.Table("asset_representations").
Distinct("asset_representations.role").
Joins("JOIN asset_versions ON asset_versions.id = asset_representations.asset_version_id").
Joins("JOIN project_asset_links ON project_asset_links.asset_id = asset_versions.asset_id").
Where("project_asset_links.project_id = ? AND asset_versions.asset_id = ?", projectID, assetID).
Pluck("asset_representations.role", &representationRoles).Error; err != nil {
return nil, err
}
seen := make(map[string]struct{}, len(shotRoles)+len(representationRoles))
for _, role := range append(shotRoles, representationRoles...) {
if role != "" {
seen[role] = struct{}{}
}
}
roles := make([]string, 0, len(seen))
for role := range seen {
roles = append(roles, role)
}
sort.Strings(roles)
return roles, nil
}
func (r *Repository) AssetVersionForProject(projectID string, versionID string) (*model.AssetVersion, error) {
var version model.AssetVersion
err := r.db.Table("asset_versions").Select("asset_versions.*").Joins("JOIN project_asset_links ON project_asset_links.asset_id = asset_versions.asset_id").Where("project_asset_links.project_id = ? AND asset_versions.id = ?", projectID, versionID).First(&version).Error
if err != nil {
return nil, err
}
return &version, nil
}
func (r *Repository) CreateAssetVersion(version *model.AssetVersion) error {
return r.db.Create(version).Error
}