Files
KSP_project/app/models.py
T
2026-05-08 15:16:04 +08:00

188 lines
8.7 KiB
Python

from __future__ import annotations
import uuid
from datetime import datetime, timezone
from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, Numeric, String, Text, Uuid
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.extensions import db
def utcnow() -> datetime:
return datetime.now(timezone.utc)
class TimestampMixin:
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=utcnow, nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
)
class EngineFamily(TimestampMixin, db.Model):
__tablename__ = "engine_families"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
engine_name: Mapped[str] = mapped_column(String(255), nullable=False, unique=True)
part_name: Mapped[str | None] = mapped_column(String(255))
cycle: Mapped[str | None] = mapped_column(String(120))
size_m: Mapped[float | None] = mapped_column(Numeric(8, 3))
entry_cost: Mapped[int | None] = mapped_column(Integer)
variants: Mapped[list["EngineVariant"]] = relationship(
back_populates="family",
cascade="all, delete-orphan",
lazy="selectin",
order_by="EngineVariant.source_sheet_row",
)
class EngineVariant(TimestampMixin, db.Model):
__tablename__ = "engine_variants"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
family_id: Mapped[uuid.UUID] = mapped_column(
Uuid, ForeignKey("engine_families.id", ondelete="CASCADE"), nullable=False, index=True
)
fuel_type: Mapped[str] = mapped_column(String(120), nullable=False)
work_env: Mapped[str | None] = mapped_column(String(32))
sl_isp: Mapped[float | None] = mapped_column(Numeric(10, 3))
vac_isp: Mapped[float | None] = mapped_column(Numeric(10, 3))
min_thrust_kn: Mapped[float | None] = mapped_column(Numeric(12, 3))
max_thrust_kn: Mapped[float | None] = mapped_column(Numeric(12, 3))
mass_t: Mapped[float | None] = mapped_column(Numeric(10, 4))
twr: Mapped[float | None] = mapped_column(Numeric(12, 4))
throttle_ratio: Mapped[float | None] = mapped_column(Numeric(8, 4))
tvc_deg: Mapped[float | None] = mapped_column(Numeric(8, 3))
price_kd: Mapped[int | None] = mapped_column(Integer)
ignitions: Mapped[int | None] = mapped_column(Integer)
has_unlimited_ignitions: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
mod_source: Mapped[str | None] = mapped_column(String(120))
engine_note: Mapped[str | None] = mapped_column(Text)
config_name: Mapped[str | None] = mapped_column(String(255), index=True)
tech_required: Mapped[str | None] = mapped_column(String(120))
config_note: Mapped[str | None] = mapped_column(Text)
source_sheet_row: Mapped[int | None] = mapped_column(Integer)
family: Mapped[EngineFamily] = relationship(back_populates="variants")
class CommunicationPart(TimestampMixin, db.Model):
__tablename__ = "communication_parts"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
part_name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
display_name: Mapped[str | None] = mapped_column(String(255))
mass_t: Mapped[float | None] = mapped_column(Numeric(10, 4))
is_active: Mapped[bool | None] = mapped_column(Boolean)
is_deployable: Mapped[bool | None] = mapped_column(Boolean)
antenna_type: Mapped[str | None] = mapped_column(String(120))
deployed_diameter_m: Mapped[float | None] = mapped_column(Numeric(10, 3))
range_raw: Mapped[float | None] = mapped_column(Numeric(24, 3))
range_km: Mapped[float | None] = mapped_column(Numeric(24, 3))
range_au: Mapped[float | None] = mapped_column(Numeric(18, 6))
range_light_year: Mapped[float | None] = mapped_column(Numeric(18, 6))
angle_deg: Mapped[float | None] = mapped_column(Numeric(10, 3))
speed: Mapped[float | None] = mapped_column(Numeric(10, 3))
idle_power_watt: Mapped[float | None] = mapped_column(Numeric(12, 4))
idle_power_text: Mapped[str | None] = mapped_column(String(64))
transmitting_power_watt: Mapped[float | None] = mapped_column(Numeric(12, 4))
transmitting_power_text: Mapped[str | None] = mapped_column(String(64))
source: Mapped[str | None] = mapped_column(String(120))
entry_cost: Mapped[int | None] = mapped_column(Integer)
cost: Mapped[int | None] = mapped_column(Integer)
description: Mapped[str | None] = mapped_column(Text)
rescale_factor: Mapped[float | None] = mapped_column(Numeric(8, 3))
tweakscale: Mapped[str | None] = mapped_column(String(64))
is_feeder: Mapped[bool | None] = mapped_column(Boolean)
tech_required: Mapped[str | None] = mapped_column(String(120))
note: Mapped[str | None] = mapped_column(Text)
class TankSpec(TimestampMixin, db.Model):
__tablename__ = "tank_specs"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
tank_name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
fuel_type: Mapped[str | None] = mapped_column(String(120))
dry_mass_t: Mapped[float | None] = mapped_column(Numeric(10, 4))
fuel_mass_t: Mapped[float | None] = mapped_column(Numeric(10, 4))
wet_mass_t: Mapped[float | None] = mapped_column(Numeric(10, 4))
tank_volume_l: Mapped[float | None] = mapped_column(Numeric(12, 3))
mass_ratio: Mapped[float | None] = mapped_column(Numeric(12, 4))
kiloliters_per_ton: Mapped[float | None] = mapped_column(Numeric(12, 4))
vehicle_name: Mapped[str | None] = mapped_column(String(120))
source: Mapped[str | None] = mapped_column(String(120))
note: Mapped[str | None] = mapped_column(Text)
class VehicleCost(TimestampMixin, db.Model):
__tablename__ = "vehicle_costs"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
vehicle_name: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
launch_price: Mapped[int | None] = mapped_column(Integer)
source: Mapped[str | None] = mapped_column(String(120))
class Asset(TimestampMixin, db.Model):
__tablename__ = "assets"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
name: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True)
asset_type: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
is_retired: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
program: Mapped[str | None] = mapped_column(String(255))
home_region: Mapped[str | None] = mapped_column(String(120))
note: Mapped[str | None] = mapped_column(Text)
log_entries: Mapped[list["AssetLogEntry"]] = relationship(
back_populates="asset",
cascade="all, delete-orphan",
lazy="selectin",
order_by="AssetLogEntry.start_at",
)
class AssetLogEntry(TimestampMixin, db.Model):
__tablename__ = "asset_log_entries"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
asset_id: Mapped[uuid.UUID] = mapped_column(
Uuid, ForeignKey("assets.id", ondelete="CASCADE"), nullable=False, index=True
)
entry_kind: Mapped[str] = mapped_column(String(16), nullable=False)
title: Mapped[str] = mapped_column(String(255), nullable=False)
state_label: Mapped[str | None] = mapped_column(String(120))
mission_label: Mapped[str | None] = mapped_column(String(255))
location: Mapped[str | None] = mapped_column(String(255))
start_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, index=True)
end_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
summary: Mapped[str | None] = mapped_column(Text)
note: Mapped[str | None] = mapped_column(Text)
asset: Mapped[Asset] = relationship(back_populates="log_entries")
state_nodes: Mapped[list["AssetStateNode"]] = relationship(
back_populates="entry",
cascade="all, delete-orphan",
lazy="selectin",
order_by="AssetStateNode.at_time",
)
class AssetStateNode(TimestampMixin, db.Model):
__tablename__ = "asset_state_nodes"
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
entry_id: Mapped[uuid.UUID] = mapped_column(
Uuid, ForeignKey("asset_log_entries.id", ondelete="CASCADE"), nullable=False, index=True
)
title: Mapped[str] = mapped_column(String(255), nullable=False)
detail: Mapped[str | None] = mapped_column(Text)
at_time: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, index=True)
entry: Mapped[AssetLogEntry] = relationship(back_populates="state_nodes")