working version?

This commit is contained in:
maxime 2026-02-24 22:14:36 +01:00
commit 44c5fbf284
26 changed files with 824 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.pyc
*.swp
*.swo

9
frontend/index.html Normal file
View File

@ -0,0 +1,9 @@
<html>
<head>
<link href="/static/css/main.css" rel="stylesheet" />
</head>
<body hx-trigger="load" hx-get="/app">
</body>
<script src="/static/js/htmx.min.js"></script>
<script>htmx.logAll();</script>
</html>

View File

@ -0,0 +1,22 @@
body {
}
.cat {
display: grid;
grid-template-columns: 20rem 1fr 1fr 1fr;
}
.cat > div {
display: block;
padding: 1em;
width: 10em;
}
.cat_header > div {
font-weight: bold;
}
.cat:nth-child(event) {
background-color:#f1f1f1;
}
.cat:nth-child(odd) {
background-color:#eaeaea;
}

1
frontend/static/js/htmx.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
{% include("templates/cat_form.html.j2") %}
{% include("templates/cat_list.html.j2") %}

View File

@ -0,0 +1,39 @@
<div class="cat">
<div class="cat_name">{{ cat.name }}</div>
<div class="cat_generation">{{ cat.generation_row.day }}</div>
<div class="cat_sex">
{{ cat.sex }}
</div>
<div class="cat_state">{{ cat.state }}</div>
<div class="cat_parent_a">
{% if cat.parent_a != None %}{{ cat_by_ids[cat.parent_a].name }}{% endif %}</div>
<div class="cat_parent_b">{% if cat.parent_b != None %}{{ cat_by_ids[cat.parent_b].name }}{% endif %}</div>
<div class="cat_stats">
<div class="cat_stat_str">STR: {{ cat.stat_str }} ({{ cat.stat_mod_str }})</div>
<div class="cat_stat_dex">DEX: {{ cat.stat_dex }} ({{ cat.stat_mod_dex }})</div>
<div class="cat_stat_con">CON: {{ cat.stat_con }} ({{ cat.stat_mod_con }})</div>
<div class="cat_stat_int">INT: {{ cat.stat_int }} ({{ cat.stat_mod_int }})</div>
<div class="cat_stat_spd">SPD: {{ cat.stat_spd }} ({{ cat.stat_mod_spd }})</div>
<div class="cat_stat_cha">CHA: {{ cat.stat_cha }} ({{ cat.stat_mod_cha }})</div>
<div class="cat_stat_lck">LCK: {{ cat.stat_lck }} ({{ cat.stat_mod_lck }})</div>
<div class="cat_stat_total">Total: {{
[cat.stat_str,
cat.stat_dex,
cat.stat_con,
cat.stat_int,
cat.stat_spd,
cat.stat_cha,
cat.stat_lck,
] | sum
}}</div>
</div>
<div class="cat_actions">
<div class="cat_edit_button">
<button hx-get="/hx/cat_form/{{ cat.id }}">Edit</button>
</div>
<div class="cat_delete_button">
<button class="delete_cat" value="{{ cat.id }}" hx-delete="/cat/{{ cat.id }}">Delete</button>
</div>
</div>
</div>

View File

@ -0,0 +1,55 @@
<div id="cat-form">
<form
hx-post="/cat"
hx-swap="none"
>
<h2>Generation</h2>
<label>Generation:
{% include "templates/generation_form.html.j2" with context %}
</label>
<h2>Cat</h2>
<label>Name: <input type="text" name="name" /></label>
<label>Sex:
<select name="sex">
<option value="UNDEF">?</option>
<option value="MALE">M</option>
<option value="FEMALE">F</option>
</select>
</label>
<label>Stat:
<select name="state">
<option value="BABY">Baby</option>
<option value="ADULT">Adult</option>
<option value="RETREAT">Retreated</option>
<option value="DEAD">Dead</option>
</select>
</label>
<h2>Parents</h2>
<label>A:
<select name="parent_a">
<option selected disabled value>Unset</option>
{% for cat in cats_parent %}
<option value="{{ cat.id }}">{{ cat.name }}</option>
{% endfor %}
</select>
</label>
<label>B:
<select name="parent_b">
<option selected disabled value>Unset</option>
{% for cat in cats_parent %}
<option value="{{ cat.id }}">{{ cat.name }}</option>
{% endfor %}
</select>
</label>
<h2>Stats</h2>
<label>STR: <input type="number" name="stat_str" value="0"/></label>
<label>DEX: <input type="number" name="stat_dex" value="0"/></label>
<label>CON: <input type="number" name="stat_con" value="0"/></label>
<label>INT: <input type="number" name="stat_int" value="0"/></label>
<label>SPD: <input type="number" name="stat_spd" value="0"/></label>
<label>CHA: <input type="number" name="stat_cha" value="0"/></label>
<label>LCK: <input type="number" name="stat_lck" value="0"/></label>
<input type="submit" value="Add cat" />
</form>
</div>

