Skip to content

Commit 55db609

Browse files
committed
fix: refresh background
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
1 parent 697d904 commit 55db609

2 files changed

Lines changed: 19 additions & 7 deletions

File tree

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,16 +456,24 @@ export async function executeQuery(
456456
offset,
457457
})
458458

459+
// Skip the count sub-query if the count is already cached — saves a full table scan
460+
// on every page navigation after the first (page 2, 3, ... all share the same countCacheKey).
461+
const cachedCount = await cache.getCount(countCacheKey)
459462
const [rows, countResult] = await Promise.all([
460463
qx.select(mainQuery, params),
461-
qx.selectOne(countQuery, params),
464+
cachedCount === null ? qx.selectOne(countQuery, params) : Promise.resolve(null),
462465
])
463466

464-
const count = parseInt(countResult.count, 10)
467+
const count = cachedCount !== null ? cachedCount : parseInt(countResult?.count ?? '0', 10)
465468
const memberIds = rows.map((org) => org.id)
466469

467470
if (memberIds.length === 0) {
468-
return { rows: [], count, limit, offset }
471+
const emptyResult = { rows: [], count, limit, offset }
472+
await Promise.all([
473+
cache.set(cacheKey, emptyResult, 21600),
474+
cachedCount === null ? cache.setCount(countCacheKey, count, 21600) : Promise.resolve(),
475+
])
476+
return emptyResult
469477
}
470478

471479
const [memberOrganizations, identities, memberSegments, maintainerRoles] = await Promise.all([

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,12 +422,14 @@ export const buildQuery = ({
422422
Boolean,
423423
)
424424

425+
const needsMemberEnrichments = filterHasMe || fields.includes('me.')
426+
425427
const joins = [
426428
withAggregates
427429
? `INNER JOIN "memberSegmentsAgg" msa ON msa."memberId" = m.id AND msa."segmentId" = $(segmentId)`
428430
: '',
429431
needsMemberOrgs ? `LEFT JOIN member_orgs mo ON mo."memberId" = m.id` : '',
430-
`LEFT JOIN "memberEnrichments" me ON me."memberId" = m.id`,
432+
needsMemberEnrichments ? `LEFT JOIN "memberEnrichments" me ON me."memberId" = m.id` : '',
431433
searchConfig.join,
432434
].filter(Boolean)
433435

@@ -464,9 +466,11 @@ export const buildCountQuery = ({
464466
searchConfig.join,
465467
].filter(Boolean)
466468

467-
// When withAggregates is true the join is on memberSegmentsAgg_pkey (unique on memberId+segmentId),
468-
// so there are no duplicate m.id values — COUNT(*) is equivalent to COUNT(DISTINCT m.id) but cheaper.
469-
const countExpr = withAggregates ? 'COUNT(*)' : 'COUNT(DISTINCT m.id)'
469+
// COUNT(*) is safe only when every join is guaranteed one-to-one per member:
470+
// - memberSegmentsAgg is unique on (memberId, segmentId) with segmentId fixed → safe
471+
// - member_orgs CTE uses ARRAY_AGG GROUP BY memberId → one row per member → safe
472+
// - memberEnrichments may have multiple rows per member → COUNT(*) would overcount
473+
const countExpr = withAggregates && !filterHasMe ? 'COUNT(*)' : 'COUNT(DISTINCT m.id)'
470474

471475
return `
472476
${ctes.length > 0 ? `WITH ${ctes.join(',\n')}` : ''}

0 commit comments

Comments
 (0)