Commit d8892b53 authored by George Papathanail's avatar George Papathanail
Browse files

Merge remote-tracking branch 'origin/develop' into feat/qod-v1

parents 4bf7ab8d 32938d0b
Loading
Loading
Loading
Loading
Loading
+2 −2
Changes for .gitignore: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -34,5 +34,5 @@ coverage.xml
# Runtime scratch files
.tmp/

# Editor hook logs
.cursor/hook-logs/
# Cursor editor config
.cursor/
+36 −0
Changes for src/open_exposure_gateway/adapters/database/mappers.py: 36 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ from open_exposure_gateway.adapters.database.sql import (
    CallbackRegistrationRow,
    OperationRow,
    QodSessionRow,
    TrafficInfluenceRow,
)
from open_exposure_gateway.domain.models import (
    AppDeployment,
@@ -20,6 +21,7 @@ from open_exposure_gateway.domain.models import (
    CallbackRegistration,
    Operation,
    QodSession,
    TrafficInfluence,
)
from open_exposure_gateway.domain.models.qod_sessions.models import QodStatusInfo

@@ -186,6 +188,40 @@ class QodSessionMapper:
        )


class TrafficInfluenceMapper:
    @staticmethod
    def to_domain(row: TrafficInfluenceRow) -> TrafficInfluence:
        return TrafficInfluence(
            traffic_influence_id=row.traffic_influence_id,
            operation_id=row.operation_id,
            app_registration_id=row.app_registration_id,
            edge_cloud_zone_id=row.edge_cloud_zone_id,
            edge_cloud_region=row.edge_cloud_region,
            source_port=row.source_port,
            destination_port=row.destination_port,
            destination_protocol=row.destination_protocol,
            state=row.state,
            external_ref=row.external_ref,
            created_at=row.created_at,
            updated_at=row.updated_at,
        )

    @staticmethod
    def to_row(domain: TrafficInfluence) -> TrafficInfluenceRow:
        return TrafficInfluenceRow(
            traffic_influence_id=domain.traffic_influence_id,
            operation_id=domain.operation_id,
            app_registration_id=domain.app_registration_id,
            edge_cloud_zone_id=domain.edge_cloud_zone_id,
            edge_cloud_region=domain.edge_cloud_region,
            source_port=domain.source_port,
            destination_port=domain.destination_port,
            destination_protocol=domain.destination_protocol,
            state=domain.state,
            external_ref=domain.external_ref,
        )


class CallbackRegistrationMapper:
    @staticmethod
    def to_domain(row: CallbackRegistrationRow) -> CallbackRegistration:
+10 −0
Changes for src/open_exposure_gateway/adapters/database/repos/app_instances.py: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -52,6 +52,16 @@ class SqlAppInstanceRepository(AppInstanceRepository):
        row = await self._session.scalar(stmt.limit(1))
        return row is not None

    async def list_ready_ids_in_zone(
        self, app_registration_id: UUID, edge_cloud_zone_id: UUID
    ) -> list[UUID]:
        stmt = select(AppInstanceRow.app_instance_id).where(
            AppInstanceRow.app_registration_id == app_registration_id,
            AppInstanceRow.edge_cloud_zone_id == edge_cloud_zone_id,
            AppInstanceRow.state == AppInstanceState.READY,
        )
        return list(await self._session.scalars(stmt))

    async def save(self, app_instance: AppInstance) -> AppInstance:
        merged = await self._session.merge(AppInstanceMapper.to_row(app_instance))
        await self._session.flush()
+46 −0
Changes for src/open_exposure_gateway/adapters/database/repos/traffic_influences.py: 46 added lines, 0 removed lines.
Original line number Diff line number Diff line
from uuid import UUID

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from open_exposure_gateway.adapters.database.mappers import TrafficInfluenceMapper
from open_exposure_gateway.adapters.database.sql import TrafficInfluenceRow
from open_exposure_gateway.domain.models import TrafficInfluence
from open_exposure_gateway.domain.models.traffic_influences.enums import TrafficInfluenceState
from open_exposure_gateway.ports.database.traffic_influences import TrafficInfluenceRepository


class SqlTrafficInfluenceRepository(TrafficInfluenceRepository):
    def __init__(self, session: AsyncSession) -> None:
        self._session = session

    async def get_by_id(self, traffic_influence_id: UUID) -> TrafficInfluence | None:
        stmt = select(TrafficInfluenceRow).where(
            TrafficInfluenceRow.traffic_influence_id == traffic_influence_id
        )
        row = await self._session.scalar(stmt)
        return TrafficInfluenceMapper.to_domain(row) if row is not None else None

    async def get_by_operation_id(self, operation_id: UUID) -> TrafficInfluence | None:
        stmt = select(TrafficInfluenceRow).where(TrafficInfluenceRow.operation_id == operation_id)
        row = await self._session.scalar(stmt)
        return TrafficInfluenceMapper.to_domain(row) if row is not None else None

    async def list_by_app_registration_id(
        self, app_registration_id: UUID | None
    ) -> list[TrafficInfluence]:
        stmt = select(TrafficInfluenceRow).where(
            TrafficInfluenceRow.state != TrafficInfluenceState.DELETED
        )
        if app_registration_id is not None:
            stmt = stmt.where(TrafficInfluenceRow.app_registration_id == app_registration_id)
        rows = await self._session.scalars(stmt)
        return [TrafficInfluenceMapper.to_domain(row) for row in rows]

    async def save(self, traffic_influence: TrafficInfluence) -> TrafficInfluence:
        merged = await self._session.merge(TrafficInfluenceMapper.to_row(traffic_influence))
        await self._session.flush()
        saved = await self.get_by_id(merged.traffic_influence_id)
        if saved is None:
            raise RuntimeError("Saved traffic influence could not be reloaded")
        return saved
+26 −0
Changes for src/open_exposure_gateway/adapters/database/sql.py: 26 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ from open_exposure_gateway.domain.models.registration.enums import (
    AppRegistrationStatus,
    PackageType,
)
from open_exposure_gateway.domain.models.traffic_influences.enums import TrafficInfluenceState


def get_metadata() -> MetaData:
@@ -248,3 +249,28 @@ class QodSessionRow(AuditedMixin, Base):
    started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    ended_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    status_info: Mapped[str | None] = mapped_column(String(32))


class TrafficInfluenceRow(AuditedMixin, Base):
    __tablename__ = "traffic_influences"
    __table_args__ = (
        Index("idx_traffic_influences_operation", "operation_id"),
        Index("idx_traffic_influences_app_registration", "app_registration_id"),
    )

    traffic_influence_id: Mapped[UUID] = mapped_column(PG_UUID(as_uuid=True), primary_key=True)
    operation_id: Mapped[UUID] = mapped_column(
        ForeignKey("operations.operation_id"), nullable=False
    )
    app_registration_id: Mapped[UUID] = mapped_column(
        ForeignKey("app_registrations.app_registration_id"), nullable=False
    )
    edge_cloud_zone_id: Mapped[UUID | None] = mapped_column(PG_UUID(as_uuid=True))
    edge_cloud_region: Mapped[str | None] = mapped_column(String(256))
    source_port: Mapped[int | None] = mapped_column(Integer)
    destination_port: Mapped[int | None] = mapped_column(Integer)
    destination_protocol: Mapped[str | None] = mapped_column(String(32))
    state: Mapped[TrafficInfluenceState] = mapped_column(
        _enum_type(TrafficInfluenceState), nullable=False
    )
    external_ref: Mapped[str | None] = mapped_column(String(255))
Loading