Complete NextSteps roadmap: planning engine UI, calendar cluster, flexible wishes
Works through every numbered item in NextSteps260913.md section 3, plus the three known verification issues in section 4.1. Surface what the backend already computed: - 3.1 render surplus_advice in PlanResults, mirroring the shortfall remedies - 3.2 surface VacationBalance.is_assumed so assumed statutory years are visible - 3.3 age-4 expiry given the proposed plan, via a new Age4Projection reusing the existing _age4_projections arithmetic (Dashboard stat verified, not rebuilt) Calendar cluster (one pass over the holiday data): - new GET /api/calendar/days exposing roda dagar, klamdagar and day overrides, paginated four years at a time - 3.4 shade roda dagar/klamdagar, with R/K badges so colour is not the only signal - 3.6 click-to-override behind an explicit mode toggle, leaving drag multi-select intact - 3.7 click month/year to advance - 3.8 per-year red-days list in Settings, statutory days plus overrides i18n: - 3.5 five backend-generated Swedish surfaces converted to message_key + data, following the tips_service pattern; old string fields replaced, not kept Flexible wishes (3.9): - PLANNING_ENGINE_SPEC section 10: window_mode, candidate search, cost function, deterministic tie-break, two-pass ordering, test matrix rows 15-24 - backend: entity, migration 006, _FULL_SCHEMA sync, repository, allocator - frontend: season-preset toggle in WishEditor, unplaced outcome rendering Fixes (4.1): - pin typecheck to the local tsc rather than npx resolving a newer TypeScript - ignore generated coverage/ and dist/ in the ESLint flat config - fix the flaky usePlanApply test properly, with waitFor rather than a retry Tests: backend 361 -> 404, frontend 540 -> 704. Coverage 89.47% -> 96.52% lines. Not yet verified in a browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RXMhc9nT6sNz1SL4j8dznL
This commit is contained in:
@@ -1,115 +0,0 @@
|
||||
"""SQLite implementation of BreakPeriodRepository.
|
||||
|
||||
Handles the break_period table with date fields (start_date, end_date).
|
||||
"""
|
||||
|
||||
from datetime import date, datetime
|
||||
from uuid import UUID
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from app.entities.break_period import BreakPeriod
|
||||
from app.repositories.break_period_repository import BreakPeriodRepository
|
||||
from app.utils.errors import NotFoundError
|
||||
|
||||
|
||||
class SQLiteBreakPeriodRepository(BreakPeriodRepository):
|
||||
def __init__(self, connection: aiosqlite.Connection) -> None:
|
||||
self._conn = connection
|
||||
|
||||
@staticmethod
|
||||
def _row_to_entity(row: aiosqlite.Row) -> BreakPeriod:
|
||||
return BreakPeriod(
|
||||
id=UUID(row["id"]),
|
||||
workspace_id=UUID(row["workspace_id"]),
|
||||
name=row["name"],
|
||||
start_date=date.fromisoformat(row["start_date"]),
|
||||
end_date=date.fromisoformat(row["end_date"]),
|
||||
target_weeks=row["target_weeks"],
|
||||
created_at=datetime.fromisoformat(row["created_at"]),
|
||||
updated_at=datetime.fromisoformat(row["updated_at"]),
|
||||
)
|
||||
|
||||
async def create(self, item: BreakPeriod) -> BreakPeriod:
|
||||
now = datetime.now()
|
||||
item.created_at = item.created_at or now
|
||||
item.updated_at = now
|
||||
await self._conn.execute(
|
||||
"""
|
||||
INSERT INTO break_period
|
||||
(id, workspace_id, name, start_date, end_date, target_weeks,
|
||||
created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
str(item.id),
|
||||
str(item.workspace_id),
|
||||
item.name,
|
||||
item.start_date.isoformat(),
|
||||
item.end_date.isoformat(),
|
||||
item.target_weeks,
|
||||
item.created_at.isoformat(),
|
||||
item.updated_at.isoformat(),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
return item
|
||||
|
||||
async def get_by_id(self, id: UUID) -> BreakPeriod | None:
|
||||
cursor = await self._conn.execute("SELECT * FROM break_period WHERE id = ?", (str(id),))
|
||||
row = await cursor.fetchone()
|
||||
return self._row_to_entity(row) if row else None
|
||||
|
||||
async def get_by_workspace(self, workspace_id: UUID) -> list[BreakPeriod]:
|
||||
cursor = await self._conn.execute(
|
||||
"SELECT * FROM break_period WHERE workspace_id = ? ORDER BY start_date ASC",
|
||||
(str(workspace_id),),
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [self._row_to_entity(row) for row in rows]
|
||||
|
||||
async def update(self, id: UUID, item: BreakPeriod) -> BreakPeriod:
|
||||
item.updated_at = datetime.now()
|
||||
cursor = await self._conn.execute(
|
||||
"""
|
||||
UPDATE break_period
|
||||
SET name = ?, start_date = ?, end_date = ?, target_weeks = ?,
|
||||
updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
item.name,
|
||||
item.start_date.isoformat(),
|
||||
item.end_date.isoformat(),
|
||||
item.target_weeks,
|
||||
item.updated_at.isoformat(),
|
||||
str(id),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise NotFoundError(f"BreakPeriod {id} not found")
|
||||
refreshed = await self.get_by_id(id)
|
||||
assert refreshed is not None # just updated
|
||||
return refreshed
|
||||
|
||||
async def delete(self, id: UUID) -> None:
|
||||
cursor = await self._conn.execute("DELETE FROM break_period WHERE id = ?", (str(id),))
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise NotFoundError(f"BreakPeriod {id} not found")
|
||||
|
||||
async def list(self, **filters: object) -> list[BreakPeriod]:
|
||||
clauses: list[str] = []
|
||||
params: list[object] = []
|
||||
for column in ("workspace_id",):
|
||||
if column in filters and filters[column] is not None:
|
||||
value = filters[column]
|
||||
clauses.append(f"{column} = ?")
|
||||
params.append(str(value) if isinstance(value, UUID) else value)
|
||||
where = f" WHERE {' AND '.join(clauses)}" if clauses else ""
|
||||
cursor = await self._conn.execute(
|
||||
f"SELECT * FROM break_period{where} ORDER BY start_date ASC", params
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [self._row_to_entity(row) for row in rows]
|
||||
@@ -26,6 +26,7 @@ class SQLiteChildRepository(ChildRepository):
|
||||
if row["preschool_start_date"]
|
||||
else None
|
||||
),
|
||||
preschool_planning_days_per_year=row["preschool_planning_days_per_year"],
|
||||
created_at=datetime.fromisoformat(row["created_at"]),
|
||||
)
|
||||
|
||||
@@ -33,8 +34,10 @@ class SQLiteChildRepository(ChildRepository):
|
||||
item.created_at = item.created_at or datetime.now()
|
||||
await self._conn.execute(
|
||||
"""
|
||||
INSERT INTO child (id, workspace_id, name, birth_date, preschool_start_date, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO child
|
||||
(id, workspace_id, name, birth_date, preschool_start_date,
|
||||
preschool_planning_days_per_year, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
str(item.id),
|
||||
@@ -42,6 +45,7 @@ class SQLiteChildRepository(ChildRepository):
|
||||
item.name,
|
||||
item.birth_date.isoformat(),
|
||||
item.preschool_start_date.isoformat() if item.preschool_start_date else None,
|
||||
item.preschool_planning_days_per_year,
|
||||
item.created_at.isoformat(),
|
||||
),
|
||||
)
|
||||
@@ -57,13 +61,15 @@ class SQLiteChildRepository(ChildRepository):
|
||||
cursor = await self._conn.execute(
|
||||
"""
|
||||
UPDATE child
|
||||
SET name = ?, birth_date = ?, preschool_start_date = ?
|
||||
SET name = ?, birth_date = ?, preschool_start_date = ?,
|
||||
preschool_planning_days_per_year = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
item.name,
|
||||
item.birth_date.isoformat(),
|
||||
item.preschool_start_date.isoformat() if item.preschool_start_date else None,
|
||||
item.preschool_planning_days_per_year,
|
||||
str(id),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
"""SQLite implementation of DayOverrideRepository.
|
||||
|
||||
Follows the VacationDaysRepository reference shape: map rows <-> entities
|
||||
explicitly in `_row_to_entity`, always parameterize queries, raise
|
||||
NotFoundError from update/delete when the row is missing.
|
||||
"""
|
||||
|
||||
from datetime import date, datetime
|
||||
from uuid import UUID
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from app.entities.day_override import DayOverride
|
||||
from app.repositories.day_override_repository import DayOverrideRepository
|
||||
from app.utils.errors import NotFoundError
|
||||
|
||||
|
||||
class SQLiteDayOverrideRepository(DayOverrideRepository):
|
||||
def __init__(self, connection: aiosqlite.Connection) -> None:
|
||||
self._conn = connection
|
||||
|
||||
@staticmethod
|
||||
def _row_to_entity(row: aiosqlite.Row) -> DayOverride:
|
||||
return DayOverride(
|
||||
id=UUID(row["id"]),
|
||||
workspace_id=UUID(row["workspace_id"]),
|
||||
date=date.fromisoformat(row["date"]),
|
||||
is_working_day=bool(row["is_working_day"]),
|
||||
note=row["note"],
|
||||
created_at=datetime.fromisoformat(row["created_at"]),
|
||||
updated_at=datetime.fromisoformat(row["updated_at"]),
|
||||
)
|
||||
|
||||
async def create(self, item: DayOverride) -> DayOverride:
|
||||
now = datetime.now()
|
||||
item.created_at = item.created_at or now
|
||||
item.updated_at = now
|
||||
await self._conn.execute(
|
||||
"""
|
||||
INSERT INTO day_override
|
||||
(id, workspace_id, date, is_working_day, note, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
str(item.id),
|
||||
str(item.workspace_id),
|
||||
item.date.isoformat(),
|
||||
int(item.is_working_day),
|
||||
item.note,
|
||||
item.created_at.isoformat(),
|
||||
item.updated_at.isoformat(),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
return item
|
||||
|
||||
async def get_by_id(self, id: UUID) -> DayOverride | None:
|
||||
cursor = await self._conn.execute("SELECT * FROM day_override WHERE id = ?", (str(id),))
|
||||
row = await cursor.fetchone()
|
||||
return self._row_to_entity(row) if row else None
|
||||
|
||||
async def get_by_workspace_date(self, workspace_id: UUID, day: date) -> DayOverride | None:
|
||||
cursor = await self._conn.execute(
|
||||
"SELECT * FROM day_override WHERE workspace_id = ? AND date = ?",
|
||||
(str(workspace_id), day.isoformat()),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
return self._row_to_entity(row) if row else None
|
||||
|
||||
async def update(self, id: UUID, item: DayOverride) -> DayOverride:
|
||||
item.updated_at = datetime.now()
|
||||
cursor = await self._conn.execute(
|
||||
"""
|
||||
UPDATE day_override
|
||||
SET is_working_day = ?, note = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(int(item.is_working_day), item.note, item.updated_at.isoformat(), str(id)),
|
||||
)
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise NotFoundError(f"DayOverride {id} not found")
|
||||
refreshed = await self.get_by_id(id)
|
||||
assert refreshed is not None # just updated
|
||||
return refreshed
|
||||
|
||||
async def delete(self, id: UUID) -> None:
|
||||
cursor = await self._conn.execute("DELETE FROM day_override WHERE id = ?", (str(id),))
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise NotFoundError(f"DayOverride {id} not found")
|
||||
|
||||
async def list(self, **filters: object) -> list[DayOverride]:
|
||||
clauses: list[str] = []
|
||||
params: list[object] = []
|
||||
for column in ("workspace_id",):
|
||||
if column in filters and filters[column] is not None:
|
||||
value = filters[column]
|
||||
clauses.append(f"{column} = ?")
|
||||
params.append(str(value) if isinstance(value, UUID) else value)
|
||||
where = f" WHERE {' AND '.join(clauses)}" if clauses else ""
|
||||
cursor = await self._conn.execute(
|
||||
f"SELECT * FROM day_override{where} ORDER BY date ASC", params
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [self._row_to_entity(row) for row in rows]
|
||||
|
||||
async def list_by_workspace(self, workspace_id: UUID) -> list[DayOverride]:
|
||||
return await self.list(workspace_id=workspace_id)
|
||||
@@ -0,0 +1,171 @@
|
||||
"""SQLite implementation of LeaveWishRepository.
|
||||
|
||||
Handles the leave_wish table. The recurring window is stored as month/day
|
||||
integers (not dates) so it can repeat yearly (see app/entities/leave_wish.py).
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
import aiosqlite
|
||||
|
||||
from app.entities.leave_wish import LeaveWish
|
||||
from app.repositories.leave_wish_repository import LeaveWishRepository
|
||||
from app.utils.errors import NotFoundError
|
||||
|
||||
|
||||
class SQLiteLeaveWishRepository(LeaveWishRepository):
|
||||
def __init__(self, connection: aiosqlite.Connection) -> None:
|
||||
self._conn = connection
|
||||
|
||||
@staticmethod
|
||||
def _row_to_entity(row: aiosqlite.Row) -> LeaveWish:
|
||||
return LeaveWish(
|
||||
id=UUID(row["id"]),
|
||||
workspace_id=UUID(row["workspace_id"]),
|
||||
child_id=UUID(row["child_id"]) if row["child_id"] is not None else None,
|
||||
name=row["name"],
|
||||
window_start_month=row["window_start_month"],
|
||||
window_start_day=row["window_start_day"],
|
||||
window_end_month=row["window_end_month"],
|
||||
window_end_day=row["window_end_day"],
|
||||
target_weeks=row["target_weeks"],
|
||||
recurrence=row["recurrence"],
|
||||
first_year=row["first_year"],
|
||||
last_year=row["last_year"],
|
||||
priority=row["priority"],
|
||||
parent_mode=row["parent_mode"],
|
||||
parent_personal_data_uuid=(
|
||||
UUID(row["parent_personal_data_uuid"])
|
||||
if row["parent_personal_data_uuid"] is not None
|
||||
else None
|
||||
),
|
||||
goal_override=row["goal_override"],
|
||||
window_mode=row["window_mode"],
|
||||
created_at=datetime.fromisoformat(row["created_at"]),
|
||||
updated_at=datetime.fromisoformat(row["updated_at"]),
|
||||
)
|
||||
|
||||
async def create(self, item: LeaveWish) -> LeaveWish:
|
||||
now = datetime.now()
|
||||
item.created_at = item.created_at or now
|
||||
item.updated_at = now
|
||||
await self._conn.execute(
|
||||
"""
|
||||
INSERT INTO leave_wish
|
||||
(id, workspace_id, child_id, name,
|
||||
window_start_month, window_start_day, window_end_month, window_end_day,
|
||||
target_weeks, recurrence, first_year, last_year,
|
||||
priority, parent_mode, parent_personal_data_uuid, goal_override,
|
||||
window_mode, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
str(item.id),
|
||||
str(item.workspace_id),
|
||||
str(item.child_id) if item.child_id is not None else None,
|
||||
item.name,
|
||||
item.window_start_month,
|
||||
item.window_start_day,
|
||||
item.window_end_month,
|
||||
item.window_end_day,
|
||||
item.target_weeks,
|
||||
item.recurrence,
|
||||
item.first_year,
|
||||
item.last_year,
|
||||
item.priority,
|
||||
item.parent_mode,
|
||||
(
|
||||
str(item.parent_personal_data_uuid)
|
||||
if item.parent_personal_data_uuid is not None
|
||||
else None
|
||||
),
|
||||
item.goal_override,
|
||||
item.window_mode,
|
||||
item.created_at.isoformat(),
|
||||
item.updated_at.isoformat(),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
return item
|
||||
|
||||
async def get_by_id(self, id: UUID) -> LeaveWish | None:
|
||||
cursor = await self._conn.execute("SELECT * FROM leave_wish WHERE id = ?", (str(id),))
|
||||
row = await cursor.fetchone()
|
||||
return self._row_to_entity(row) if row else None
|
||||
|
||||
async def get_by_workspace(self, workspace_id: UUID) -> list[LeaveWish]:
|
||||
cursor = await self._conn.execute(
|
||||
"SELECT * FROM leave_wish WHERE workspace_id = ? "
|
||||
"ORDER BY priority ASC, first_year ASC, window_start_month ASC, window_start_day ASC",
|
||||
(str(workspace_id),),
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [self._row_to_entity(row) for row in rows]
|
||||
|
||||
async def update(self, id: UUID, item: LeaveWish) -> LeaveWish:
|
||||
item.updated_at = datetime.now()
|
||||
cursor = await self._conn.execute(
|
||||
"""
|
||||
UPDATE leave_wish
|
||||
SET child_id = ?, name = ?,
|
||||
window_start_month = ?, window_start_day = ?,
|
||||
window_end_month = ?, window_end_day = ?,
|
||||
target_weeks = ?, recurrence = ?, first_year = ?, last_year = ?,
|
||||
priority = ?, parent_mode = ?, parent_personal_data_uuid = ?,
|
||||
goal_override = ?, window_mode = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
str(item.child_id) if item.child_id is not None else None,
|
||||
item.name,
|
||||
item.window_start_month,
|
||||
item.window_start_day,
|
||||
item.window_end_month,
|
||||
item.window_end_day,
|
||||
item.target_weeks,
|
||||
item.recurrence,
|
||||
item.first_year,
|
||||
item.last_year,
|
||||
item.priority,
|
||||
item.parent_mode,
|
||||
(
|
||||
str(item.parent_personal_data_uuid)
|
||||
if item.parent_personal_data_uuid is not None
|
||||
else None
|
||||
),
|
||||
item.goal_override,
|
||||
item.window_mode,
|
||||
item.updated_at.isoformat(),
|
||||
str(id),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise NotFoundError(f"LeaveWish {id} not found")
|
||||
refreshed = await self.get_by_id(id)
|
||||
assert refreshed is not None # just updated
|
||||
return refreshed
|
||||
|
||||
async def delete(self, id: UUID) -> None:
|
||||
cursor = await self._conn.execute("DELETE FROM leave_wish WHERE id = ?", (str(id),))
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise NotFoundError(f"LeaveWish {id} not found")
|
||||
|
||||
async def list(self, **filters: object) -> list[LeaveWish]:
|
||||
clauses: list[str] = []
|
||||
params: list[object] = []
|
||||
for column in ("workspace_id", "child_id"):
|
||||
if column in filters and filters[column] is not None:
|
||||
value = filters[column]
|
||||
clauses.append(f"{column} = ?")
|
||||
params.append(str(value) if isinstance(value, UUID) else value)
|
||||
where = f" WHERE {' AND '.join(clauses)}" if clauses else ""
|
||||
cursor = await self._conn.execute(
|
||||
f"SELECT * FROM leave_wish{where} "
|
||||
"ORDER BY priority ASC, first_year ASC, window_start_month ASC, window_start_day ASC",
|
||||
params,
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return [self._row_to_entity(row) for row in rows]
|
||||
@@ -26,6 +26,7 @@ class SQLitePersonalDataRepository(PersonalDataRepository):
|
||||
name=row["name"],
|
||||
salary_type=row["salary_type"],
|
||||
employment_status=row["employment_status"],
|
||||
min_vacation_days_per_year=row["min_vacation_days_per_year"],
|
||||
personnummer_enc=row["personnummer_enc"],
|
||||
created_at=datetime.fromisoformat(row["created_at"]),
|
||||
deleted_at=datetime.fromisoformat(row["deleted_at"]) if row["deleted_at"] else None,
|
||||
@@ -38,8 +39,8 @@ class SQLitePersonalDataRepository(PersonalDataRepository):
|
||||
"""
|
||||
INSERT INTO personal_data
|
||||
(uuid, workspace_id, name, salary_type, employment_status,
|
||||
personnummer_enc, created_at, deleted_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
min_vacation_days_per_year, personnummer_enc, created_at, deleted_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
str(item.uuid),
|
||||
@@ -47,6 +48,7 @@ class SQLitePersonalDataRepository(PersonalDataRepository):
|
||||
item.name,
|
||||
item.salary_type,
|
||||
item.employment_status,
|
||||
item.min_vacation_days_per_year,
|
||||
item.personnummer_enc,
|
||||
item.created_at.isoformat(),
|
||||
item.deleted_at.isoformat() if item.deleted_at else None,
|
||||
@@ -68,10 +70,17 @@ class SQLitePersonalDataRepository(PersonalDataRepository):
|
||||
"""
|
||||
UPDATE personal_data
|
||||
SET name = ?, salary_type = ?, employment_status = ?,
|
||||
personnummer_enc = ?
|
||||
min_vacation_days_per_year = ?, personnummer_enc = ?
|
||||
WHERE uuid = ? AND deleted_at IS NULL
|
||||
""",
|
||||
(item.name, item.salary_type, item.employment_status, item.personnummer_enc, str(id)),
|
||||
(
|
||||
item.name,
|
||||
item.salary_type,
|
||||
item.employment_status,
|
||||
item.min_vacation_days_per_year,
|
||||
item.personnummer_enc,
|
||||
str(id),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
|
||||
@@ -24,14 +24,24 @@ class SQLiteWorkspaceRepository(WorkspaceRepository):
|
||||
id=UUID(row["id"]),
|
||||
name=row["name"],
|
||||
planning_goal=row["planning_goal"],
|
||||
planning_mode=row["planning_mode"],
|
||||
created_at=datetime.fromisoformat(row["created_at"]),
|
||||
)
|
||||
|
||||
async def create(self, item: Workspace) -> Workspace:
|
||||
item.created_at = item.created_at or datetime.now()
|
||||
await self._conn.execute(
|
||||
"INSERT INTO workspace (id, name, planning_goal, created_at) VALUES (?, ?, ?, ?)",
|
||||
(str(item.id), item.name, item.planning_goal, item.created_at.isoformat()),
|
||||
"""
|
||||
INSERT INTO workspace (id, name, planning_goal, planning_mode, created_at)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
str(item.id),
|
||||
item.name,
|
||||
item.planning_goal,
|
||||
item.planning_mode,
|
||||
item.created_at.isoformat(),
|
||||
),
|
||||
)
|
||||
await self._conn.commit()
|
||||
return item
|
||||
@@ -43,8 +53,8 @@ class SQLiteWorkspaceRepository(WorkspaceRepository):
|
||||
|
||||
async def update(self, id: UUID, item: Workspace) -> Workspace:
|
||||
cursor = await self._conn.execute(
|
||||
"UPDATE workspace SET name = ?, planning_goal = ? WHERE id = ?",
|
||||
(item.name, item.planning_goal, str(id)),
|
||||
"UPDATE workspace SET name = ?, planning_goal = ?, planning_mode = ? WHERE id = ?",
|
||||
(item.name, item.planning_goal, item.planning_mode, str(id)),
|
||||
)
|
||||
await self._conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
|
||||
Reference in New Issue
Block a user