42 lines
1.7 KiB
Python
42 lines
1.7 KiB
Python
"""SQLAlchemy-backed per-user preferences repository."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
|
|
|
from deerflow.persistence.user_preferences.model import UserPreferencesRow
|
|
|
|
|
|
class UserPreferencesRepository:
|
|
def __init__(self, session_factory: async_sessionmaker[AsyncSession]) -> None:
|
|
self._sf = session_factory
|
|
|
|
async def get_for_user(self, user_id: str) -> dict[str, Any]:
|
|
"""Return the user's stored preferences (empty dict when none)."""
|
|
async with self._sf() as session:
|
|
row = await session.get(UserPreferencesRow, user_id)
|
|
if row is None or not isinstance(row.preferences, dict):
|
|
return {}
|
|
return dict(row.preferences)
|
|
|
|
async def merge_for_user(self, user_id: str, patch: dict[str, Any]) -> dict[str, Any]:
|
|
"""Shallow-merge ``patch`` into the user's preferences and return the result."""
|
|
now = datetime.now(UTC)
|
|
async with self._sf() as session:
|
|
row = await session.get(UserPreferencesRow, user_id)
|
|
if row is None:
|
|
merged = dict(patch)
|
|
row = UserPreferencesRow(user_id=user_id, preferences=merged, created_at=now, updated_at=now)
|
|
session.add(row)
|
|
else:
|
|
merged = dict(row.preferences or {})
|
|
merged.update(patch)
|
|
# Reassign so SQLAlchemy detects the change on the JSON column.
|
|
row.preferences = merged
|
|
row.updated_at = now
|
|
await session.commit()
|
|
return dict(merged)
|