import { describe, expect, it } from 'bun:test'; import { queryAcross } from './mail-scope'; // The merge is the part that can be silently wrong: a page with a hole in it looks like missing mail rather // than like a bug. These pin the property that makes it exact — each mailbox is asked for offset+limit. const mailbox = (dates: string[]) => ({ account: { id: dates.length, email: `a${dates.length}@x` }, db: {} as never, }) as never; describe('queryAcross', () => { const A = ['2026-08-10', '2026-08-08', '2026-08-02']; const B = ['2026-08-09', '2026-08-07', '2026-08-01']; const opened = [ { account: { id: 1, email: 'a@x' }, db: 'A' }, { account: { id: 2, email: 'b@x' }, db: 'B' }, ] as never as Parameters[0]; const run = (db: unknown, take: number) => ((db as unknown as string) === 'A' ? A : B).slice(0, take).map((date) => ({ date })); it('interleaves newest-first across mailboxes', () => { const rows = queryAcross(opened, run as never, { sortBy: (r) => String(r.date), limit: 4, offset: 0 }); expect(rows.map((r) => r.date)).toEqual(['2026-08-10', '2026-08-09', '2026-08-08', '2026-08-07']); }); it('labels every row with the mailbox it came from', () => { const rows = queryAcross(opened, run as never, { sortBy: (r) => String(r.date), limit: 2, offset: 0 }); expect(rows.map((r) => r.accountEmail)).toEqual(['a@x', 'b@x']); }); // The reason each mailbox is asked for offset+limit rather than limit: page 2 must not skip a row that // ranked low locally and high globally. it('pages without a hole', () => { const p1 = queryAcross(opened, run as never, { sortBy: (r) => String(r.date), limit: 2, offset: 0 }); const p2 = queryAcross(opened, run as never, { sortBy: (r) => String(r.date), limit: 2, offset: 2 }); const p3 = queryAcross(opened, run as never, { sortBy: (r) => String(r.date), limit: 2, offset: 4 }); expect([...p1, ...p2, ...p3].map((r) => r.date)).toEqual([...A, ...B].sort().reverse()); }); // The contract, pinned: local order must match merge order. A mailbox handing back rows in the wrong // direction breaks top-K silently, which is why the `descending` option was removed rather than fixed — // it flipped the merge while every caller's SQL still said ORDER BY date DESC. it('trusts each mailbox to be newest-first', () => { const backwards = (db: unknown, take: number) => ((db as unknown as string) === 'A' ? [...A].reverse() : [...B].reverse()) .slice(0, take) .map((date) => ({ date })); const rows = queryAcross(opened, backwards as never, { sortBy: (r) => String(r.date), limit: 2, offset: 0 }); // The true two newest are 08-10 and 08-09. Fed oldest-first mailboxes, the helper sorts correctly // within what it was handed and returns neither — no error, no gap, just quietly the wrong mail. That // is the failure the written contract exists to prevent, and it is why the `descending` option went. expect(rows.map((r) => r.date)).toEqual(['2026-08-08', '2026-08-07']); expect(rows.map((r) => r.date)).not.toContain('2026-08-10'); }); });