789 lines
44 KiB
Python
789 lines
44 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from geoalchemy2 import Geometry
|
|
from sqlalchemy import CheckConstraint, DateTime, ForeignKey, Float, Index, JSON, String, Text, UniqueConstraint, func, text
|
|
from sqlalchemy.sql.sqltypes import Integer
|
|
from sqlalchemy.dialects.postgresql import UUID
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.db.base import Base
|
|
|
|
|
|
SOURCE_CLASSIFICATIONS = (
|
|
"authoritative",
|
|
"corroborative",
|
|
"contextual",
|
|
"derived",
|
|
"experimental",
|
|
)
|
|
SOURCE_FRESHNESS_STATUSES = (
|
|
"unknown",
|
|
"current",
|
|
"due",
|
|
"stale",
|
|
"not_applicable",
|
|
"review_required",
|
|
)
|
|
SOURCE_INGEST_STATUSES = (
|
|
"registered",
|
|
"configured",
|
|
"not_configured",
|
|
"available",
|
|
"ingested",
|
|
"failed",
|
|
"quarantined",
|
|
"legacy_unverified",
|
|
)
|
|
PROVENANCE_STATUSES = ("complete", "incomplete", "not_applicable")
|
|
LINEAGE_STATUSES = ("complete", "incomplete", "not_applicable")
|
|
VALIDATION_STATUSES = ("not_validated", "passed", "failed")
|
|
QUARANTINE_STATUSES = ("not_quarantined", "quarantined")
|
|
|
|
|
|
class Project(Base):
|
|
__tablename__ = "projects"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
region: Mapped[str] = mapped_column(String(120), default="Belgium and Belgian North Sea")
|
|
status: Mapped[str] = mapped_column(String(32), default="active")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
|
|
|
areas: Mapped[list["Area"]] = relationship("Area", back_populates="project", cascade="all, delete-orphan")
|
|
datasets: Mapped[list["Dataset"]] = relationship("Dataset", back_populates="project", cascade="all, delete-orphan")
|
|
|
|
|
|
class Area(Base):
|
|
__tablename__ = "areas"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
geometry: Mapped[str] = mapped_column(Geometry("MultiPolygon", srid=4326), nullable=False)
|
|
original_crs: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
area_m2: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
bbox: Mapped[str | None] = mapped_column(Geometry("Polygon", srid=4326), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
project: Mapped[Project] = relationship("Project", back_populates="areas")
|
|
|
|
|
|
class SourceRegistry(Base):
|
|
"""Server-owned source identity and authority contract.
|
|
|
|
Dataset metadata remains descriptive until a governed importer binds a
|
|
dataset to both this registry entry and an immutable SourceSnapshot.
|
|
"""
|
|
|
|
__tablename__ = "source_registry"
|
|
__table_args__ = (
|
|
UniqueConstraint("source_key", name="uq_source_registry_source_key"),
|
|
CheckConstraint(
|
|
"classification IN ('authoritative', 'corroborative', 'contextual', 'derived', 'experimental')",
|
|
name="ck_source_registry_classification",
|
|
),
|
|
CheckConstraint(
|
|
"freshness_status IN ('unknown', 'current', 'due', 'stale', 'not_applicable', 'review_required')",
|
|
name="ck_source_registry_freshness_status",
|
|
),
|
|
CheckConstraint(
|
|
"ingest_status IN ('registered', 'configured', 'not_configured', 'available', 'ingested', "
|
|
"'failed', 'quarantined', 'legacy_unverified')",
|
|
name="ck_source_registry_ingest_status",
|
|
),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
source_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
display_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
classification: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
authority_name: Mapped[str] = mapped_column(String(255), nullable=False, default="unknown", server_default="unknown")
|
|
authority_scope_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
provider_adapter_key: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
source_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
license_name: Mapped[str] = mapped_column(String(255), nullable=False, default="unknown", server_default="unknown")
|
|
license_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
usage_restrictions: Mapped[str] = mapped_column(Text, nullable=False, default="unknown", server_default="unknown")
|
|
default_crs: Mapped[str] = mapped_column(String(64), nullable=False, default="unknown", server_default="unknown")
|
|
default_units: Mapped[str] = mapped_column(String(120), nullable=False, default="unknown", server_default="unknown")
|
|
spatial_resolution_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
temporal_coverage_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
geographic_coverage_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
expected_geometry_types_json: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
|
expected_attributes_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
usage_policy_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
freshness_status: Mapped[str] = mapped_column(
|
|
String(32), nullable=False, default="unknown", server_default="unknown"
|
|
)
|
|
ingest_status: Mapped[str] = mapped_column(
|
|
String(32), nullable=False, default="registered", server_default="registered"
|
|
)
|
|
known_limitations_json: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
|
registry_metadata_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
|
|
|
snapshots: Mapped[list["SourceSnapshot"]] = relationship(
|
|
"SourceSnapshot", back_populates="source_registry", cascade="all, delete-orphan"
|
|
)
|
|
datasets: Mapped[list["Dataset"]] = relationship("Dataset", back_populates="source_registry")
|
|
dataset_versions: Mapped[list["DatasetVersion"]] = relationship("DatasetVersion", back_populates="source_registry")
|
|
|
|
|
|
class SourceSnapshot(Base):
|
|
"""Immutable source-version evidence recorded by governed ingestion."""
|
|
|
|
__tablename__ = "source_snapshots"
|
|
__table_args__ = (
|
|
UniqueConstraint("source_registry_id", "snapshot_key", name="uq_source_snapshots_registry_key"),
|
|
CheckConstraint(
|
|
"freshness_status IN ('unknown', 'current', 'due', 'stale', 'not_applicable', 'review_required')",
|
|
name="ck_source_snapshots_freshness_status",
|
|
),
|
|
CheckConstraint(
|
|
"ingest_status IN ('registered', 'configured', 'not_configured', 'available', 'ingested', "
|
|
"'failed', 'quarantined', 'legacy_unverified')",
|
|
name="ck_source_snapshots_ingest_status",
|
|
),
|
|
CheckConstraint(
|
|
"checksum_sha256 = lower(checksum_sha256) AND checksum_sha256 ~ '^[0-9a-f]{64}$'",
|
|
name="ck_source_snapshots_checksum_sha256",
|
|
),
|
|
Index("ix_source_snapshots_registry_fetched", "source_registry_id", "fetched_at"),
|
|
Index("ix_source_snapshots_checksum", "checksum_sha256"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
source_registry_id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("source_registry.id", ondelete="CASCADE"), nullable=False
|
|
)
|
|
snapshot_key: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
source_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
snapshot_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
fetched_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now())
|
|
source_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
checksum_sha256: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
crs: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
units: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
spatial_resolution_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
temporal_coverage_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
geographic_coverage_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
observed_schema_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
freshness_status: Mapped[str] = mapped_column(
|
|
String(32), nullable=False, default="unknown", server_default="unknown"
|
|
)
|
|
ingest_status: Mapped[str] = mapped_column(
|
|
String(32), nullable=False, default="registered", server_default="registered"
|
|
)
|
|
known_limitations_json: Mapped[list] = mapped_column(JSON, nullable=False, default=list)
|
|
snapshot_metadata_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
source_registry: Mapped[SourceRegistry] = relationship("SourceRegistry", back_populates="snapshots")
|
|
datasets: Mapped[list["Dataset"]] = relationship("Dataset", back_populates="source_snapshot")
|
|
dataset_versions: Mapped[list["DatasetVersion"]] = relationship("DatasetVersion", back_populates="source_snapshot")
|
|
quarantines: Mapped[list["DatasetQuarantine"]] = relationship("DatasetQuarantine", back_populates="source_snapshot")
|
|
|
|
|
|
class Dataset(Base):
|
|
__tablename__ = "datasets"
|
|
__table_args__ = (
|
|
CheckConstraint(
|
|
"valid_to IS NULL OR valid_from IS NULL OR valid_to >= valid_from",
|
|
name="ck_datasets_temporal_valid_range",
|
|
),
|
|
CheckConstraint(
|
|
"validation_status IN ('not_validated', 'passed', 'failed')",
|
|
name="ck_datasets_validation_status",
|
|
),
|
|
CheckConstraint(
|
|
"provenance_status IN ('complete', 'incomplete', 'not_applicable')",
|
|
name="ck_datasets_provenance_status",
|
|
),
|
|
CheckConstraint(
|
|
"lineage_status IN ('complete', 'incomplete', 'not_applicable')",
|
|
name="ck_datasets_lineage_status",
|
|
),
|
|
CheckConstraint(
|
|
"quarantine_status IN ('not_quarantined', 'quarantined')",
|
|
name="ck_datasets_quarantine_status",
|
|
),
|
|
CheckConstraint(
|
|
"ingest_key IS NULL OR btrim(ingest_key) <> ''",
|
|
name="ck_datasets_ingest_key_not_blank",
|
|
),
|
|
UniqueConstraint("project_id", "ingest_key", name="uq_datasets_project_ingest_key"),
|
|
Index(
|
|
"ix_datasets_project_temporal_series_observed",
|
|
"project_id",
|
|
"temporal_series_key",
|
|
"observed_at",
|
|
),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
area_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("areas.id", ondelete="SET NULL"), nullable=True)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
dataset_type: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
source: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
storage_path: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
original_filename: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
stored_filename: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
content_type: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
size_bytes: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
checksum_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
ingest_key: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
derived_from_dataset_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("datasets.id", ondelete="SET NULL"),
|
|
nullable=True,
|
|
)
|
|
crs: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
bounds_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
resolution_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
bands_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
dataset_role: Mapped[str] = mapped_column(String(32), nullable=False, default="source", server_default="source")
|
|
source_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
reference_layer_name: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
source_metadata: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
provenance_metadata: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
source_registry_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("source_registry.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
source_snapshot_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("source_snapshots.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
data_contract_key: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
data_contract_version: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
validation_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="not_validated",
|
|
server_default="not_validated",
|
|
comment="not_validated | passed | failed",
|
|
)
|
|
validation_report_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
provenance_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="incomplete",
|
|
server_default="incomplete",
|
|
comment="complete | incomplete | not_applicable",
|
|
)
|
|
lineage_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="incomplete",
|
|
server_default="incomplete",
|
|
comment="complete | incomplete | not_applicable",
|
|
)
|
|
quarantine_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="not_quarantined",
|
|
server_default="not_quarantined",
|
|
comment="not_quarantined | quarantined",
|
|
)
|
|
imported_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
temporal_series_key: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
observed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
valid_from: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
valid_to: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
temporal_granularity: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
source_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
status: Mapped[str] = mapped_column(String(32), default="uploaded")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
|
|
|
project: Mapped[Project] = relationship("Project", back_populates="datasets")
|
|
versions: Mapped[list["DatasetVersion"]] = relationship(
|
|
"DatasetVersion",
|
|
back_populates="dataset",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
vector_features: Mapped[list["VectorFeature"]] = relationship(
|
|
"VectorFeature",
|
|
back_populates="dataset",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
source_registry: Mapped[SourceRegistry | None] = relationship("SourceRegistry", back_populates="datasets")
|
|
source_snapshot: Mapped[SourceSnapshot | None] = relationship("SourceSnapshot", back_populates="datasets")
|
|
parent_lineage_edges: Mapped[list["DatasetLineageEdge"]] = relationship(
|
|
"DatasetLineageEdge",
|
|
foreign_keys="DatasetLineageEdge.parent_dataset_id",
|
|
back_populates="parent_dataset",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
child_lineage_edges: Mapped[list["DatasetLineageEdge"]] = relationship(
|
|
"DatasetLineageEdge",
|
|
foreign_keys="DatasetLineageEdge.child_dataset_id",
|
|
back_populates="child_dataset",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
quarantines: Mapped[list["DatasetQuarantine"]] = relationship(
|
|
"DatasetQuarantine", back_populates="dataset", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class DatasetVersion(Base):
|
|
__tablename__ = "dataset_versions"
|
|
__table_args__ = (
|
|
CheckConstraint(
|
|
"valid_to IS NULL OR valid_from IS NULL OR valid_to >= valid_from",
|
|
name="ck_dataset_versions_temporal_valid_range",
|
|
),
|
|
CheckConstraint(
|
|
"validation_status IN ('not_validated', 'passed', 'failed')",
|
|
name="ck_dataset_versions_validation_status",
|
|
),
|
|
CheckConstraint(
|
|
"provenance_status IN ('complete', 'incomplete', 'not_applicable')",
|
|
name="ck_dataset_versions_provenance_status",
|
|
),
|
|
CheckConstraint(
|
|
"lineage_status IN ('complete', 'incomplete', 'not_applicable')",
|
|
name="ck_dataset_versions_lineage_status",
|
|
),
|
|
CheckConstraint(
|
|
"ingest_key IS NULL OR btrim(ingest_key) <> ''",
|
|
name="ck_dataset_versions_ingest_key_not_blank",
|
|
),
|
|
Index("ix_dataset_versions_dataset_version", "dataset_id", "version", unique=True),
|
|
UniqueConstraint("dataset_id", "ingest_key", name="uq_dataset_versions_dataset_ingest_key"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
dataset_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="CASCADE"), nullable=False)
|
|
version: Mapped[int] = mapped_column(Integer, default=1)
|
|
storage_path: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
source_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
observed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
valid_from: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
valid_to: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
checksum_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
ingest_key: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
source_metadata: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
provenance_metadata: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
source_registry_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("source_registry.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
source_snapshot_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("source_snapshots.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
data_contract_key: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
data_contract_version: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
validation_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="not_validated",
|
|
server_default="not_validated",
|
|
comment="not_validated | passed | failed",
|
|
)
|
|
validation_report_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
provenance_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="incomplete",
|
|
server_default="incomplete",
|
|
comment="complete | incomplete | not_applicable",
|
|
)
|
|
lineage_status: Mapped[str] = mapped_column(
|
|
String(32),
|
|
nullable=False,
|
|
default="incomplete",
|
|
server_default="incomplete",
|
|
comment="complete | incomplete | not_applicable",
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
dataset: Mapped[Dataset] = relationship("Dataset", back_populates="versions")
|
|
source_registry: Mapped[SourceRegistry | None] = relationship("SourceRegistry", back_populates="dataset_versions")
|
|
source_snapshot: Mapped[SourceSnapshot | None] = relationship("SourceSnapshot", back_populates="dataset_versions")
|
|
quarantines: Mapped[list["DatasetQuarantine"]] = relationship("DatasetQuarantine", back_populates="dataset_version")
|
|
|
|
|
|
class DatasetLineageEdge(Base):
|
|
"""Immutable relationship between input/output datasets and transforms."""
|
|
|
|
__tablename__ = "dataset_lineage_edges"
|
|
__table_args__ = (
|
|
CheckConstraint("parent_dataset_id <> child_dataset_id", name="ck_dataset_lineage_edges_distinct_datasets"),
|
|
UniqueConstraint(
|
|
"parent_dataset_id",
|
|
"child_dataset_id",
|
|
"relation_type",
|
|
"transformation_name",
|
|
name="uq_dataset_lineage_edges_relation",
|
|
),
|
|
Index("ix_dataset_lineage_edges_parent", "parent_dataset_id"),
|
|
Index("ix_dataset_lineage_edges_child", "child_dataset_id"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
parent_dataset_id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="CASCADE"), nullable=False
|
|
)
|
|
child_dataset_id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="CASCADE"), nullable=False
|
|
)
|
|
parent_dataset_version_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("dataset_versions.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
child_dataset_version_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("dataset_versions.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
relation_type: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
transformation_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
transformation_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
parameters_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
input_checksum_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
output_checksum_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
parent_dataset: Mapped[Dataset] = relationship(
|
|
"Dataset", foreign_keys=[parent_dataset_id], back_populates="parent_lineage_edges"
|
|
)
|
|
child_dataset: Mapped[Dataset] = relationship(
|
|
"Dataset", foreign_keys=[child_dataset_id], back_populates="child_lineage_edges"
|
|
)
|
|
|
|
|
|
class DatasetQuarantine(Base):
|
|
"""Durable fail-closed record for rejected or doubtful source artifacts."""
|
|
|
|
__tablename__ = "dataset_quarantines"
|
|
__table_args__ = (
|
|
CheckConstraint(
|
|
"dataset_id IS NOT NULL OR dataset_version_id IS NOT NULL OR source_snapshot_id IS NOT NULL",
|
|
name="ck_dataset_quarantines_target_present",
|
|
),
|
|
CheckConstraint(
|
|
"status IN ('quarantined', 'released', 'rejected')",
|
|
name="ck_dataset_quarantines_status",
|
|
),
|
|
Index("ix_dataset_quarantines_dataset_status", "dataset_id", "status"),
|
|
Index("ix_dataset_quarantines_snapshot_status", "source_snapshot_id", "status"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
dataset_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
dataset_version_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("dataset_versions.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
source_snapshot_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True), ForeignKey("source_snapshots.id", ondelete="SET NULL"), nullable=True
|
|
)
|
|
stage: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
reason_code: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
details_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
artifact_path: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
artifact_checksum_sha256: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
status: Mapped[str] = mapped_column(
|
|
String(32), nullable=False, default="quarantined", server_default="quarantined"
|
|
)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
resolved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
resolved_by: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
|
|
dataset: Mapped[Dataset | None] = relationship("Dataset", back_populates="quarantines")
|
|
dataset_version: Mapped[DatasetVersion | None] = relationship("DatasetVersion", back_populates="quarantines")
|
|
source_snapshot: Mapped[SourceSnapshot | None] = relationship("SourceSnapshot", back_populates="quarantines")
|
|
|
|
|
|
class VectorFeature(Base):
|
|
__tablename__ = "vector_features"
|
|
__table_args__ = (
|
|
Index("ix_vector_features_dataset_id", "dataset_id"),
|
|
Index("ix_vector_features_geometry", "geometry", postgresql_using="gist"),
|
|
Index("ix_vector_features_dataset_source_feature", "dataset_id", "source_feature_id"),
|
|
Index(
|
|
"ix_vector_features_dataset_municipality",
|
|
"dataset_id",
|
|
text("(properties_json ->> 'municipality')"),
|
|
),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
dataset_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="CASCADE"), nullable=False)
|
|
feature_class: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
source_feature_id: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
properties_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
geometry: Mapped[str] = mapped_column(Geometry("Geometry", srid=4326, spatial_index=False), nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
dataset: Mapped[Dataset] = relationship("Dataset", back_populates="vector_features")
|
|
|
|
|
|
class AnalysisRun(Base):
|
|
__tablename__ = "analysis_runs"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
area_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("areas.id", ondelete="SET NULL"), nullable=True)
|
|
dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True)
|
|
analysis_type: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
model_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
|
model_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
parameters_json: Mapped[dict] = mapped_column(JSON, nullable=False)
|
|
result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
|
|
class Detection(Base):
|
|
__tablename__ = "detections"
|
|
__table_args__ = (
|
|
Index("ix_detections_project_id", "project_id"),
|
|
Index("ix_detections_dataset_id", "dataset_id"),
|
|
Index("ix_detections_analysis_run_id", "analysis_run_id"),
|
|
Index("ix_detections_class_name", "class_name"),
|
|
Index("ix_detections_geometry", "geometry", postgresql_using="gist"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
analysis_run_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("analysis_runs.id", ondelete="SET NULL"), nullable=True)
|
|
job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True)
|
|
model_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
model_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
class_name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
confidence: Mapped[float] = mapped_column(Float, nullable=False)
|
|
geometry: Mapped[str] = mapped_column(Geometry("Geometry", srid=4326, spatial_index=False), nullable=False)
|
|
bbox_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
source_tile_path: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
properties_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
|
|
class Segmentation(Base):
|
|
__tablename__ = "segmentations"
|
|
__table_args__ = (
|
|
Index("ix_segmentations_project_id", "project_id"),
|
|
Index("ix_segmentations_dataset_id", "dataset_id"),
|
|
Index("ix_segmentations_analysis_run_id", "analysis_run_id"),
|
|
Index("ix_segmentations_job_id", "job_id"),
|
|
Index("ix_segmentations_class_name", "class_name"),
|
|
Index("ix_segmentations_geometry", "geometry", postgresql_using="gist"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True)
|
|
analysis_run_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("analysis_runs.id", ondelete="SET NULL"), nullable=True)
|
|
model_name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
model_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
class_name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
confidence: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
geometry: Mapped[str] = mapped_column(Geometry("MultiPolygon", srid=4326, spatial_index=False), nullable=False)
|
|
bbox_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
area_m2: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
mask_path: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
source_tile_path: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
|
tile_index: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
properties_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
provenance_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
|
|
class QualityCheck(Base):
|
|
__tablename__ = "quality_checks"
|
|
__table_args__ = (
|
|
Index("ix_quality_checks_project_id", "project_id"),
|
|
Index("ix_quality_checks_reference_dataset_id", "reference_dataset_id"),
|
|
Index("ix_quality_checks_candidate_dataset_id", "candidate_dataset_id"),
|
|
Index("ix_quality_checks_analysis_run_id", "analysis_run_id"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True)
|
|
analysis_run_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("analysis_runs.id", ondelete="SET NULL"), nullable=True)
|
|
candidate_dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
reference_dataset_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="CASCADE"), nullable=False)
|
|
check_type: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
score: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
parameters_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
findings_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
class Metric(Base):
|
|
__tablename__ = "metrics"
|
|
__table_args__ = (
|
|
Index("ix_metrics_quality_check_id", "quality_check_id"),
|
|
Index("ix_metrics_analysis_run_id", "analysis_run_id"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
quality_check_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("quality_checks.id", ondelete="CASCADE"), nullable=True)
|
|
analysis_run_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("analysis_runs.id", ondelete="SET NULL"), nullable=True)
|
|
metric_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
metric_value: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
metric_unit: Mapped[str | None] = mapped_column(String(64), nullable=True)
|
|
label: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
|
metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
|
|
class DetectionReview(Base):
|
|
__tablename__ = "detection_reviews"
|
|
__table_args__ = (
|
|
CheckConstraint(
|
|
"evidence_role IN ('false_positive', 'false_negative')",
|
|
name="ck_detection_reviews_evidence_role",
|
|
),
|
|
CheckConstraint(
|
|
"decision IN ('confirmed_model_false_positive', 'confirmed_model_false_negative', "
|
|
"'reference_gap_or_change', 'qa_alignment_mismatch', "
|
|
"'imagery_obscured_or_uncertain', 'uncertain', 'unreviewed')",
|
|
name="ck_detection_reviews_decision",
|
|
),
|
|
UniqueConstraint(
|
|
"quality_check_id",
|
|
"evidence_role",
|
|
"evidence_feature_id",
|
|
name="uq_detection_reviews_evidence",
|
|
),
|
|
Index("ix_detection_reviews_project_id", "project_id"),
|
|
Index("ix_detection_reviews_quality_check_id", "quality_check_id"),
|
|
Index("ix_detection_reviews_analysis_run_id", "analysis_run_id"),
|
|
Index("ix_detection_reviews_decision", "decision"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
quality_check_id: Mapped[uuid.UUID] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("quality_checks.id", ondelete="CASCADE"),
|
|
nullable=False,
|
|
)
|
|
analysis_run_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("analysis_runs.id", ondelete="SET NULL"),
|
|
nullable=True,
|
|
)
|
|
evidence_role: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
evidence_feature_id: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
detection_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("detections.id", ondelete="SET NULL"),
|
|
nullable=True,
|
|
)
|
|
reference_feature_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
UUID(as_uuid=True),
|
|
ForeignKey("vector_features.id", ondelete="SET NULL"),
|
|
nullable=True,
|
|
)
|
|
decision: Mapped[str] = mapped_column(String(64), nullable=False, default="unreviewed", server_default="unreviewed")
|
|
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
reviewed_by: Mapped[str] = mapped_column(String(120), nullable=False, default="operator", server_default="operator")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
|
|
|
|
|
class Export(Base):
|
|
__tablename__ = "exports"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
analysis_run_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("analysis_runs.id", ondelete="SET NULL"), nullable=True)
|
|
export_type: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
storage_path: Mapped[str] = mapped_column(String(500), nullable=False)
|
|
metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
|
|
class Job(Base):
|
|
__tablename__ = "jobs"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
job_type: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False, default="queued")
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
input_dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
output_dataset_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("datasets.id", ondelete="SET NULL"), nullable=True)
|
|
parameters_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
class AoiOperation(Base):
|
|
__tablename__ = "aoi_operations"
|
|
__table_args__ = (
|
|
CheckConstraint(
|
|
"status IN ('queued', 'running', 'partial', 'success', 'failed', 'cancelled')",
|
|
name="ck_aoi_operations_status",
|
|
),
|
|
Index("ix_aoi_operations_project_status", "project_id", "status"),
|
|
Index("ix_aoi_operations_geometry", "geometry", postgresql_using="gist"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
area_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("areas.id", ondelete="SET NULL"), nullable=True)
|
|
parent_job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True)
|
|
operation_type: Mapped[str] = mapped_column(String(128), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False, default="queued")
|
|
geometry: Mapped[str] = mapped_column(Geometry("MultiPolygon", srid=4326, spatial_index=False), nullable=False)
|
|
request_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
plan_json: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
|
|
|
|
|
class AoiOperationPartition(Base):
|
|
__tablename__ = "aoi_operation_partitions"
|
|
__table_args__ = (
|
|
CheckConstraint(
|
|
"status IN ('queued', 'running', 'success', 'failed', 'skipped')",
|
|
name="ck_aoi_operation_partitions_status",
|
|
),
|
|
UniqueConstraint("operation_id", "partition_key", name="uq_aoi_operation_partition_key"),
|
|
Index("ix_aoi_operation_partitions_operation_status", "operation_id", "status"),
|
|
Index("ix_aoi_operation_partitions_geometry", "geometry", postgresql_using="gist"),
|
|
)
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
operation_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("aoi_operations.id", ondelete="CASCADE"), nullable=False)
|
|
child_job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True)
|
|
partition_key: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
provider_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
product_key: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
ordinal: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
status: Mapped[str] = mapped_column(String(32), nullable=False, default="queued")
|
|
geometry: Mapped[str] = mapped_column(Geometry("MultiPolygon", srid=4326, spatial_index=False), nullable=False)
|
|
attempt_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
max_attempts: Mapped[int] = mapped_column(Integer, nullable=False, default=3)
|
|
checkpoint_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|