View File

@ -0,0 +1,66 @@
<div id="cat-form">
<form
hx-patch="/cat/{{ cat.id }}"
hx-swap="none"
>
<h2>Generation</h2>
<label>Generation:
{% include "templates/generation_form.html.j2" %}
</label>
<h2>Cat</h2>
<input type="hidden" name="id" value="{{ cat.id }}" />
<label>Name: <input type="text" name="name" value="{{ cat.name }}" /></label>
<label>Sex:
<select name="sex">
<option {% if cat.sex.name == 'UNDEF' %}selected{% endif %} value="UNDEF">?</option>
<option {% if cat.sex.name == 'MALE' %}selected{% endif %} value="MALE">M</option>
<option {% if cat.sex.name == 'FEMALE' %}selected{% endif %} value="FEMALE">F</option>
</select>
</label>
<label>Stat:
<select name="state" value="{{ cat.state.name }}">
<option {% if cat.state.name == 'BABY' %}selected{% endif %} value="BABY">Baby</option>
<option {% if cat.state.name == 'ADULT' %}selected{% endif %} value="ADULT">Adult</option>
<option {% if cat.state.name == 'RETREAT' %}selected{% endif %} value="RETREAT">Retreated</option>
<option {% if cat.state.name == 'DEAD' %}selected{% endif %} value="DEAD">Dead</option>
</select>
</label>
<h2>Parents</h2>
<label>A:
<select name="parent_a">
<option selected disabled value>Unset</option>
{% for parent_cat_a in cats_parent %}
<option
{% if parent_cat_a.id == cat.parent_a %}selected{% endif %}
value="{{ parent_cat_a.id }}"
>
{{ parent_cat_a.name }}
</option>
{% endfor %}
</select>
</label>
<label>B:
<select name="parent_b">
<option selected disabled value>Unset</option>
{% for parent_cat_b in cats_parent %}
<option
{% if parent_cat_b.id == cat.parent_b %}selected{% endif %}
value="{{ parent_cat_b.id }}"
>
{{ parent_cat_b.name }}
</option>
{% endfor %}
</select>
</label>
<h2>Stats</h2>
<label>STR: <input type="number" name="stat_str" value="{{ cat.stat_str }}"/></label>
<label>DEX: <input type="number" name="stat_dex" value="{{ cat.stat_dex }}"/></label>
<label>CON: <input type="number" name="stat_con" value="{{ cat.stat_con }}"/></label>
<label>INT: <input type="number" name="stat_int" value="{{ cat.stat_int }}"/></label>
<label>SPD: <input type="number" name="stat_spd" value="{{ cat.stat_spd }}"/></label>
<label>CHA: <input type="number" name="stat_cha" value="{{ cat.stat_cha }}"/></label>
<label>LCK: <input type="number" name="stat_lck" value="{{ cat.stat_lck }}"/></label>
<input type="submit" value="Update cat" />
</form>
</div>

View File

@ -0,0 +1,53 @@
<div
id="catlist"
>
<h1>Cat list ({{ cat_list | length }})</h1>
<div class="cat_header cat"
hx-get="/hx/cat_list"
hx-include="input[name='sortby'], input[name='state_filters']"
hx-target="#catlist_data"
hx-trigger="load, reloadCatList from:document, change, htmx:after-request from:(#cat-form form) queue: last"
>
<div>
<label>
Name
<input type="radio" name="sortby" value="name" />
</label>
</div>
<div>
Generation
<input type="radio" name="sortby" value="generation" />
</div>
<div>
Sex
<input type="radio" name="sortby" value="sex" />
</div>
<div>
State
<input type="radio" name="sortby" value="state" />
</div>
<div>
Parent A
<input type="radio" name="sortby" value="parent_a" />
</div>
<div>
Parent B
<input type="radio" name="sortby" value="parent_b" />
</div>
<div>
Stats
<input type="radio" name="sortby" value="stats" />
</div>
<div>
Filters<br/>
<label>Babys <input type="checkbox" name="state_filters" value="BABY" />
<label>Adults <input type="checkbox" name="state_filters" value="ADULT" />
<label>Retreated <input type="checkbox" name="state_filters" value="RETREAT" />
<label>Dead <input type="checkbox" name="state_filters" value="DEAD" />
</div>
</div>
<div
id="catlist_data"
>
</div>
-</div>

