"""ReleaseSpatial model to store spatial UPC data for spatial audio products.""" import sqlalchemy from sqlalchemy import BigInteger from sqlalchemy import Column from sqlalchemy import DateTime from sqlalchemy import func from sqlalchemy import Integer from oto import response from product_digital.connectors import mysql from product_digital.constants import error from product_digital.models import product_additional_upc class ReleaseSpatial(mysql.BaseModel): """Contains release spatial UPC data. Used to store spatial UPC when a spatial audio asset is uploaded for a release. """ __tablename__ = 'release_spatial' release_id = Column(Integer, primary_key=True, nullable=False) upc = Column(BigInteger, nullable=False) created_at = Column(DateTime, default=func.now()) updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) def to_dict(self): """Convert the release spatial data to dict.""" return { 'release_id': self.release_id, 'upc': self.upc, } def update(self, **kwargs): """Update object with kwargs data.""" for key, value in kwargs.items(): setattr(self, key, value) @mysql.wrap_db_errors @mysql.db_session_wrap def get_release_spatial(product_id, session): """Get release spatial data for a product. Args: product_id (int): release primary key session (object): SQLAlchemy database session (optional) Returns: Response: release spatial data or not found error. """ release_spatial = session.query(ReleaseSpatial).filter_by( release_id=product_id).first() if not release_spatial: return response.create_not_found_response( error.ERROR_MESSAGE_RELEASE_SPATIAL_NOT_FOUND) return response.Response(message=release_spatial.to_dict()) @mysql.wrap_db_errors @mysql.db_session_wrap def create_release_spatial(spatial_data, session): """Create a new release spatial record. Args: spatial_data (dict): dictionary of spatial data. session (object): SQLAlchemy database session (optional) Returns: Response: release spatial object, or 409 if a record already exists. """ new_spatial = ReleaseSpatial() new_spatial.update(**spatial_data) session.add(new_spatial) try: # Flush the release_spatial insert alone so only its own uniqueness # violation (PK or UNIQUE(upc)) maps to 409. A failure mirroring to # product_additional_upc is a real dual-write error -- let it surface, # not masquerade as 409. session.flush() except sqlalchemy.exc.IntegrityError: session.rollback() return response.create_error_response( code=error.VALIDATION_ERROR, message=error.ERROR_MESSAGE_RELEASE_SPATIAL_ALREADY_EXISTS, status=409) product_additional_upc.mirror_create_or_restore( spatial_data['release_id'], spatial_data['upc'], session) session.commit() return response.Response(message=new_spatial.to_dict()) @mysql.wrap_db_errors @mysql.db_session_wrap def delete_release_spatial(product_id, session): """Delete a release spatial record. Args: product_id (int): release primary key session (object): SQLAlchemy database session (optional) Returns: Response: success or not found error. """ deleted = session.query(ReleaseSpatial).filter_by( release_id=product_id).delete() if not deleted: return response.create_not_found_response( error.ERROR_MESSAGE_RELEASE_SPATIAL_NOT_FOUND) product_additional_upc.mirror_soft_delete(product_id, session) session.commit() return response.Response(message={})