import { TableAggregate } from '@convex-dev/aggregate'
import { components, internal } from '../_generated/api'
import type { DataModel } from '../_generated/dataModel'
import type { QueryCtx } from '../_generated/server'
import { internalMutation } from '../_generated/server'
import { migrations } from '../migrations'
// Fame aggregate - tracks total fame score per user
const fameAggregate = new TableAggregate<{
Key: number // to_user_id
DataModel: DataModel
TableName: 'fame'
}>(components.fameAggregate, {
sortKey: (doc) => doc.to_user_id,
sumValue: (doc) => (doc.is_positive ? 1 : -1)
})
export const backfillFame = migrations.define({
table: 'fame',
migrateOne: async (ctx, doc) => {
// Update fameAggregate for each fame document
await fameAggregate.insertIfDoesNotExist(ctx, doc)
console.log(
'backfilled fame for user',
doc.to_user_id,
doc.is_positive ? '+1' : '-1'
)
}
})
export const clearFameAggregate = internalMutation({
args: {},
handler: async (ctx) => {
await fameAggregate.clear(ctx)
}
})
// Run this to backfill fame aggregates for existing data
export const runBackfillFame = migrations.runner(
internal.model.fame.backfillFame
)
export async function getFameTotal(
ctx: QueryCtx,
userId: number
): Promise<number> {
// Use aggregate for O(log n) fame total calculation
return await fameAggregate.sum(ctx, {
bounds: {
lower: { key: userId, inclusive: true },
upper: { key: userId, inclusive: true }
}
})
}
import { TableAggregate } from '@convex-dev/aggregate'
import { components, internal } from '../_generated/api'
import type { DataModel } from '../_generated/dataModel'
import type { QueryCtx } from '../_generated/server'
import { internalMutation } from '../_generated/server'
import { migrations } from '../migrations'
// Fame aggregate - tracks total fame score per user
const fameAggregate = new TableAggregate<{
Key: number // to_user_id
DataModel: DataModel
TableName: 'fame'
}>(components.fameAggregate, {
sortKey: (doc) => doc.to_user_id,
sumValue: (doc) => (doc.is_positive ? 1 : -1)
})
export const backfillFame = migrations.define({
table: 'fame',
migrateOne: async (ctx, doc) => {
// Update fameAggregate for each fame document
await fameAggregate.insertIfDoesNotExist(ctx, doc)
console.log(
'backfilled fame for user',
doc.to_user_id,
doc.is_positive ? '+1' : '-1'
)
}
})
export const clearFameAggregate = internalMutation({
args: {},
handler: async (ctx) => {
await fameAggregate.clear(ctx)
}
})
// Run this to backfill fame aggregates for existing data
export const runBackfillFame = migrations.runner(
internal.model.fame.backfillFame
)
export async function getFameTotal(
ctx: QueryCtx,
userId: number
): Promise<number> {
// Use aggregate for O(log n) fame total calculation
return await fameAggregate.sum(ctx, {
bounds: {
lower: { key: userId, inclusive: true },
upper: { key: userId, inclusive: true }
}
})
}