How to paginate searched results using cursor based?
this is my function for querying data and there is something wrong because when I load more data, there are items that are not related to the searched query?
@UseMiddleware(isAuthenticated)
@Query(() => PaginatedQuizzes)
async quizzes(
@Arg('limit', () => Int) limit: number,
@Arg('cursor', () => String, { nullable: true }) cursor: string | null,
@Arg('query', () => String, { nullable: true }) query: string | null
): Promise<PaginatedQuizzes> {
const realLimit = Math.min(50, limit);
const realLimitPlusOne = realLimit + 1;
const qs = await getConnection()
.getRepository(Quiz)
.createQueryBuilder('q')
.leftJoinAndSelect('q.author', 'author')
.leftJoinAndSelect('q.questions', 'questions')
if (query) {
const formattedQuery = query.trim().replace(/ /g, ' <-> ');
qs.where(
`to_tsvector('simple',q.title) @@ to_tsquery('simple', :query)`,
{
query: `${formattedQuery}:*`,
}
).orWhere(
`to_tsvector('simple',q.description) @@ to_tsquery('simple', :query)`,
{
query: `${formattedQuery}:*`,
}
);
}
if (cursor) {
qs.where('q."created_at" < :cursor', {
cursor: new Date(parseInt(cursor)),
});
}
const quizzes = await qs
.orderBy('q.created_at', 'DESC')
.take(realLimitPlusOne)
.getMany();
return {
quizzes: (quizzes as [Quiz]).slice(0, realLimit),
hasMore: (quizzes as [Quiz]).length === realLimitPlusOne,
};
}
thank you so much for the responses, but i was able to solved it on my own using find option,
@UseMiddleware(isAuthenticated)
@Query(() => PaginatedQuizzes)
async quizzes(
@Arg('limit', () => Int) limit: number,
@Arg('cursor', () => String, { nullable: true }) cursor: string | null,
@Arg('query', () => String, { nullable: true }) query: string | null
): Promise<PaginatedQuizzes> {
const realLimit = Math.min(20, limit);
const realLimitPlusOne = realLimit + 1;
let findOptionInitial: FindManyOptions = {
relations: [
'author',
'questions',
],
order: {
created_at: 'DESC',
},
take: realLimitPlusOne,
};
let findOption: FindManyOptions;
if (cursor && query) {
const formattedQuery = query.trim().replace(/ /g, ' <-> ');
findOption = {
...findOptionInitial,
where: [
{
description: Raw(
(description) =>
`to_tsvector('simple', ${description}) @@ to_tsquery('simple', :query)`,
{
query: formattedQuery,
}
),
created_at: LessThan(new Date(parseInt(cursor))),
},
{
title: Raw(
(title) =>
`to_tsvector('simple', ${title}) @@ to_tsquery('simple', :query)`,
{
query: formattedQuery,
}
),
created_at: LessThan(new Date(parseInt(cursor))),
},
],
};
} else if (cursor) {
findOption = {
...findOptionInitial,
where: {
created_at: LessThan(new Date(parseInt(cursor))),
},
};
} else if (query) {
const formattedQuery = query.trim().replace(/ /g, ' <-> ');
findOption = {
...findOptionInitial,
where: [
{
description: Raw(
(description) =>
`to_tsvector('simple', ${description}) @@ to_tsquery('simple', :query)`,
{
query: formattedQuery,
}
),
},
{
title: Raw(
(title) =>
`to_tsvector('simple', ${title}) @@ to_tsquery('simple', :query)`,
{
query: formattedQuery,
}
),
},
],
};
} else {
findOption = findOptionInitial;
}
const quizzes = await Quiz.find(findOption as FindManyOptions);
return {
quizzes: (quizzes as [Quiz]).slice(0, realLimit),
hasMore: (quizzes as [Quiz]).length === realLimitPlusOne,
};
}