"""One-off: add split-address tokens to existing messages' FTS vector. New messages get address parts indexed via `_doc_text_blob` (so a bare "wfdif" finds dyrektor@wfdif.com.pl). This backfills that into already-indexed rows by appending the split-address lexemes to `body_indexed`. Idempotent — tsvector concat merges duplicate lexemes, so re-running is harmless. Run: python -m scripts.reindex_address_parts """ from __future__ import annotations import asyncio from sqlalchemy import func, select, update from app.db import get_sessionmaker from app.models import Message from app.search.pg import _TS_CONFIG, _email_parts def _address_parts_blob(msg: Message) -> str: parts: list[str] = [] for field in (msg.from_addr, msg.to_addr, msg.cc_addr): for addr in field: email = addr.get("email", "") if email: parts.append(_email_parts(email)) return " ".join(parts) async def main() -> None: sm = get_sessionmaker() updated = 0 async with sm() as session: msgs = list(await session.scalars(select(Message).where(Message.body_indexed.is_not(None)))) for msg in msgs: blob = _address_parts_blob(msg) if not blob: continue await session.execute( update(Message) .where(Message.id == msg.id) .values( body_indexed=Message.body_indexed.op("||")( func.to_tsvector(_TS_CONFIG, blob) ) ) ) updated += 1 await session.commit() print(f"reindexed address parts into {updated} messages") if __name__ == "__main__": asyncio.run(main())