Skip to content

Commit 2e0aee8

Browse files
committed
fix: cursor bugs
1 parent 9c92975 commit 2e0aee8

File tree

1 file changed

+8
-15
lines changed

1 file changed

+8
-15
lines changed

services/libs/data-access-layer/src/members/queryBuilder.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -103,30 +103,22 @@ const getOrderClause = (
103103
direction: OrderDirection,
104104
withAggregates: boolean,
105105
): string => {
106-
// Default sort:
107-
// - when aggregates are included → sort by activityCount (from msa)
108-
// - otherwise → sort by joinedAt (from members)
109106
const defaultOrder = withAggregates ? 'msa."activityCount" DESC' : 'm."joinedAt" DESC'
110107

111-
// If no specific order field is provided, use the default one
112108
if (!parsedField) return defaultOrder
113109

114110
const fieldExpr = ORDER_FIELD_MAP[parsedField]
115111

116-
// If the requested field is not mapped, fall back to default order
117112
if (!fieldExpr) return defaultOrder
118113

119-
// Safety check:
120-
// If the order field refers to msa.* but aggregates are not included,
121-
// fallback to the default safe order instead of generating invalid SQL.
122114
if (!withAggregates && fieldExpr.includes('msa.')) {
123115
return defaultOrder
124116
}
125117

126-
// Return the valid ORDER BY clause
127118
return `${fieldExpr} ${direction}`
128119
}
129120

121+
// TODO: rework
130122
const detectPinnedMemberId = (filterString: string): { pinned: boolean; smallList: boolean } => {
131123
if (!filterString) return { pinned: false, smallList: false }
132124

@@ -211,7 +203,7 @@ export const buildQuery = ({
211203
const useActivityCountOptimized =
212204
withAggregates && (!sortField || sortField === 'activityCount') && !filterHasMe
213205
// (we do allow mo.* now, but only outside the CTE; see below)
214-
206+
log.info(`useActivityCountOptimized=${useActivityCountOptimized}`)
215207
if (useActivityCountOptimized) {
216208
const ctes: string[] = []
217209

@@ -225,9 +217,8 @@ export const buildQuery = ({
225217
? `\n INNER JOIN member_search ms ON ms."memberId" = msa."memberId"`
226218
: ''
227219

228-
// Oversample to keep page filled after outer filters; tune multiplier if needed
229-
const oversampleMultiplier = 5
230-
const prefetch = Math.max(limit * oversampleMultiplier + offset, limit + offset)
220+
// Fix pagination: fetch enough rows to handle the requested page correctly
221+
const totalNeeded = limit + offset
231222

232223
ctes.push(
233224
`
@@ -241,15 +232,15 @@ export const buildQuery = ({
241232
msa."segmentId" = $(segmentId)
242233
ORDER BY
243234
msa."activityCount" ${direction} NULLS LAST
244-
LIMIT ${prefetch}
235+
LIMIT ${totalNeeded}
245236
)
246237
`.trim(),
247238
)
248239

249240
const withClause = `WITH ${ctes.join(',\n')}`
250241
const memberOrgsJoin = needsMemberOrgs ? `LEFT JOIN member_orgs mo ON mo."memberId" = m.id` : ''
251242

252-
// Outer filters (including mo./me.) applied here; index handles the CTE ranking
243+
// Outer filters (including mo./me.) applied here; remove OFFSET/LIMIT since top_members already handles it
253244
return `
254245
${withClause}
255246
SELECT ${fields}
@@ -303,6 +294,7 @@ export const buildCountQuery = ({
303294
includeMemberOrgs = false,
304295
}: BuildCountQueryArgs): string => {
305296
const filterHasMo = filterString.includes('mo.')
297+
const filterHasMe = filterString.includes('me.')
306298
const needsMemberOrgs = includeMemberOrgs || filterHasMo
307299

308300
const ctes = [needsMemberOrgs ? buildMemberOrgsCTE(true) : '', searchConfig.cte].filter(Boolean)
@@ -312,6 +304,7 @@ export const buildCountQuery = ({
312304
? `INNER JOIN "memberSegmentsAgg" msa ON msa."memberId" = m.id AND msa."segmentId" = $(segmentId)`
313305
: '',
314306
needsMemberOrgs ? `LEFT JOIN member_orgs mo ON mo."memberId" = m.id` : '',
307+
filterHasMe ? `LEFT JOIN "memberEnrichments" me ON me."memberId" = m.id` : '',
315308
searchConfig.join,
316309
].filter(Boolean)
317310

0 commit comments

Comments
 (0)