View File

@ -0,0 +1,4 @@
{% for cat in cat_list %}
{% include "templates/cat.html.j2" %}
{% endfor %}

View File

@ -0,0 +1,21 @@
<select
name="generation"
hx-post="/hx/generation/next"
hx-trigger="change[target.selectedOptions[0].value=='new']"
hx-on::after-request="document.location.reload()"
>
<option value="new">
New generation
</option>
{% for generation in generations %}
<option
{% if selected_generation == generation.id %}
selected
{% endif %}
value="{{ generation.id }}"
>
{{ generation.day }}
</option>
{% endfor %}
</select>

View File

@ -0,0 +1 @@
<option value="{{ value }}">{{ label }}</option>

View File

47
mewgenics_heredity/app.py Normal file
View File

@ -0,0 +1,47 @@
from litestar import Litestar, get
from litestar.plugins.sqlalchemy import AsyncSessionConfig, SQLAlchemyAsyncConfig, SQLAlchemyPlugin
from litestar.plugins.htmx import HTMXPlugin
from litestar.contrib.jinja import JinjaTemplateEngine
from litestar.template.config import TemplateConfig
from litestar.static_files import create_static_files_router
from pathlib import Path
from .config import config
from .controllers import CatController, FrontendController, GenerationController
from .middlewares import UrlEncodedMiddleware
session_config = AsyncSessionConfig(expire_on_commit=False)
sqlalchemy_config = SQLAlchemyAsyncConfig(
connection_string=config['db.url'],
session_config=session_config,
create_all=True
)
async def on_startup(app: Litestar) -> None:
async with sqlalchemy_config.get_session() as session:
pass
@get(path='/healthcheck')
async def healthcheck() -> str:
return 'hello world'
app = Litestar(
route_handlers=[
healthcheck,
create_static_files_router(path='/', directories=['frontend'], html_mode=True),
create_static_files_router(path='/static', directories=['frontend/static']),
FrontendController,
CatController,
GenerationController
],
on_startup=[on_startup],
debug=True,
plugins=[
SQLAlchemyPlugin(config=sqlalchemy_config),
HTMXPlugin()
],
template_config=TemplateConfig(
directory=[Path('frontend')],
engine=JinjaTemplateEngine
),
middleware=[UrlEncodedMiddleware()]
)

View File

@ -0,0 +1,3 @@
config = {
'db.url': 'postgresql+psycopg://localhost/mewgenics'
}

View File

@ -0,0 +1,90 @@
from uuid import UUID
from typing import Annotated
from litestar import Controller, get, post, patch, delete
from litestar.di import Provide
from litestar.enums import RequestEncodingType
from litestar.params import Parameter, Body
from litestar.plugins.htmx import TriggerEvent
from litestar.status_codes import HTTP_200_OK
from ..models import Cat, CatRepository, SexEnum, StateEnum
from ..models import Generation, GenerationRepository
class CatController(Controller):
dependencies={
'cats_repo': Provide(CatRepository.provider),
'generation_repo': Provide(GenerationRepository.provider)
}
@post(path='/cat')
async def post_cat(
self,
cats_repo: CatRepository,
generation_repo: GenerationRepository,
data: Annotated[Cat.create_type, Body(media_type=RequestEncodingType.URL_ENCODED)]
) -> Cat.type:
raw_data = data.model_dump(exclude_unset=True, exclude_none=True)
if isinstance(raw_data['sex'], str):
raw_data['sex'] = getattr(SexEnum, raw_data['sex'])
if isinstance(raw_data['state'], str):
raw_data['state'] = getattr(StateEnum, raw_data['state'])
new_obj = await cats_repo.add(Cat(**raw_data))
await cats_repo.session.commit()
return Cat.type.model_validate(new_obj)
@patch(path='/cat/{cat_id:uuid}')
async def patch_cat_by_id(
self,
cat_id: UUID,
cats_repo: CatRepository,
data: Annotated[Cat.type, Body(media_type=RequestEncodingType.URL_ENCODED)]
) -> Cat.type:
raw_data = data.model_dump(exclude_unset=True, exclude_none=True)
if isinstance(raw_data['sex'], str):
raw_data['sex'] = getattr(SexEnum, raw_data['sex'])
if isinstance(raw_data['state'], str):
raw_data['state'] = getattr(StateEnum, raw_data['state'])
raw_data['id'] = cat_id
new_obj = await cats_repo.update(Cat(**raw_data))
await cats_repo.session.commit()
return Cat.type.model_validate(new_obj)
@get(path='/cat/{cat_id:uuid}')
async def get_cat_by_id(
self,
cats_repo: CatRepository,
cat_id: UUID=Parameter(title='Cat ID')
) -> Cat.type:
return await cats_repo.get(cat_id)
@get(path='/cats')
async def get_cat_list(
self,
cats_repo: CatRepository,
) -> list[Cat]:
return await cats_repo.list()
@delete(path='/cat/{cat_id:uuid}', status_code=HTTP_200_OK)
async def delete_cat_by_id(
self,
cat_id: UUID,
cats_repo: CatRepository,
) -> TriggerEvent:
await cats_repo.delete(cat_id)
await cats_repo.session.commit()
return TriggerEvent(
content='Deleted cat',
name='reloadCatList',
after='receive'
)

