Sorry for the late reply but thanks for the suggestions! I wasn't able to figure out how to get the [Id<'anime>, boolean] method working so I ended up going with just do a check before inserting into the aggregate (I'm also looking into triggers). I was wondering if this was a good approach overall?
convex/lib/aggregates.ts
export const animeStatsByEntry = new TableAggregate<{
Namespace: Id<'anime'>
Key: null
DataModel: DataModel
TableName: 'anime_entries'
}>(components.aggregateByAnime, {
namespace: doc => doc.animeId,
sortKey: _ => null,
sumValue: doc => doc.rating!
})
convex/functions/anime.ts
export const getBySlug = query({
args: { slug: v.string },
handler: async (ctx, args) => {
const anime = await ctx.db
.query('anime')
.withIndex('by_slug', q => q.eq('slug', args.slug))
.first()
if (!anime) return null
const opts = {
namespace: anime._id,
bounds: {
lower: undefined,
upper: undefined
}
}
return {
...anime,
rating:
(await animeStatsByEntry.sum(ctx, opts)) /
(await animeStatsByEntry.count(ctx, opts))
}
}
})
convex/functions/anime_entries.ts
async function insertRatingAggregate(
ctx: MutationCtx,
entryId: Id<'anime_entries'>
) {
const createdEntry = await ctx.db.get(entryId)
if (!createdEntry) throw new ConvexError('Failed to get created entry')
await animeStatsByEntry.insert(ctx, createdEntry)
}
export const createEditorEntry = authRLSMutation({
args: {
lists: v.array(v.id('lists')),
entry: v.object(AnimeEntries.withoutSystemFields)
},
handler: async (ctx, args) => {
const { lists, entry } = args
const entryId = await ctx.db.insert('anime_entries', entry)
if (entry.rating) await insertRatingAggregate(ctx, entryId)
return await Promise.all(
lists.map(list =>
ctx.db.insert('anime_lists_entries', {
entryId,
listId: list
})
)
)
}
})