feat(github): index connections by installation + status mutation

This commit is contained in:
Gabriel Brown
2026-07-11 14:07:57 -04:00
parent 18cb424b99
commit f7c3aa6482
3 changed files with 86 additions and 1 deletions
+26
View File
@@ -138,6 +138,32 @@ export const upsertConnectionForUser = internalMutation({
}, },
}); });
export const setConnectionStatusByInstallation = internalMutation({
args: {
installationId: v.string(),
status: v.union(
v.literal('active'),
v.literal('needs_reauth'),
v.literal('revoked'),
),
},
handler: async (ctx, { installationId, status }) => {
const connections = await ctx.db
.query('gitConnections')
.withIndex('by_installation', (q) =>
q.eq('installationId', installationId),
)
.collect();
const now = Date.now();
for (const connection of connections) {
await ctx.db.patch(connection._id, { status, updatedAt: now });
}
return { updated: connections.length };
},
});
export const createForkSpoonRecord = internalMutation({ export const createForkSpoonRecord = internalMutation({
args: { args: {
ownerId: v.id('users'), ownerId: v.id('users'),
+2 -1
View File
@@ -53,7 +53,8 @@ const applicationTables = {
}) })
.index('by_user', ['userId']) .index('by_user', ['userId'])
.index('by_user_provider', ['userId', 'provider']) .index('by_user_provider', ['userId', 'provider'])
.index('by_status', ['status']), .index('by_status', ['status'])
.index('by_installation', ['installationId']),
spoons: defineTable({ spoons: defineTable({
ownerId: v.id('users'), ownerId: v.id('users'),
name: v.string(), name: v.string(),
@@ -0,0 +1,58 @@
import { convexTest } from 'convex-test';
import { describe, expect, test } from 'vitest';
import { internal } from '../../convex/_generated/api.js';
import schema from '../../convex/schema';
const modules = import.meta.glob('../../convex/**/*.*s');
const seedConnection = async (
t: ReturnType<typeof convexTest>,
installationId: string,
) =>
await t.run(async (ctx) => {
const now = Date.now();
const userId = await ctx.db.insert('users', {
email: 'a@b.c',
name: 'A',
});
return await ctx.db.insert('gitConnections', {
userId,
provider: 'github',
displayName: `GitHub installation ${installationId}`,
installationId,
status: 'active',
connectedAt: now,
updatedAt: now,
});
});
describe('setConnectionStatusByInstallation', () => {
test('flips the matching connection status', async () => {
const t = convexTest(schema, modules);
const connectionId = await seedConnection(t, '42');
const result = await t.mutation(
internal.github.setConnectionStatusByInstallation,
{ installationId: '42', status: 'needs_reauth' },
);
expect(result).toEqual({ updated: 1 });
const connection = await t.run(async (ctx) => await ctx.db.get(connectionId));
expect(connection?.status).toBe('needs_reauth');
});
test('is a no-op when no connection matches', async () => {
const t = convexTest(schema, modules);
const connectionId = await seedConnection(t, '42');
const result = await t.mutation(
internal.github.setConnectionStatusByInstallation,
{ installationId: '999', status: 'revoked' },
);
expect(result).toEqual({ updated: 0 });
const connection = await t.run(async (ctx) => await ctx.db.get(connectionId));
expect(connection?.status).toBe('active');
});
});