""" SQLAlchemy ORM models for Nexus Autoparts. """ from sqlalchemy import ( Column, Integer, String, Float, Boolean, Text, DateTime, ForeignKey, UniqueConstraint, Index, func, text ) from sqlalchemy.dialects.postgresql import JSONB, TSVECTOR from sqlalchemy.orm import relationship, DeclarativeBase from datetime import datetime class Base(DeclarativeBase): pass # ───────────────────────────────────────────── # Lookup tables # ───────────────────────────────────────────── class FuelType(Base): __tablename__ = "fuel_type" id_fuel = Column(Integer, primary_key=True) name_fuel = Column(String(50), nullable=False, unique=True) class BodyType(Base): __tablename__ = "body_type" id_body = Column(Integer, primary_key=True) name_body = Column(String(50), nullable=False, unique=True) class Drivetrain(Base): __tablename__ = "drivetrain" id_drivetrain = Column(Integer, primary_key=True) name_drivetrain = Column(String(50), nullable=False, unique=True) class Transmission(Base): __tablename__ = "transmission" id_transmission = Column(Integer, primary_key=True) name_transmission = Column(String(50), nullable=False, unique=True) class Material(Base): __tablename__ = "materials" id_material = Column(Integer, primary_key=True) name_material = Column(String(100), nullable=False, unique=True) class PositionPart(Base): __tablename__ = "position_part" id_position_part = Column(Integer, primary_key=True) name_position_part = Column(String(50), nullable=False, unique=True) class ManufactureType(Base): __tablename__ = "manufacture_type" id_type_manu = Column(Integer, primary_key=True) name_type_manu = Column(String(50), nullable=False, unique=True) class QualityTier(Base): __tablename__ = "quality_tier" id_quality_tier = Column(Integer, primary_key=True) name_quality = Column(String(50), nullable=False, unique=True) class Country(Base): __tablename__ = "countries" id_country = Column(Integer, primary_key=True) name_country = Column(String(100), nullable=False, unique=True) class ReferenceType(Base): __tablename__ = "reference_type" id_ref_type = Column(Integer, primary_key=True) name_ref_type = Column(String(50), nullable=False, unique=True) class Shape(Base): __tablename__ = "shapes" id_shape = Column(Integer, primary_key=True) name_shape = Column(String(50), nullable=False, unique=True) # ───────────────────────────────────────────── # Core tables # ───────────────────────────────────────────── class Brand(Base): __tablename__ = "brands" id_brand = Column(Integer, primary_key=True) name_brand = Column(String(200), nullable=False, unique=True) country = Column(String(100)) founded_year = Column(Integer) created_at = Column(DateTime, default=datetime.utcnow) models = relationship("Model", back_populates="brand") class Year(Base): __tablename__ = "years" id_year = Column(Integer, primary_key=True) year_car = Column(Integer, nullable=False, unique=True) created_at = Column(DateTime, default=datetime.utcnow) class Engine(Base): __tablename__ = "engines" id_engine = Column(Integer, primary_key=True) name_engine = Column(String(300), nullable=False) displacement_cc = Column(Float) cylinders = Column(Integer) id_fuel = Column(Integer, ForeignKey("fuel_type.id_fuel")) power_hp = Column(Integer) torque_nm = Column(Integer) engine_code = Column(String(100)) created_at = Column(DateTime, default=datetime.utcnow) fuel_type = relationship("FuelType") class Model(Base): __tablename__ = "models" id_model = Column(Integer, primary_key=True) brand_id = Column(Integer, ForeignKey("brands.id_brand"), nullable=False) name_model = Column(String(300), nullable=False) id_body = Column(Integer, ForeignKey("body_type.id_body")) generation = Column(String(100)) production_start_year = Column(Integer) production_end_year = Column(Integer) created_at = Column(DateTime, default=datetime.utcnow) brand = relationship("Brand", back_populates="models") body_type = relationship("BodyType") __table_args__ = ( Index("idx_models_brand", "brand_id"), ) class ModelYearEngine(Base): __tablename__ = "model_year_engine" id_mye = Column(Integer, primary_key=True) model_id = Column(Integer, ForeignKey("models.id_model"), nullable=False) year_id = Column(Integer, ForeignKey("years.id_year"), nullable=False) engine_id = Column(Integer, ForeignKey("engines.id_engine"), nullable=False) trim_level = Column(String(100)) id_drivetrain = Column(Integer, ForeignKey("drivetrain.id_drivetrain")) id_transmission = Column(Integer, ForeignKey("transmission.id_transmission")) created_at = Column(DateTime, default=datetime.utcnow) model = relationship("Model") year = relationship("Year") engine = relationship("Engine") drivetrain = relationship("Drivetrain") transmission = relationship("Transmission") __table_args__ = ( UniqueConstraint("model_id", "year_id", "engine_id", "trim_level", name="uq_mye_combo"), Index("idx_mye_model", "model_id"), Index("idx_mye_year", "year_id"), Index("idx_mye_engine", "engine_id"), ) class PartCategory(Base): __tablename__ = "part_categories" id_part_category = Column(Integer, primary_key=True) name_part_category = Column(String(200), nullable=False) name_es = Column(String(200)) parent_id = Column(Integer, ForeignKey("part_categories.id_part_category")) slug = Column(String(200), unique=True) icon_name = Column(String(100)) display_order = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.utcnow) parent = relationship("PartCategory", remote_side="PartCategory.id_part_category") __table_args__ = ( Index("idx_part_categories_parent", "parent_id"), Index("idx_part_categories_slug", "slug"), ) class PartGroup(Base): __tablename__ = "part_groups" id_part_group = Column(Integer, primary_key=True) category_id = Column(Integer, ForeignKey("part_categories.id_part_category"), nullable=False) name_part_group = Column(String(200), nullable=False) name_es = Column(String(200)) slug = Column(String(200)) display_order = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.utcnow) category = relationship("PartCategory") __table_args__ = ( Index("idx_part_groups_category", "category_id"), ) class Part(Base): __tablename__ = "parts" id_part = Column(Integer, primary_key=True) oem_part_number = Column(String(100), nullable=False) name_part = Column(String(300), nullable=False) name_es = Column(String(300)) group_id = Column(Integer, ForeignKey("part_groups.id_part_group")) description = Column(Text) description_es = Column(Text) weight_kg = Column(Float) id_material = Column(Integer, ForeignKey("materials.id_material")) created_at = Column(DateTime, default=datetime.utcnow) search_vector = Column(TSVECTOR) group = relationship("PartGroup") material = relationship("Material") __table_args__ = ( Index("idx_parts_oem", "oem_part_number"), Index("idx_parts_group", "group_id"), Index("idx_parts_search", "search_vector", postgresql_using="gin"), ) class VehiclePart(Base): __tablename__ = "vehicle_parts" id_vehicle_part = Column(Integer, primary_key=True) model_year_engine_id = Column(Integer, ForeignKey("model_year_engine.id_mye"), nullable=False) part_id = Column(Integer, ForeignKey("parts.id_part"), nullable=False) quantity_required = Column(Integer, default=1) id_position_part = Column(Integer, ForeignKey("position_part.id_position_part")) fitment_notes = Column(Text) created_at = Column(DateTime, default=datetime.utcnow) model_year_engine = relationship("ModelYearEngine") part = relationship("Part") position = relationship("PositionPart") __table_args__ = ( UniqueConstraint("model_year_engine_id", "part_id", "id_position_part", name="uq_vehicle_part"), Index("idx_vehicle_parts_mye", "model_year_engine_id"), Index("idx_vehicle_parts_part", "part_id"), ) class Manufacturer(Base): __tablename__ = "manufacturers" id_manufacture = Column(Integer, primary_key=True) name_manufacture = Column(String(200), nullable=False, unique=True) id_type_manu = Column(Integer, ForeignKey("manufacture_type.id_type_manu")) id_quality_tier = Column(Integer, ForeignKey("quality_tier.id_quality_tier")) id_country = Column(Integer, ForeignKey("countries.id_country")) logo_url = Column(String(500)) website = Column(String(500)) created_at = Column(DateTime, default=datetime.utcnow) manufacture_type = relationship("ManufactureType") quality_tier = relationship("QualityTier") country = relationship("Country") class AftermarketPart(Base): __tablename__ = "aftermarket_parts" id_aftermarket_parts = Column(Integer, primary_key=True) oem_part_id = Column(Integer, ForeignKey("parts.id_part"), nullable=False) manufacturer_id = Column(Integer, ForeignKey("manufacturers.id_manufacture"), nullable=False) part_number = Column(String(100), nullable=False) name_aftermarket_parts = Column(String(300)) name_es = Column(String(300)) id_quality_tier = Column(Integer, ForeignKey("quality_tier.id_quality_tier")) price_usd = Column(Float) warranty_months = Column(Integer) created_at = Column(DateTime, default=datetime.utcnow) oem_part = relationship("Part") manufacturer = relationship("Manufacturer") quality_tier = relationship("QualityTier") __table_args__ = ( Index("idx_aftermarket_oem", "oem_part_id"), Index("idx_aftermarket_manufacturer", "manufacturer_id"), Index("idx_aftermarket_part_number", "part_number"), ) class PartCrossReference(Base): __tablename__ = "part_cross_references" id_part_cross_ref = Column(Integer, primary_key=True) part_id = Column(Integer, ForeignKey("parts.id_part"), nullable=False) cross_reference_number = Column(String(100), nullable=False) id_ref_type = Column(Integer, ForeignKey("reference_type.id_ref_type")) source_ref = Column(String(200)) notes = Column(Text) created_at = Column(DateTime, default=datetime.utcnow) part = relationship("Part") reference_type = relationship("ReferenceType") __table_args__ = ( Index("idx_cross_ref_part", "part_id"), Index("idx_cross_ref_number", "cross_reference_number"), ) class Diagram(Base): __tablename__ = "diagrams" id_diagram = Column(Integer, primary_key=True) name_diagram = Column(String(300), nullable=False) name_es = Column(String(300)) group_id = Column(Integer, ForeignKey("part_groups.id_part_group"), nullable=False) image_path = Column(String(500), nullable=False) thumbnail_path = Column(String(500)) display_order = Column(Integer, default=0) source_diagram = Column(String(200)) created_at = Column(DateTime, default=datetime.utcnow) group = relationship("PartGroup") __table_args__ = ( Index("idx_diagrams_group", "group_id"), ) class VehicleDiagram(Base): __tablename__ = "vehicle_diagrams" id_vehicle_dgr = Column(Integer, primary_key=True) diagram_id = Column(Integer, ForeignKey("diagrams.id_diagram"), nullable=False) model_year_engine_id = Column(Integer, ForeignKey("model_year_engine.id_mye"), nullable=False) notes = Column(Text) created_at = Column(DateTime, default=datetime.utcnow) diagram = relationship("Diagram") model_year_engine = relationship("ModelYearEngine") __table_args__ = ( UniqueConstraint("diagram_id", "model_year_engine_id", name="uq_vehicle_diagram"), Index("idx_vehicle_diagrams_diagram", "diagram_id"), Index("idx_vehicle_diagrams_mye", "model_year_engine_id"), ) class DiagramHotspot(Base): __tablename__ = "diagram_hotspots" id_dgr_hotspot = Column(Integer, primary_key=True) diagram_id = Column(Integer, ForeignKey("diagrams.id_diagram"), nullable=False) part_id = Column(Integer, ForeignKey("parts.id_part")) callout_number = Column(Integer) id_shape = Column(Integer, ForeignKey("shapes.id_shape")) coords = Column(Text, nullable=False) created_at = Column(DateTime, default=datetime.utcnow) diagram = relationship("Diagram") part = relationship("Part") shape = relationship("Shape") __table_args__ = ( Index("idx_hotspots_diagram", "diagram_id"), Index("idx_hotspots_part", "part_id"), ) class VinCache(Base): __tablename__ = "vin_cache" id = Column(Integer, primary_key=True) vin = Column(String(17), nullable=False, unique=True) decoded_data = Column(JSONB, nullable=False) make = Column(String(100)) model = Column(String(100)) year = Column(Integer) engine_info = Column(String(200)) body_class = Column(String(100)) drive_type = Column(String(100)) model_year_engine_id = Column(Integer, ForeignKey("model_year_engine.id_mye")) created_at = Column(DateTime, default=datetime.utcnow) expires_at = Column(DateTime) __table_args__ = ( Index("idx_vin_cache_vin", "vin"), Index("idx_vin_cache_make_model", "make", "model", "year"), ) # ───────────────────────────────────────────── # Full-text search trigger SQL (run after table creation) # ───────────────────────────────────────────── SEARCH_VECTOR_TRIGGER_SQL = """ CREATE OR REPLACE FUNCTION parts_search_vector_update() RETURNS trigger AS $$ BEGIN NEW.search_vector := to_tsvector('spanish', coalesce(NEW.oem_part_number, '') || ' ' || coalesce(NEW.name_part, '') || ' ' || coalesce(NEW.name_es, '') || ' ' || coalesce(NEW.description, '') ); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trg_parts_search_vector ON parts; CREATE TRIGGER trg_parts_search_vector BEFORE INSERT OR UPDATE ON parts FOR EACH ROW EXECUTE FUNCTION parts_search_vector_update(); """