Michael Holmes
Michael Holmes15mo ago

Is this the way to include / join a table?

I'm extending Doc<"organizationCourses"> into an interface OrganizationCourse that includes course.
import { query } from '../_generated/server';
import { v } from 'convex/values';
import { OrganizationCourse } from '../interfaces';
import { paginationOptsValidator } from 'convex/server';

export const getOrganizationCourses = query({
args: { id: v.id('organizations'), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
try {
let organization = (await ctx.db.get(args.id)) as Organization;

if (!organization) throw new Error('Organization not found');

const organizationCourses = await ctx.db
.query('organizationCourses')
.withIndex('organization_course_index', q => q.eq('organizationId', organization!._id))
.order('desc')
.paginate(args.paginationOpts);

// Include each course
const coursesPromises = organizationCourses.page.map(orgCourse =>
ctx.db.get(orgCourse.courseId)
);
const courses = await Promise.all(coursesPromises);

organizationCourses.page.forEach((orgCourse: OrganizationCourse, index) => {
orgCourse.course = courses[index];
});

return { data: organizationCourses, error: null };
} catch (error) {
console.error('organizationCourses error', error);
return { data: null, error: 'There was a problem' };
}
},
});
import { query } from '../_generated/server';
import { v } from 'convex/values';
import { OrganizationCourse } from '../interfaces';
import { paginationOptsValidator } from 'convex/server';

export const getOrganizationCourses = query({
args: { id: v.id('organizations'), paginationOpts: paginationOptsValidator },
handler: async (ctx, args) => {
try {
let organization = (await ctx.db.get(args.id)) as Organization;

if (!organization) throw new Error('Organization not found');

const organizationCourses = await ctx.db
.query('organizationCourses')
.withIndex('organization_course_index', q => q.eq('organizationId', organization!._id))
.order('desc')
.paginate(args.paginationOpts);

// Include each course
const coursesPromises = organizationCourses.page.map(orgCourse =>
ctx.db.get(orgCourse.courseId)
);
const courses = await Promise.all(coursesPromises);

organizationCourses.page.forEach((orgCourse: OrganizationCourse, index) => {
orgCourse.course = courses[index];
});

return { data: organizationCourses, error: null };
} catch (error) {
console.error('organizationCourses error', error);
return { data: null, error: 'There was a problem' };
}
},
});
2 Replies
lee
lee15mo ago
looks good to me! you could get better type inference by doing a .map instead of a .forEach, which might mean you don't need to define an interface because the type will be inferred
ian
ian15mo ago
If you're returning a paginated result to use with the usePaginatedQuery, it needs to conform to PaginationResult which has these fields:
export interface PaginationResult<T> {
/**
* The page of results.
*/
page: T[];

/**
* Have we reached the end of the results?
*/
isDone: boolean;

/**
* A {@link Cursor} to continue loading more results.
*/
continueCursor: Cursor;
}
export interface PaginationResult<T> {
/**
* The page of results.
*/
page: T[];

/**
* Have we reached the end of the results?
*/
isDone: boolean;

/**
* A {@link Cursor} to continue loading more results.
*/
continueCursor: Cursor;
}
These are the fields in organizationCourses so instead of returning {data: organizationCourses, error: null} you'd need to return something like: { ...organizationCourses, error: null} but I'm not sure how to read the error, without having a custom equivalent to usePaginatedQuery or passing it in page somehow.. Are you usig usePaginatedQuery?

Did you find this page helpful?