feat(github): index connections by installation + status mutation
This commit is contained in:
@@ -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({
|
||||
args: {
|
||||
ownerId: v.id('users'),
|
||||
|
||||
@@ -53,7 +53,8 @@ const applicationTables = {
|
||||
})
|
||||
.index('by_user', ['userId'])
|
||||
.index('by_user_provider', ['userId', 'provider'])
|
||||
.index('by_status', ['status']),
|
||||
.index('by_status', ['status'])
|
||||
.index('by_installation', ['installationId']),
|
||||
spoons: defineTable({
|
||||
ownerId: v.id('users'),
|
||||
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');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user