"""Asset type model.""" from typing import Any from sqlalchemy import ( TIMESTAMP, Column, Enum, Float, Integer, String, delete, func, select, text, ) from sqlalchemy.dialects.mysql import INTEGER from sqlalchemy.orm import Mapped, Session, mapped_column, validates from video.connectors import mysql class VideoAsset(mysql.BaseModel): """Video Asset.""" __tablename__ = "video_asset" primary_key = Column( "id", Integer, nullable=False, primary_key=True, autoincrement=True, ) product_id = Column( "product_id", INTEGER(unsigned=True), nullable=False, ) tuid = Column("tuid", INTEGER(unsigned=True), nullable=False, default=0) asset_type: Mapped[str] = mapped_column( Enum( "video_master", "H264_SD", "H264_HD", "video_image_S2", "video_image_S5", "video_image_S10", "video_image_S11", ), name="asset_type", nullable=False, ) asset_path = Column("asset_path", String(255)) last_updated = Column( TIMESTAMP, nullable=False, server_default=text("CURRENT_TIMESTAMP") ) duration = Column( "duration", Float(10), nullable=True, default=0.000, ) @validates("asset_path", "product_id", "asset_type") def validate_asset_data(self, key: str, value: Any) -> Any: """Ensure required fields are not blank. Returns: The validated value unchanged. Raises: ValueError: if the value is blank. """ if not value: raise ValueError(f"{key} should not be blank.") return value def to_dict(self) -> dict[str, Any]: """Get a dict representation.""" return { "id": self.primary_key, "product_id": self.product_id, "asset_type": self.asset_type, "asset_path": self.asset_path, "tuid": self.tuid, "last_updated": self.last_updated.strftime("%Y-%m-%d %H:%M:%S"), "duration": self.duration, } def _get_by_product_id_and_asset_type( product_id: int, asset_type: str, session: Session, tuid: int | None = None, ) -> VideoAsset | None: filters = [VideoAsset.product_id == product_id, VideoAsset.asset_type == asset_type] if tuid: filters.append(VideoAsset.tuid == tuid) return session.execute(select(VideoAsset).where(*filters)).scalar_one_or_none() def _get_by_product_id(product_id: int, session: Session) -> list[VideoAsset]: return list( session.execute(select(VideoAsset).where(VideoAsset.product_id == product_id)) .scalars() .all() ) def get_by_product_id( product_id: int, session: Session | None = None, ) -> list[dict[str, Any]]: """Get video assets by product_id. Returns: list: video asset dicts, or [] if none found. """ if session is None: with mysql.db_session() as s: return get_by_product_id(product_id, session=s) video_assets = _get_by_product_id(product_id, session) if not video_assets: return [] return [video_asset.to_dict() for video_asset in video_assets] def get_by_product_id_and_asset_type( product_id: int, asset_type: str, session: Session | None = None, ) -> dict[str, Any]: """Get video asset by product_id and asset_type. Returns: dict: video asset dict, or {} if not found. """ if session is None: with mysql.db_session() as s: return get_by_product_id_and_asset_type(product_id, asset_type, session=s) video_asset = _get_by_product_id_and_asset_type(product_id, asset_type, session) if not video_asset: return {} return video_asset.to_dict() def upsert( new_video_asset: dict[str, Any], session: Session | None = None, ) -> dict[str, Any]: """Create or update a video_asset.""" if session is None: with mysql.db_session() as s: return upsert(new_video_asset, session=s) tuid = int(new_video_asset["tuid"]) if new_video_asset.get("tuid") else None video_asset = _get_by_product_id_and_asset_type( new_video_asset["product_id"], new_video_asset["asset_type"], session, tuid ) if video_asset: return update(video_asset, new_video_asset, session) return create(new_video_asset, session=session) def update( video_asset: VideoAsset, new_video_asset: dict[str, Any], session: Session, ) -> dict[str, Any]: """Update video asset.""" video_asset.last_updated = func.now() # type: ignore[assignment] sanitized = sanitize_input(new_video_asset) for field_name, value in sanitized.items(): setattr(video_asset, field_name, value) session.add(video_asset) session.flush() return video_asset.to_dict() def create(video_asset: dict[str, Any], session: Session) -> dict[str, Any]: """Create video asset.""" sanitized = sanitize_input(video_asset) video_asset_model = VideoAsset(**sanitized) session.add(video_asset_model) session.flush() return video_asset_model.to_dict() def delete_asset(product_id: int, session: Session | None = None) -> None: """Delete video assets for a product.""" if session is None: with mysql.db_session() as s: return delete_asset(product_id, session=s) session.execute(delete(VideoAsset).where(VideoAsset.product_id == product_id)) def sanitize_input(video_asset: dict[str, Any]) -> dict[str, Any]: """Drop keys that shouldn't be monkeyed with.""" valid_columns = VideoAsset.__table__.columns.keys() sanitized_keys = video_asset.keys() & valid_columns sanitized_dict = {k: video_asset[k] for k in sanitized_keys} sanitized_dict.pop("primary_key", None) return sanitized_dict def bulk_upsert_video_assets( new_video_assets: list[dict[str, Any]], session: Session | None = None, ) -> list[dict[str, Any]]: """Bulk Upsert video assets for products.""" if session is None: with mysql.db_session() as s: return bulk_upsert_video_assets(new_video_assets, session=s) return [ upsert(new_video_asset, session=session) for new_video_asset in new_video_assets ]