2026-05-09 21:33:48 +00:00
|
|
|
"""Upsert helper for wealthfolio account snapshots.
|
2026-05-07 17:06:19 +00:00
|
|
|
|
2026-05-09 21:33:48 +00:00
|
|
|
The actual read happens in `wealthfolio_pg.py` (against the
|
|
|
|
|
`wealthfolio_sync` PG mirror). This module keeps the upsert helper that
|
|
|
|
|
both prod and tests use, so callers can:
|
2026-05-07 17:06:19 +00:00
|
|
|
|
2026-05-09 21:33:48 +00:00
|
|
|
rows = await read_account_snapshots_from_pg(wf_session)
|
|
|
|
|
await upsert_snapshots(session, rows)
|
2026-05-07 17:06:19 +00:00
|
|
|
"""
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
|
|
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
|
|
|
|
from sqlalchemy.dialects.sqlite import insert as sqlite_insert
|
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
|
|
|
|
|
from fire_planner.db import AccountSnapshot
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _dialect_insert(session: AsyncSession) -> Any:
|
|
|
|
|
bind = session.get_bind()
|
|
|
|
|
if bind.dialect.name == "sqlite":
|
|
|
|
|
return sqlite_insert
|
|
|
|
|
return pg_insert
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def upsert_snapshots(session: AsyncSession, rows: list[dict[str, Any]]) -> int:
|
2026-05-09 21:33:48 +00:00
|
|
|
"""Idempotent upsert on `external_id` (one row per account per day)."""
|
2026-05-07 17:06:19 +00:00
|
|
|
if not rows:
|
|
|
|
|
return 0
|
|
|
|
|
insert_ = _dialect_insert(session)
|
|
|
|
|
stmt = insert_(AccountSnapshot).values(rows)
|
|
|
|
|
update_cols = {
|
|
|
|
|
"market_value": stmt.excluded.market_value,
|
|
|
|
|
"market_value_gbp": stmt.excluded.market_value_gbp,
|
|
|
|
|
"snapshot_date": stmt.excluded.snapshot_date,
|
|
|
|
|
"account_name": stmt.excluded.account_name,
|
|
|
|
|
"account_type": stmt.excluded.account_type,
|
2026-05-09 21:33:48 +00:00
|
|
|
"currency": stmt.excluded.currency,
|
|
|
|
|
"cost_basis_gbp": stmt.excluded.cost_basis_gbp,
|
2026-05-07 17:06:19 +00:00
|
|
|
}
|
|
|
|
|
stmt = stmt.on_conflict_do_update(index_elements=["external_id"], set_=update_cols)
|
|
|
|
|
await session.execute(stmt)
|
|
|
|
|
return len(rows)
|