fix(domain): base pagination hasMore on fetched rows, not filtered rows (#135)

This commit is contained in:
Shuvam Kumar 2026-07-23 19:21:31 +05:30 committed by GitHub
parent 0d654c06e6
commit 8ca2e0b332
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 8 deletions

View File

@ -5,6 +5,7 @@ import { createDataforseoClient } from "@/server/lib/dataforseo";
import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache"; import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache";
import { normalizeDomainInput } from "@/server/lib/domainUtils"; import { normalizeDomainInput } from "@/server/lib/domainUtils";
import { mapKeywordItem } from "@/server/features/domain/services/domainKeywordMapper"; import { mapKeywordItem } from "@/server/features/domain/services/domainKeywordMapper";
import { computeHasMore } from "@/server/features/domain/services/pagination";
import { import {
buildKeywordFilters, buildKeywordFilters,
buildOrderBy, buildOrderBy,
@ -99,10 +100,12 @@ export async function getKeywordsPage(
); );
const totalCount = response.totalCount; const totalCount = response.totalCount;
const hasMore = const hasMore = computeHasMore(
totalCount != null offset,
? offset + keywords.length < totalCount response.items.length,
: keywords.length === input.pageSize; totalCount,
input.pageSize,
);
const result: DomainKeywordsPageResult = { const result: DomainKeywordsPageResult = {
domain, domain,

View File

@ -5,6 +5,7 @@ import { createDataforseoClient } from "@/server/lib/dataforseo";
import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache"; import { buildCacheKey, getCached, setCached } from "@/server/lib/r2-cache";
import { normalizeDomainInput, toRelativePath } from "@/server/lib/domainUtils"; import { normalizeDomainInput, toRelativePath } from "@/server/lib/domainUtils";
import type { RelevantPagesItem } from "@/server/lib/dataforseo"; import type { RelevantPagesItem } from "@/server/lib/dataforseo";
import { computeHasMore } from "@/server/features/domain/services/pagination";
import type { DomainKeywordsFilters } from "@/types/schemas/domain"; import type { DomainKeywordsFilters } from "@/types/schemas/domain";
const DOMAIN_PAGES_PAGE_TTL_SECONDS = 12 * 60 * 60; const DOMAIN_PAGES_PAGE_TTL_SECONDS = 12 * 60 * 60;
@ -179,10 +180,12 @@ export async function getPagesPage(
); );
const totalCount = response.totalCount; const totalCount = response.totalCount;
const hasMore = const hasMore = computeHasMore(
totalCount != null offset,
? offset + pages.length < totalCount response.items.length,
: pages.length === input.pageSize; totalCount,
input.pageSize,
);
const result: DomainPagesPageResult = { const result: DomainPagesPageResult = {
domain, domain,

View File

@ -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);
});
});

View File

@ -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;
}