fix(convex): order spoonCommits by committedAt via index so bounding keeps newest

This commit is contained in:
Gabriel Brown
2026-07-11 14:41:31 -04:00
parent 9067d16734
commit bce6769277
3 changed files with 57 additions and 4 deletions
@@ -108,6 +108,33 @@ describe('spoonCommits.listForSpoon (no side) bounded + merged', () => {
expect(times).toEqual([...times].sort((a, b) => b - a));
});
test('keeps the true newest-N per side when a side exceeds the limit', async () => {
const t = convexTest(schema, modules);
const ownerId = await createUser(t, 'owner@example.com');
const spoonId = await seedSpoon(t, ownerId);
// One side holds MORE commits than the limit, inserted in NON-monotonic
// committedAt order (so DB creation order != committedAt order). A query
// that bounds by insertion/_creationTime order would drop the true newest
// commit (500). Only ordering by committedAt keeps the real top-3.
await seedCommits(t, spoonId, ownerId, [
{ side: 'upstream', committedAt: 500, sha: 'u500' },
{ side: 'upstream', committedAt: 100, sha: 'u100' },
{ side: 'upstream', committedAt: 200, sha: 'u200' },
{ side: 'upstream', committedAt: 300, sha: 'u300' },
{ side: 'upstream', committedAt: 400, sha: 'u400' },
]);
const result = await authed(t, ownerId).query(
api.spoonCommits.listForSpoon,
{ spoonId, limit: 3 },
);
// True top-3 by committedAt desc. The buggy index (by_spoon_side, ordered
// by _creationTime) would instead return the last-3-inserted [400,300,200].
expect(result.map((c) => c.sha)).toEqual(['u500', 'u400', 'u300']);
});
test('returns all rows when under the limit', async () => {
const t = convexTest(schema, modules);
const ownerId = await createUser(t, 'owner@example.com');
@@ -148,6 +175,31 @@ describe('spoonCommits.listForSpoon (no side) bounded + merged', () => {
});
});
describe('spoonCommits.listForSpoon (single side) bounded', () => {
test('keeps the true newest-N when the side exceeds the limit', async () => {
const t = convexTest(schema, modules);
const ownerId = await createUser(t, 'owner@example.com');
const spoonId = await seedSpoon(t, ownerId);
// Non-monotonic insertion order so _creationTime order != committedAt.
await seedCommits(t, spoonId, ownerId, [
{ side: 'fork', committedAt: 500, sha: 'f500' },
{ side: 'fork', committedAt: 100, sha: 'f100' },
{ side: 'fork', committedAt: 200, sha: 'f200' },
{ side: 'fork', committedAt: 300, sha: 'f300' },
{ side: 'fork', committedAt: 400, sha: 'f400' },
]);
const result = await authed(t, ownerId).query(
api.spoonCommits.listForSpoon,
{ spoonId, side: 'fork', limit: 3 },
);
// True top-3 by committedAt desc, not the last-3-inserted [400,300,200].
expect(result.map((c) => c.sha)).toEqual(['f500', 'f400', 'f300']);
});
});
const seedJobs = async (
t: ReturnType<typeof convexTest>,
spoonId: Id<'spoons'>,