Files
2026-04-24 00:20:42 +03:00

222 lines
6.8 KiB
Python

from __future__ import annotations
from datetime import datetime
from sqlalchemy import (
BigInteger,
Boolean,
DateTime,
Enum,
ForeignKey,
Integer,
String,
Text,
func,
)
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
CAR_TABLE_NAME = "iaai_cars"
IMAGE_TABLE_NAME = "iaai_images"
SYNC_RUN_TABLE_NAME = "iaai_sync_runs"
CURRENCY_ENUM_VALUES = ("JPY", "USD", "EUR", "RUB", "KRW", "AED", "GBP", "CAD")
DRIVE_ENUM_VALUES = ("FWD", "RWD", "TWO_WD", "FOUR_WD", "2WD", "4WD", "NA")
GEARBOX_ENUM_VALUES = ("AT", "CVT", "MT", "EV", "NA")
STEERING_WHEEL_ENUM_VALUES = ("LEFT", "RIGHT", "left", "right", "NA")
BODY_TYPE_ENUM_VALUES = (
"COUPE",
"SUV",
"HATCHBACK",
"MINIVAN",
"SEDAN",
"NA",
"Station Wagon",
"Pickup",
"Truck",
"Open",
"RV",
"Other",
"STATION_WAGON",
"PICKUP",
"TRUCK",
"OPEN",
"OTHER",
)
COUNTRY_ENUM_VALUES = ("JP", "KR", "US", "CA", "NA")
ORIGIN_ENUM_VALUES = (
"TAU",
"CARSENSOR",
"HANAMARU",
"ENCAR",
"KURUMA_TRADER",
"carsensor",
"encar",
"kuruma_trader",
"asnet",
"kababa",
"ACV",
"COPART",
"IAAI",
"copart",
"iaai",
"NA",
"ASNET",
"KABABA",
)
SELLING_TYPE_ENUM_VALUES = ("STOCK", "AUCTION", "TENDER", "stock", "auction", "tender", "NA")
class Car(Base):
__tablename__ = CAR_TABLE_NAME
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
parser_id: Mapped[str] = mapped_column(String(50), nullable=False, unique=True)
brand: Mapped[str] = mapped_column(String(50), nullable=False)
model: Mapped[str] = mapped_column(String(50), nullable=False)
year: Mapped[int | None] = mapped_column(Integer, nullable=True)
price: Mapped[int | None] = mapped_column(BigInteger, nullable=True)
currency: Mapped[str] = mapped_column(
Enum(
*CURRENCY_ENUM_VALUES,
name="currencyenum",
native_enum=True,
create_constraint=False,
),
nullable=False,
default="USD",
)
mileage: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
country: Mapped[str] = mapped_column(
Enum(
*COUNTRY_ENUM_VALUES,
name="countryenum",
native_enum=True,
create_constraint=False,
),
nullable=False,
default="NA",
)
is_sold: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
color: Mapped[str] = mapped_column(String(), nullable=False, default="other")
drive: Mapped[str | None] = mapped_column(
Enum(
*DRIVE_ENUM_VALUES,
name="driveenum",
native_enum=True,
create_constraint=False,
),
nullable=True,
)
gearbox: Mapped[str | None] = mapped_column(
Enum(
*GEARBOX_ENUM_VALUES,
name="gearboxenum",
native_enum=True,
create_constraint=False,
),
nullable=True,
)
steering_wheel: Mapped[str | None] = mapped_column(
Enum(
*STEERING_WHEEL_ENUM_VALUES,
name="steeringwheelenum",
native_enum=True,
create_constraint=False,
),
nullable=True,
)
body_type: Mapped[str] = mapped_column(
Enum(
*BODY_TYPE_ENUM_VALUES,
name="bodytypeenum",
native_enum=True,
create_constraint=False,
),
nullable=False,
default="OTHER",
)
engine_volume: Mapped[int | None] = mapped_column(Integer, nullable=True)
selling_type: Mapped[str] = mapped_column(
Enum(
*SELLING_TYPE_ENUM_VALUES,
name="sellingtypeenum",
native_enum=True,
create_constraint=False,
),
nullable=False,
default="NA",
)
one_owner: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
new_car: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
is_hidden: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
origin: Mapped[str] = mapped_column(
Enum(
*ORIGIN_ENUM_VALUES,
name="originenum",
native_enum=True,
create_constraint=False,
),
nullable=False,
default="NA",
)
origin_url: Mapped[str] = mapped_column(String(), nullable=False)
origin_id: Mapped[str] = mapped_column(String(), nullable=False, unique=True)
is_damaged: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
evaluation: Mapped[str | None] = mapped_column(String(), nullable=True)
non_smoking: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
rental: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
repair_history: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
slug: Mapped[str] = mapped_column(String(), nullable=False)
last_seen_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=func.now())
images: Mapped[list["Image"]] = relationship(
"Image",
back_populates="car",
cascade="all, delete-orphan",
)
class Image(Base):
__tablename__ = IMAGE_TABLE_NAME
id: Mapped[int] = mapped_column(
BigInteger().with_variant(Integer, "sqlite"),
primary_key=True,
autoincrement=True,
)
fullres_image: Mapped[str] = mapped_column(String(), nullable=False)
preview_image: Mapped[str] = mapped_column(String(), nullable=False)
order_index: Mapped[int] = mapped_column(Integer, nullable=False)
car_id: Mapped[int] = mapped_column(
Integer,
ForeignKey(f"{CAR_TABLE_NAME}.id", ondelete="CASCADE"),
nullable=False,
)
car: Mapped[Car] = relationship("Car", back_populates="images")
class SyncRun(Base):
__tablename__ = SYNC_RUN_TABLE_NAME
id: Mapped[int] = mapped_column(
BigInteger().with_variant(Integer, "sqlite"),
primary_key=True,
autoincrement=True,
)
started_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, default=func.now())
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
status: Mapped[str] = mapped_column(Text, nullable=False)
lane: Mapped[str] = mapped_column(Text, nullable=False)
ids_fetched: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
cars_upserted: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
cars_failed: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
images_upserted: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
error_summary: Mapped[str | None] = mapped_column(Text, nullable=True)