"""SQLAlchemy implementation of EditPlanClipRepository.""" from __future__ import annotations from typing import List, Optional from sqlalchemy.orm import Session from packages.adapters.sqlalchemy_impl.models import EditPlanClipModel from packages.domain.edit_plan_clip import EditPlanClip, EditPlanClipStatus class SQLAlchemyEditPlanClipRepository: """SQLAlchemy 剪辑计划片段仓储""" def __init__(self, session: Session) -> None: self.session = session def list_by_plan( self, plan_id: str, *, status: Optional[EditPlanClipStatus] = None, skip: int = 0, limit: int = 100, ) -> List[EditPlanClip]: """按计划列出片段,按 order 排序""" query = self.session.query(EditPlanClipModel).filter( EditPlanClipModel.plan_id == plan_id, ) if status: query = query.filter(EditPlanClipModel.status == status) query = query.order_by(EditPlanClipModel.order) models = query.offset(skip).limit(limit).all() return [self._model_to_entity(m) for m in models] def get(self, clip_id: str) -> Optional[EditPlanClip]: """根据 ID 获取片段""" model = self.session.query(EditPlanClipModel).filter(EditPlanClipModel.id == clip_id).first() if model is None: return None return self._model_to_entity(model) def create(self, clip: EditPlanClip) -> EditPlanClip: """创建片段""" model = EditPlanClipModel( id=clip.id, plan_id=clip.plan_id, clip_type=clip.clip_type, order=clip.order, template_clip_config_id=clip.template_clip_config_id, asset_id=clip.asset_id, text_content=clip.text_content, start_time=clip.start_time, duration=clip.duration, transition_effect=clip.transition_effect, transition_duration=clip.transition_duration, playback_speed=clip.playback_speed, status=clip.status, config=clip.config, ) self.session.add(model) self.session.commit() self.session.refresh(model) return self._model_to_entity(model) def update(self, clip: EditPlanClip) -> EditPlanClip: """更新片段""" model = self.session.query(EditPlanClipModel).filter(EditPlanClipModel.id == clip.id).first() if model is None: raise ValueError(f"EditPlanClip {clip.id} not found") model.plan_id = clip.plan_id model.clip_type = clip.clip_type model.order = clip.order model.template_clip_config_id = clip.template_clip_config_id model.asset_id = clip.asset_id model.text_content = clip.text_content model.start_time = clip.start_time model.duration = clip.duration model.transition_effect = clip.transition_effect model.transition_duration = clip.transition_duration model.playback_speed = clip.playback_speed model.status = clip.status model.config = clip.config model.updated_at = clip.updated_at self.session.commit() self.session.refresh(model) return self._model_to_entity(model) def delete(self, clip_id: str) -> bool: """删除片段""" model = self.session.query(EditPlanClipModel).filter(EditPlanClipModel.id == clip_id).first() if model is None: return False self.session.delete(model) self.session.commit() return True def delete_by_plan(self, plan_id: str) -> int: """删除计划下所有片段,返回删除数量""" count = self.session.query(EditPlanClipModel).filter(EditPlanClipModel.plan_id == plan_id).delete() self.session.commit() return count def count(self, *, plan_id: Optional[str] = None, status: Optional[EditPlanClipStatus] = None) -> int: """统计片段数量""" query = self.session.query(EditPlanClipModel) if plan_id: query = query.filter(EditPlanClipModel.plan_id == plan_id) if status: query = query.filter(EditPlanClipModel.status == status) return query.count() @staticmethod def _model_to_entity(model: EditPlanClipModel) -> EditPlanClip: return EditPlanClip( id=model.id, plan_id=model.plan_id, clip_type=model.clip_type, order=model.order, template_clip_config_id=model.template_clip_config_id or "", asset_id=model.asset_id or "", text_content=model.text_content or "", start_time=model.start_time or 0.0, duration=model.duration or 0.0, transition_effect=model.transition_effect or "cut", transition_duration=getattr(model, "transition_duration", 0.0) or 0.0, playback_speed=model.playback_speed or 1.0, status=EditPlanClipStatus(model.status) if model.status else EditPlanClipStatus.PENDING, config=model.config or {}, created_at=model.created_at, updated_at=model.updated_at, )