2024-01-29 17:37:30 +00:00
|
|
|
import datetime
|
2024-01-30 00:32:04 +00:00
|
|
|
import re
|
2024-01-29 17:37:30 +00:00
|
|
|
from typing import Optional
|
|
|
|
|
|
|
|
from sqlalchemy import String, Select, select, Table, Column, ForeignKey
|
|
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
|
|
|
|
|
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class Resource(Base):
|
|
|
|
__tablename__ = "resources"
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
label: Mapped[str] = mapped_column(String(127))
|
|
|
|
wiki_url: Mapped[str] # FIXME: rename to uri
|
|
|
|
recipes_populated_at: Mapped[Optional[datetime.datetime]]
|
|
|
|
flows: Mapped[list["ResourceFlow"]] = relationship(back_populates="resource")
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def by_label(cls, search: str) -> Select[tuple["Resource"]]:
|
|
|
|
return select(cls).where(cls.label.ilike(search))
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return (
|
|
|
|
f"Resource(id={self.id}, "
|
|
|
|
f"label={self.label}, "
|
|
|
|
f"wiki_url={self.wiki_url}, "
|
|
|
|
f"recipes_populated_at={self.recipes_populated_at})"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class Factory(Base):
|
|
|
|
__tablename__ = "factories"
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
label: Mapped[str] = mapped_column(String(127))
|
|
|
|
wiki_url: Mapped[str] # FIXME: rename to uri
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def by_label(cls, search: str) -> Select[tuple["Factory"]]:
|
|
|
|
return select(cls).where(cls.label.ilike(search))
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return f"Factory(id={self.id}, label={self.label}, wiki_url={self.wiki_url})"
|
|
|
|
|
|
|
|
|
|
|
|
ingredients_table = Table(
|
|
|
|
"recipe_ingredients",
|
|
|
|
Base.metadata,
|
|
|
|
Column("recipe_id", ForeignKey("recipes.id"), primary_key=True),
|
|
|
|
Column("resource_flow_id", ForeignKey("resource_flows.id"), primary_key=True),
|
|
|
|
)
|
|
|
|
results_table = Table(
|
|
|
|
"recipe_results",
|
|
|
|
Base.metadata,
|
|
|
|
Column("recipe_id", ForeignKey("recipes.id"), primary_key=True),
|
|
|
|
Column("resource_flow_id", ForeignKey("resource_flows.id"), primary_key=True),
|
|
|
|
)
|
|
|
|
|
2024-01-30 00:32:04 +00:00
|
|
|
amount_number = re.compile(r"^\d*(\.\d+)?")
|
|
|
|
time_number = re.compile(r"^(\d+) seconds?")
|
|
|
|
|
2024-01-29 17:37:30 +00:00
|
|
|
|
|
|
|
class ResourceFlow(Base):
|
|
|
|
__tablename__ = "resource_flows"
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
ingredient_in: Mapped[Optional["Recipe"]] = relationship(secondary=ingredients_table, back_populates="ingredients")
|
|
|
|
result_of: Mapped[Optional["Recipe"]] = relationship(secondary=results_table, back_populates="results")
|
|
|
|
resource_id: Mapped[int] = mapped_column(ForeignKey("resources.id"))
|
|
|
|
resource: Mapped["Resource"] = relationship(back_populates="flows")
|
|
|
|
amount: Mapped[str]
|
|
|
|
time: Mapped[str]
|
|
|
|
|
2024-01-30 00:32:04 +00:00
|
|
|
def amount_per_minute(self) -> float:
|
|
|
|
per_crafting_step_str = amount_number.match(self.amount).group(0)
|
|
|
|
per_crafting_step = float(per_crafting_step_str)
|
|
|
|
crafting_time_seconds_str = time_number.match(self.time).group(1)
|
|
|
|
crafting_time_seconds = float(crafting_time_seconds_str)
|
|
|
|
return per_crafting_step * (60.0 / crafting_time_seconds)
|
|
|
|
|
|
|
|
def describe(self) -> str:
|
|
|
|
return f"{repr(str(self.resource.label))}x{self.amount}"
|
|
|
|
|
2024-01-29 17:37:30 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return f"ResourceFlow(id={self.id}, resource_id={self.resource_id}, amount={self.amount}, time={self.time})"
|
|
|
|
|
|
|
|
|
|
|
|
class Recipe(Base):
|
|
|
|
__tablename__ = "recipes"
|
|
|
|
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
|
|
factory_id: Mapped[int] = mapped_column(ForeignKey("factories.id"))
|
|
|
|
factory: Mapped["Factory"] = relationship()
|
|
|
|
ingredients: Mapped[list["ResourceFlow"]] = relationship(
|
|
|
|
secondary=ingredients_table, back_populates="ingredient_in"
|
|
|
|
)
|
|
|
|
results: Mapped[list["ResourceFlow"]] = relationship(secondary=results_table, back_populates="result_of")
|
|
|
|
|
2024-01-30 00:32:04 +00:00
|
|
|
def describe(self) -> str:
|
|
|
|
def list_flows(flows: list["ResourceFlow"]) -> str:
|
|
|
|
return ", ".join(map(ResourceFlow.describe, flows))
|
|
|
|
|
|
|
|
return (
|
|
|
|
f"in machine: {self.factory.label}, "
|
|
|
|
f"ingredients: {list_flows(self.ingredients)}, "
|
|
|
|
f"results: {list_flows(self.results)}"
|
|
|
|
)
|
|
|
|
|
2024-01-29 17:37:30 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return f"Recipe(id={self.id}, factory={self.factory}, ingredients={self.ingredients}, results={self.results})"
|