To automatically add .withIndex('by_userId') to your queries while maintaining the standard query form, you can create a custom wrapper for the database context. This approach allows you to keep writing queries in the familiar style while enforcing the use of the index. Here's how you can implement this:
- First, create a custom wrapper function for the database context:
function createIndexedDbContext(ctx: QueryCtx, userId: string) {
const originalQuery = ctx.db.query.bind(ctx.db);
return {
...ctx.db,
query: (tableName: string) => {
const query = originalQuery(tableName);
if (tableName === "websites") {
return query.withIndex("by_userId", q => q.eq("userId", userId));
}
return query;
}
};
}
- Then, modify your custom query wrapper to use this indexed context:
const queryWithRLSAndIndex = customQuery(
query,
customCtx(async (ctx) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) {
throw new Error("Unauthenticated");
}
const userId = identity.subject;
const db = wrapDatabaseReader(ctx, ctx.db, await rlsRules(ctx));
const indexedDb = createIndexedDbContext(db, userId);
return { ctx: { ...ctx, db: indexedDb } };
})
);
- Now you can use this custom query in your Convex functions:
export const myQuery = queryWithRLSAndIndex({
handler: async (ctx) => {
const websites = await ctx.db.query("websites").collect();
}
});
This approach allows you to keep writing queries in the standard form while automatically applying the by_userId index to the "websites" table. The index is added behind the scenes, so you don't need to manually include it in each query.