Billing implements reserve -> commit -> refund against bl_quota and bl_ledger with row-level locking and idempotency keys; the refund commits on its own transaction so a failed request cannot silently keep a user's quota. Task implements the unified task centre over the state machine. Identity issues and resolves users. Remaining domains are placeholders whose READMEs state what belongs there and what must not.
38 lines
1.2 KiB
Python
Executable File
38 lines
1.2 KiB
Python
Executable File
"""Data access for the task domain. **Only this module may touch tk_task.**"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from packages.shared.models import Task
|
|
|
|
|
|
async def get(session: AsyncSession, task_id: int) -> Task | None:
|
|
return await session.get(Task, task_id)
|
|
|
|
|
|
async def get_for_update(session: AsyncSession, task_id: int) -> Task | None:
|
|
result = await session.execute(select(Task).where(Task.task_id == task_id).with_for_update())
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
async def find_by_idempotency_key(session: AsyncSession, key: str) -> Task | None:
|
|
result = await session.execute(select(Task).where(Task.idempotency_key == key))
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
async def list_for_user(session: AsyncSession, user_id: int, limit: int = 20) -> list[Task]:
|
|
result = await session.execute(
|
|
select(Task)
|
|
.where(Task.user_id == user_id)
|
|
.order_by(Task.submitted_at.desc(), Task.task_id.desc())
|
|
.limit(limit)
|
|
)
|
|
return list(result.scalars().all())
|
|
|
|
|
|
def add(session: AsyncSession, task: Task) -> Task:
|
|
session.add(task)
|
|
return task
|