View File

@ -0,0 +1,159 @@
from uuid import UUID
from litestar import Controller, get, post
from litestar.di import Provide
from litestar.response import Template
from litestar.plugins.htmx import HTMXRequest, HTMXTemplate
from advanced_alchemy.filters import OrderBy, LimitOffset, CollectionFilter
from pprint import pprint
from ..models import Cat, CatRepository, StateEnum, SexEnum
from ..models import Generation, GenerationRepository
class FrontendController(Controller):
dependencies={
'cats_repo': Provide(CatRepository.provider),
'generation_repo': Provide(GenerationRepository.provider)
}
@get(path='/app')
async def app_root(self,
request: HTMXRequest,
cats_repo: CatRepository,
generation_repo: GenerationRepository,
) -> Template:
cat_list = await cats_repo.list()
cats_parent = await cats_repo.list(
CollectionFilter(Cat.state, [StateEnum.ADULT, StateEnum.RETREAT])
)
generations = await generation_repo.list(OrderBy(Generation.day, 'desc'))
return HTMXTemplate(
template_name='templates/app.html.j2',
context={
'cat_list': cat_list,
'generations': generations,
'cats_parent': cats_parent,
'selected_generation': generations[0].id
}
)
@get(path='/hx/cat_list')
async def cat_list(
self,
cats_repo: CatRepository,
state_filters: list[str] | None = None,
sortby: str = 'name',
sortorder: str = 'asc',
) -> Template:
filters = []
if state_filters:
filters.append(
CollectionFilter(
Cat.state,
[
getattr(StateEnum, elt)
for elt in state_filters
]
)
)
elts = await cats_repo.list(
*filters,
OrderBy(sortby, sortorder)
)
all_cats = await cats_repo.list()
cats_by_ids = dict({
elt.id: elt
for elt in all_cats
})
return Template(
template_name='templates/cat_list_data.html.j2',
context={
'cat_list': elts,
'cat_by_ids': cats_by_ids
}
)
"""
@get(path='/hx/cat_form')
async def get_hx_cat_form(self,
cats_repo: CatRepository,
generation_repo: GenerationRepository
) -> Template:
cats = await cats_repo.list(
CollectionFilter(Cat.state, [StateEnum.ADULT, StateEnum.RETREAT])
)
generations = await generation_repo.list(OrderBy(Generation.day, 'desc'))
if len(generations) == 0:
await generation_repo.add(Generation(day=0))
await generation_repo.session.commit()
generations = await generation_repo.list(OrderBy(Generation.day, 'desc'))
return Template(
template_name='templates/cat_form.html.j2',
context={
'cats': cats,
'generations': generations,
'selected_generation': generations[0].id
}
)
"""
@get(path='/hx/cat_form/{cat_id:uuid}')
async def get_hx_cat_form_edit(self,
cat_id: UUID,
cats_repo: CatRepository,
generation_repo: GenerationRepository
) -> HTMXTemplate:
cat = await cats_repo.get(cat_id)
cats_parent = await cats_repo.list()
generations = await generation_repo.list(OrderBy(Generation.day, 'desc'))
return HTMXTemplate(
template_name='templates/cat_form_edit.html.j2',
context={
'cat': cat,
'cats_parent': cats_parent,
'generations': generations,
'selected_generation': cat.generation
},
re_target='#cat-form',
trigger_event='editCat',
after='receive'
)
@post(path='/hx/generation/next')
async def post_hx_generation_next(
self,
cats_repo: CatRepository,
generation_repo: GenerationRepository
) -> HTMXTemplate:
generations = await generation_repo.list(OrderBy(Generation.day, 'desc'))
next_day = 0 if len(generations) == 0 else generations[0].day + 1
new_obj = await generation_repo.add(Generation(day=next_day))
await generation_repo.session.commit()
await cats_repo.update_many(list(
map(
lambda cat: cat.grow(),
await cats_repo.list(Cat.state == StateEnum.BABY)
)
))
await cats_repo.session.commit()
generations = await generation_repo.list(OrderBy(Generation.day, 'desc'))
return HTMXTemplate(
template_name='templates/generation_form.html.j2',
context={
'generations': generations,
'selected_generation': new_obj.id
},
trigger_event="updateCats",
after="receive"
)

