from sqlalchemy import Float, ForeignKey, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base class ScopeInfo(Base): """Scope-specific attributes for an AugmentedPart of PartType "Scope". One-to-one with AugmentedPart (unique augmented_part_id). Holds fields that have no home on AugmentedPart itself; populated by the scope xlsx importer. """ __tablename__ = "scope_infos" __table_args__ = (UniqueConstraint("augmented_part_id"),) id: Mapped[int] = mapped_column(primary_key=True) augmented_part_id: Mapped[int] = mapped_column( ForeignKey("augmented_parts.id", ondelete="CASCADE"), nullable=False ) magnification_min: Mapped[float | None] = mapped_column( Float, nullable=True, default=None ) magnification_max: Mapped[float | None] = mapped_column( Float, nullable=True, default=None ) model_suffix: Mapped[str | None] = mapped_column( String, nullable=True, default=None ) # The lens diameter is a descriptive attribute (the "50" in "3-18x50"), not a # connection dimension — it has no AttachmentPoint. objective_lens_diameter_mm: Mapped[float | None] = mapped_column( Float, nullable=True, default=None ) # Kept as the raw string from the sheet (e.g. "0.75", "1/16") so no precision # or notation is lost; the parsed thread lives on its own AttachmentPoint. objective_thread_pitch: Mapped[str | None] = mapped_column( String, nullable=True, default=None )