feat(validation): add SQLModel database models and fix relationships

This commit is contained in:
2026-03-19 10:27:20 +08:00
parent d0cdf50ed5
commit d18133ce16
6 changed files with 2091 additions and 13 deletions

View File

@@ -0,0 +1,26 @@
from __future__ import annotations
from contextlib import contextmanager
from pathlib import Path
from sqlmodel import Session, SQLModel, create_engine
def get_engine(db_path: str | Path):
"""Create SQLite engine."""
db_path = Path(db_path)
db_path.parent.mkdir(parents=True, exist_ok=True)
url = f"sqlite:///{db_path}"
return create_engine(url, echo=False)
@contextmanager
def get_session(engine):
"""Context manager for database sessions."""
with Session(engine) as session:
yield session
def init_database(engine):
"""Create all tables."""
SQLModel.metadata.create_all(engine)

View File

@@ -1,25 +1,26 @@
from __future__ import annotations
from datetime import datetime
from enum import Enum
from typing import List, Optional
from sqlmodel import Field, Relationship, SQLModel
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlmodel import Field, SQLModel
class ClassificationType(str, Enum):
class ClassificationType:
STANDARD = "standard_macrolactone"
NON_STANDARD = "non_standard_macrocycle"
NOT_MACROLACTONE = "not_macrolactone"
class ProcessingStatus(str, Enum):
class ProcessingStatus:
PENDING = "pending"
SUCCESS = "success"
FAILED = "failed"
SKIPPED = "skipped"
# Define all tables without relationships first
class ParentMolecule(SQLModel, table=True):
"""Original molecule information."""
@@ -29,11 +30,11 @@ class ParentMolecule(SQLModel, table=True):
source_id: str = Field(index=True)
molecule_name: Optional[str] = None
smiles: str = Field(index=True)
classification: ClassificationType = Field(index=True)
classification: str = Field(index=True)
ring_size: Optional[int] = Field(default=None, index=True)
primary_reason_code: Optional[str] = None
primary_reason_message: Optional[str] = None
processing_status: ProcessingStatus = Field(default=ProcessingStatus.PENDING)
processing_status: str = Field(default=ProcessingStatus.PENDING)
error_message: Optional[str] = None
num_sidechains: Optional[int] = None
cleavage_positions: Optional[str] = None
@@ -41,9 +42,6 @@ class ParentMolecule(SQLModel, table=True):
created_at: datetime = Field(default_factory=datetime.utcnow)
processed_at: Optional[datetime] = None
fragments: List["SideChainFragment"] = Relationship(back_populates="parent")
numbering: Optional["RingNumbering"] = Relationship(back_populates="parent")
class RingNumbering(SQLModel, table=True):
"""Ring numbering details."""
@@ -58,8 +56,6 @@ class RingNumbering(SQLModel, table=True):
position_to_atom: str
atom_to_position: str
parent: Optional[ParentMolecule] = Relationship(back_populates="numbering")
class SideChainFragment(SQLModel, table=True):
"""Side chain fragments from cleavage."""
@@ -81,8 +77,6 @@ class SideChainFragment(SQLModel, table=True):
original_bond_type: str
image_path: Optional[str] = None
parent: Optional[ParentMolecule] = Relationship(back_populates="fragments")
class ValidationResult(SQLModel, table=True):
"""Manual validation records."""