From 8ca2e0b332642ef7958170222e19775a09b1f440 Mon Sep 17 00:00:00 2001 From: Shuvam Kumar <145355204+shuvamk@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:21:31 +0530 Subject: [PATCH] fix(domain): base pagination hasMore on fetched rows, not filtered rows (#135) --- .../domain/services/domainKeywordsPage.ts | 11 +++++++---- .../domain/services/domainPagesPage.ts | 11 +++++++---- .../domain/services/pagination.test.ts | 19 +++++++++++++++++++ .../features/domain/services/pagination.ts | 12 ++++++++++++ 4 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 src/server/features/domain/services/pagination.test.ts create mode 100644 src/server/features/domain/services/pagination.ts diff --git a/src/server/features/domain/services/domainKeywordsPage.ts b/src/server/features/domain/services/domainKeywordsPage.ts index 995911c..dd1c60c 100644 --- a/src/server/features/domain/services/domainKeywordsPage.ts +++ b/src/server/features/domain/services/domainKeywordsPage.ts @@ -5,6 +5,7 @@ import { createDataforseoClient } from "@/server/lib/dataforseo"; import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache"; import { normalizeDomainInput } from "@/server/lib/domainUtils"; import { mapKeywordItem } from "@/server/features/domain/services/domainKeywordMapper"; +import { computeHasMore } from "@/server/features/domain/services/pagination"; import { buildKeywordFilters, buildOrderBy, @@ -99,10 +100,12 @@ export async function getKeywordsPage( ); const totalCount = response.totalCount; - const hasMore = - totalCount != null - ? offset + keywords.length < totalCount - : keywords.length === input.pageSize; + const hasMore = computeHasMore( + offset, + response.items.length, + totalCount, + input.pageSize, + ); const result: DomainKeywordsPageResult = { domain, diff --git a/src/server/features/domain/services/domainPagesPage.ts b/src/server/features/domain/services/domainPagesPage.ts index 1fbd9c0..a5967ab 100644 --- a/src/server/features/domain/services/domainPagesPage.ts +++ b/src/server/features/domain/services/domainPagesPage.ts @@ -5,6 +5,7 @@ import { createDataforseoClient } from "@/server/lib/dataforseo"; import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache"; import { normalizeDomainInput, toRelativePath } from "@/server/lib/domainUtils"; import type { RelevantPagesItem } from "@/server/lib/dataforseo"; +import { computeHasMore } from "@/server/features/domain/services/pagination"; import type { DomainKeywordsFilters } from "@/types/schemas/domain"; const DOMAIN_PAGES_PAGE_TTL_SECONDS = 12 * 60 * 60; @@ -179,10 +180,12 @@ export async function getPagesPage( ); const totalCount = response.totalCount; - const hasMore = - totalCount != null - ? offset + pages.length < totalCount - : pages.length === input.pageSize; + const hasMore = computeHasMore( + offset, + response.items.length, + totalCount, + input.pageSize, + ); const result: DomainPagesPageResult = { domain, diff --git a/src/server/features/domain/services/pagination.test.ts b/src/server/features/domain/services/pagination.test.ts new file mode 100644 index 0000000..9c47b55 --- /dev/null +++ b/src/server/features/domain/services/pagination.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from "vitest"; +import { computeHasMore } from "@/server/features/domain/services/pagination"; + +describe("computeHasMore", () => { + it("uses totalCount against the raw fetched offset when known", () => { + expect(computeHasMore(0, 100, 250, 100)).toBe(true); + expect(computeHasMore(200, 50, 250, 100)).toBe(false); + }); + + it("returns false for a full page whose fetched count reaches totalCount", () => { + expect(computeHasMore(0, 100, 100, 100)).toBe(false); + }); + + it("falls back to a full-page check when totalCount is unknown", () => { + expect(computeHasMore(0, 100, null, 100)).toBe(true); + expect(computeHasMore(0, 100, undefined, 100)).toBe(true); + expect(computeHasMore(100, 40, null, 100)).toBe(false); + }); +}); diff --git a/src/server/features/domain/services/pagination.ts b/src/server/features/domain/services/pagination.ts new file mode 100644 index 0000000..4d45e76 --- /dev/null +++ b/src/server/features/domain/services/pagination.ts @@ -0,0 +1,12 @@ +/** Whether more pages exist, given the raw provider row count for this page + * (`response.items.length`). */ +export function computeHasMore( + offset: number, + fetchedCount: number, + totalCount: number | null | undefined, + pageSize: number, +): boolean { + return totalCount != null + ? offset + fetchedCount < totalCount + : fetchedCount === pageSize; +}