from datetime import datetime from uuid import uuid4 from sqlalchemy import DateTime, Float, ForeignKey, Integer, String, Text, func from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.base import Base class Job(Base): __tablename__ = "jobs" id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: f"job_{uuid4().hex[:12]}") title: Mapped[str] = mapped_column(String(255)) category: Mapped[str] = mapped_column(String(128)) description: Mapped[str] = mapped_column(Text) city: Mapped[str] = mapped_column(String(64)) region: Mapped[str] = mapped_column(String(64)) location_detail: Mapped[str] = mapped_column(String(255)) start_time: Mapped[datetime] = mapped_column(DateTime(timezone=True)) duration_hours: Mapped[float] = mapped_column(Float) headcount: Mapped[int] = mapped_column(Integer) salary_type: Mapped[str] = mapped_column(String(32)) salary_amount: Mapped[float] = mapped_column(Float) salary_currency: Mapped[str] = mapped_column(String(16), default="CNY") work_mode: Mapped[str] = mapped_column(String(64)) tags_json: Mapped[list[str]] = mapped_column(JSONB, default=list) confidence: Mapped[float] = mapped_column(Float) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) skills: Mapped[list["JobSkill"]] = relationship(back_populates="job", cascade="all, delete-orphan") class JobSkill(Base): __tablename__ = "job_skills" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) job_id: Mapped[str] = mapped_column(ForeignKey("jobs.id", ondelete="CASCADE"), index=True) skill_name: Mapped[str] = mapped_column(String(128), index=True) weight: Mapped[float] = mapped_column(Float, default=1.0) is_required: Mapped[bool] = mapped_column(default=True) job: Mapped[Job] = relationship(back_populates="skills") class Worker(Base): __tablename__ = "workers" id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: f"worker_{uuid4().hex[:12]}") name: Mapped[str] = mapped_column(String(128)) description: Mapped[str] = mapped_column(Text) cities_json: Mapped[list[str]] = mapped_column(JSONB, default=list) regions_json: Mapped[list[str]] = mapped_column(JSONB, default=list) availability_json: Mapped[list[str]] = mapped_column(JSONB, default=list) experience_tags_json: Mapped[list[str]] = mapped_column(JSONB, default=list) reliability_score: Mapped[float] = mapped_column(Float, default=0.7) profile_completion: Mapped[float] = mapped_column(Float, default=0.6) confidence: Mapped[float] = mapped_column(Float, default=0.8) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) skills: Mapped[list["WorkerSkill"]] = relationship(back_populates="worker", cascade="all, delete-orphan") class WorkerSkill(Base): __tablename__ = "worker_skills" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) worker_id: Mapped[str] = mapped_column(ForeignKey("workers.id", ondelete="CASCADE"), index=True) skill_name: Mapped[str] = mapped_column(String(128), index=True) score: Mapped[float] = mapped_column(Float, default=0.7) worker: Mapped[Worker] = relationship(back_populates="skills") class MatchRecord(Base): __tablename__ = "matches" id: Mapped[str] = mapped_column(String(64), primary_key=True, default=lambda: f"match_{uuid4().hex[:12]}") source_type: Mapped[str] = mapped_column(String(32), index=True) source_id: Mapped[str] = mapped_column(String(64), index=True) target_id: Mapped[str] = mapped_column(String(64), index=True) match_score: Mapped[float] = mapped_column(Float) breakdown_json: Mapped[dict] = mapped_column(JSONB) reasons_json: Mapped[list[str]] = mapped_column(JSONB) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())