View File

@ -0,0 +1,35 @@
from uuid import UUID
from litestar import Controller, get, post
from litestar.di import Provide
from litestar.params import Parameter
from advanced_alchemy.filters import OrderBy, LimitOffset
from ..models import Generation, GenerationRepository
class GenerationController(Controller):
dependencies={
'generation_repo': Provide(GenerationRepository.provider)
}
@post(path='/generation')
async def post_generation(
self,
generation_repo: GenerationRepository,
data: Generation.create_type
) -> Generation.type:
new_obj = await generation_repo.add(Generation(**data.model_dump()))
await generation_repo.session.commit()
return Generation.type.model_validate(new_obj)
@post(path='/generation/next')
async def post_generation_next(
self,
generation_repo: GenerationRepository
) -> Generation.type:
last_generation = await generation_repo.list(OrderBy(Generation.day, 'desc'), LimitOffset(limit=1, offset=0))
next_day = 0 if len(last_generation) == 0 else last_generation.pop().day + 1
new_obj = await generation_repo.add(Generation(day=next_day))
await generation_repo.session.commit()
return Generation.type.model_validate(new_obj)

View File

@ -0,0 +1,4 @@
from .CatController import CatController
from .FrontendController import FrontendController
from .GenerationController import GenerationController

View File

@ -0,0 +1,23 @@
from litestar.types import Scope, Receive, Send, ASGIApp
from litestar.middleware import ASGIMiddleware
from litestar.enums import ScopeType
from litestar.datastructures import Headers
from pprint import pprint
class UrlEncodedMiddleware(ASGIMiddleware):
scopes = (ScopeType.HTTP,)
async def handle(
self,
scope: Scope,
receive: Receive,
send: Send,
next_app: ASGIApp
) -> None:
headers = Headers.from_scope(scope)
if scope['method'] in ['POST', 'PUT', 'PATCH'] and headers['Content-Type'] == 'application/x-www-form-urlencoded':
pass
await next_app(scope, receive, send)

View File

@ -0,0 +1 @@
from .UrlEncodedMiddleware import UrlEncodedMiddleware

View File

@ -0,0 +1,2 @@
from .cat import Cat, SexEnum, StateEnum, CatRepository
from .generation import Generation, GenerationRepository

View File

@ -0,0 +1,12 @@
from sqlalchemy import engine_from_config, create_engine
from ..config import config
from .base import Base
from .cat import Cat
engine = engine_from_config(configuration=config, prefix='db.', echo=True)
def initdb():
Base.metadata.create_all(engine)
if __name__ == '__main__':
initdb()

View File

@ -0,0 +1,7 @@
from litestar.plugins.sqlalchemy import base
from pydantic import BaseModel as _BaseModel
Base = base.UUIDBase
class BaseType(_BaseModel):
model_config = {'from_attributes': True}

View File

