diff --git a/backend/alembic/versions/7571bc149f41_add_bridge_vessel_mapping.py b/backend/alembic/versions/7571bc149f41_add_bridge_vessel_mapping.py new file mode 100644 index 00000000..3452d64a --- /dev/null +++ b/backend/alembic/versions/7571bc149f41_add_bridge_vessel_mapping.py @@ -0,0 +1,44 @@ +"""add bridge vessel mapping + +Revision ID: 7571bc149f41 +Revises: 5801cb8f1af5 +Create Date: 2025-02-06 23:16:09.122359 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.sql import func + + +# revision identifiers, used by Alembic. +revision = '7571bc149f41' +down_revision = '5801cb8f1af5' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.create_table("brg_vessel_mapping", + sa.Column("id", sa.Integer, primary_key=True), + sa.Column("mmsi", sa.String, nullable=True), + sa.Column("imo", sa.Integer, nullable=True), + sa.Column("ship_name", sa.String, nullable=True), + sa.Column( + "vessel_id", + sa.Integer, + sa.ForeignKey("dim_vessel.id"), + nullable=True, + ), + sa.Column( + "created_at", + sa.DateTime(timezone=True), + nullable=False, + server_default=func.now(), + ), + sa.Column("updated_at", sa.DateTime(timezone=True), onupdate=func.now()), + ) + + +def downgrade() -> None: + op.drop_table("brg_vessel_mapping") + pass diff --git a/backend/bloom/container.py b/backend/bloom/container.py index 26efb6cf..b7f4a3e0 100644 --- a/backend/bloom/container.py +++ b/backend/bloom/container.py @@ -6,6 +6,7 @@ from bloom.infra.repositories.repository_raster import RepositoryRaster from bloom.infra.repositories.repository_spire_ais_data import SpireAisDataRepository from bloom.infra.repositories.repository_vessel import VesselRepository +from bloom.infra.repositories.repository_vessel_mapping import VesselMappingRepository from bloom.infra.repositories.repository_vessel_position import VesselPositionRepository from bloom.infra.repositories.repository_segment import SegmentRepository from bloom.infra.repositories.repository_zone import ZoneRepository @@ -38,6 +39,11 @@ class UseCases(containers.DeclarativeContainer): VesselRepository, session_factory=db.provided.session, ) + + vessel_mapping_repository = providers.Factory( + VesselMappingRepository, + session_factory=db.provided.session, + ) alert_repository = providers.Factory( RepositoryAlert, diff --git a/backend/bloom/domain/vessel_mapping.py b/backend/bloom/domain/vessel_mapping.py new file mode 100644 index 00000000..5a958920 --- /dev/null +++ b/backend/bloom/domain/vessel_mapping.py @@ -0,0 +1,14 @@ +from datetime import datetime +from typing import Union, ClassVar + +from pydantic import BaseModel + + +class VesselMapping(BaseModel): + id: Union[int, None] = None + mmsi: Union[int, None] = None + imo: Union[int, None] = None + ship_name: Union[str, None] = None + vessel_id: Union[int, None] = None + created_at: Union[datetime, None] = None + updated_at: Union[datetime, None] = None \ No newline at end of file diff --git a/backend/bloom/infra/database/sql_model.py b/backend/bloom/infra/database/sql_model.py index ec5b24ca..39a75ec7 100644 --- a/backend/bloom/infra/database/sql_model.py +++ b/backend/bloom/infra/database/sql_model.py @@ -44,6 +44,17 @@ class Vessel(Base): ) updated_at = Column("updated_at", DateTime(timezone=True), onupdate=func.now()) +class VesselMapping(Base): + __tablename__ = "brg_vessel_mapping" + id = Column("id", Integer, primary_key=True) + mmsi = Column("mmsi", Integer) + imo = Column("imo", Integer) + ship_name = Column("ship_name", String) + vessel_id = Column("vessel_id", Integer, ForeignKey("dim_vessel.id")) + created_at = Column( + "created_at", DateTime(timezone=True), nullable=False, server_default=func.now(), + ) + updated_at = Column("updated_at", DateTime(timezone=True), onupdate=func.now()) class Alert(Base): __tablename__ = "alert" diff --git a/backend/bloom/infra/repositories/repository_vessel_mapping.py b/backend/bloom/infra/repositories/repository_vessel_mapping.py new file mode 100644 index 00000000..f095f1c2 --- /dev/null +++ b/backend/bloom/infra/repositories/repository_vessel_mapping.py @@ -0,0 +1,53 @@ +from contextlib import AbstractContextManager +from typing import Any, Generator, Union + +from bloom.domain.vessel import Vessel +from bloom.domain.metrics import VesselTimeInZone +from bloom.infra.database import sql_model +from dependency_injector.providers import Callable +from sqlalchemy import func, select, update, insert, and_, asc, desc, literal_column +from sqlalchemy.orm import Session +from bloom.routers.requests import (DatetimeRangeRequest, + OrderByRequest, + OrderByEnum) +from bloom.domain.vessel_mapping import VesselMapping + + +class VesselMappingRepository: + def __init__( + self, + session_factory: Callable, + ) -> Callable[..., AbstractContextManager]: + self.session_factory = session_factory + + + def findBy(self, + session: Session, + mmsi:str=None, + imo:int=None, + ship_name:str=None) -> list[VesselMapping]: + stmt= (select(VesselMapping) + .select_from(sql_model.VesselMapping)) + if mmsi: + stmt=stmt.where(sql_model.VesselMapping.mmsi == mmsi) + if imo: + stmt=stmt.where(sql_model.VesselMapping.imo == imo) + if ship_name: + stmt=stmt.where(sql_model.VesselMapping.ship_name == ship_name) + return session.execute(stmt).scalar() + + def add(self, + session: Session, + mmsi:str=None, + imo:int=None, + ship_name:str=None, + vessel_id:int=None + ): + stmt=insert(sql_model.VesselMapping,[ + { + "mmsi": mmsi, + "imo": imo, + "ship_name": ship_name, + "vessel_id": vessel_id, + }]) + return session.execute(stmt) \ No newline at end of file