@ -0,0 +1,139 @@
import enum
from uuid import UUID
from typing import Optional
from litestar.plugins.sqlalchemy import repository
from sqlalchemy import String, Enum, ForeignKey, Integer, select
from sqlalchemy.orm import Mapped, mapped_column, selectinload, relationship
from sqlalchemy.ext.asyncio import AsyncSession
from .base import Base, BaseType
from .generation import Generation
class SexEnum(enum.Enum):
UNDEF=0
MALE=1
FEMALE=2
def __str__(self):
if self == SexEnum.UNDEF:
return '?'
elif self == SexEnum.MALE:
return 'M'
elif self == SexEnum.FEMALE:
return 'F'
class StateEnum(enum.Enum):
BABY=0
ADULT=1
RETREAT=2
DEAD=3
def __str__(self):
if self == StateEnum.BABY:
return 'Baby'
elif self == StateEnum.ADULT:
return 'Adult'
elif self == StateEnum.RETREAT:
return 'Retreated'
elif self == StateEnum.DEAD:
return 'Dead'
class Cat(Base):
__tablename__ = 'cats'
name: Mapped[str] = mapped_column(String(128))
sex: Mapped[SexEnum] = mapped_column(Enum(SexEnum))
state: Mapped[StateEnum] = mapped_column(Enum(StateEnum), default=StateEnum.BABY)
parent_a: Mapped[Optional[UUID]] = mapped_column(ForeignKey('cats.id'))
parent_b: Mapped[Optional[UUID]] = mapped_column(ForeignKey('cats.id'))
stat_str: Mapped[int] = mapped_column(Integer)
stat_dex: Mapped[int] = mapped_column(Integer)
stat_con: Mapped[int] = mapped_column(Integer)
stat_int: Mapped[int] = mapped_column(Integer)
stat_spd: Mapped[int] = mapped_column(Integer)
stat_cha: Mapped[int] = mapped_column(Integer)
stat_lck: Mapped[int] = mapped_column(Integer)
stat_mod_str: Mapped[int] = mapped_column(Integer, default=0)
stat_mod_dex: Mapped[int] = mapped_column(Integer, default=0)
stat_mod_con: Mapped[int] = mapped_column(Integer, default=0)
stat_mod_int: Mapped[int] = mapped_column(Integer, default=0)
stat_mod_spd: Mapped[int] = mapped_column(Integer, default=0)
stat_mod_cha: Mapped[int] = mapped_column(Integer, default=0)
stat_mod_lck: Mapped[int] = mapped_column(Integer, default=0)
generation_row: Mapped[Generation] = relationship(lazy="joined", innerjoin=True, viewonly=True)
generation: Mapped[UUID] = mapped_column(ForeignKey('generation.id'))
# level: Mapped[int] = mapped_column(Integer, default=0)
class type(BaseType):
id: UUID | None
name: str
sex: SexEnum | str
state: StateEnum | str
parent_a: UUID | None = None
parent_b: UUID | None = None
stat_str: int
stat_dex: int
stat_con: int
stat_int: int
stat_spd: int
stat_cha: int
stat_lck: int
stat_mod_str: int = 0
stat_mod_dex: int = 0
stat_mod_con: int = 0
stat_mod_int: int = 0
stat_mod_spd: int = 0
stat_mod_cha: int = 0
stat_mod_lck: int = 0
generation: UUID
# level: int = 0
class create_type(BaseType):
name: str
sex: SexEnum | str
state: StateEnum | str | None = StateEnum.BABY
parent_a: UUID | None = None
parent_b: UUID | None = None
stat_str: int
stat_dex: int
stat_con: int
stat_int: int
stat_spd: int
stat_cha: int
stat_lck: int
stat_mod_str: int | None = None
stat_mod_dex: int | None = None
stat_mod_con: int | None = None
stat_mod_int: int | None = None
stat_mod_spd: int | None = None
stat_mod_cha: int | None = None
stat_mod_lck: int | None = None
generation: UUID
# level: int | None = 0
def grow(self):
if self.state.value < StateEnum.DEAD.value:
self.state = StateEnum(self.state.value + 1)
return self
class CatRepository(repository.SQLAlchemyAsyncRepository[Cat]):
model_type = Cat
@classmethod
async def provider(cls, db_session: AsyncSession) -> CatRepository:
return CatRepository(
session=db_session,
statement=select(cls.model_type).options(selectinload(cls.model_type.generation_row))
)

View File

@ -0,0 +1,26 @@
from uuid import UUID
from litestar.plugins.sqlalchemy import repository
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.ext.asyncio import AsyncSession
from .base import Base, BaseType
class Generation(Base):
__tablename__ = 'generation'
day: Mapped[int] = mapped_column()
class type(BaseType):
id: UUID | None
day: int
class create_type(BaseType):
day: int
class GenerationRepository(repository.SQLAlchemyAsyncRepository[Generation]):
model_type = Generation
@staticmethod
async def provider(db_session: AsyncSession) -> GenerationRepository:
return GenerationRepository(session=db_session)