diff --git a/.changeset/fix-loadsubset-offset.md b/.changeset/fix-loadsubset-offset.md new file mode 100644 index 000000000..8b000e6f7 --- /dev/null +++ b/.changeset/fix-loadsubset-offset.md @@ -0,0 +1,7 @@ +--- +"@tanstack/db": patch +--- + +fix(db): pass offset to loadSubset for proper pagination support + +Fixed an issue where the `offset` parameter was not being passed to `loadSubset`, causing direct pagination (e.g., fetching page 400 with 200 items) to load all rows from the beginning instead of just the requested page. The `LoadSubsetOptions` type now includes an `offset` property, and `parseLoadSubsetOptions` helper also returns the offset value. diff --git a/packages/db/src/collection/subscription.ts b/packages/db/src/collection/subscription.ts index 1c23d7b04..d60423e75 100644 --- a/packages/db/src/collection/subscription.ts +++ b/packages/db/src/collection/subscription.ts @@ -27,6 +27,7 @@ type RequestSnapshotOptions = { type RequestLimitedSnapshotOptions = { orderBy: OrderBy limit: number + offset?: number minValue?: any } @@ -243,6 +244,7 @@ export class CollectionSubscription requestLimitedSnapshot({ orderBy, limit, + offset, minValue, }: RequestLimitedSnapshotOptions) { if (!limit) throw new Error(`limit is required`) @@ -347,6 +349,7 @@ export class CollectionSubscription const loadOptions1: LoadSubsetOptions = { where: whereWithValueFilter, limit, + offset, orderBy, subscription: this, } diff --git a/packages/db/src/query/expression-helpers.ts b/packages/db/src/query/expression-helpers.ts index dd651f396..3a0975f74 100644 --- a/packages/db/src/query/expression-helpers.ts +++ b/packages/db/src/query/expression-helpers.ts @@ -478,7 +478,7 @@ export function extractSimpleComparisons( * Good starting point for simple use cases. * * @param options - The LoadSubsetOptions from ctx.meta - * @returns Pre-parsed filters, sorts, and limit + * @returns Pre-parsed filters, sorts, limit, and offset * * @example * ```typescript @@ -491,7 +491,8 @@ export function extractSimpleComparisons( * parsed.filters.map(f => [`${f.field.join('.')}_${f.operator}`, f.value]) * ), * sort: parsed.sorts.map(s => `${s.field.join('.')}:${s.direction}`).join(','), - * limit: parsed.limit + * limit: parsed.limit, + * offset: parsed.offset * }) * } * ``` @@ -502,6 +503,7 @@ export function parseLoadSubsetOptions( where?: BasicExpression orderBy?: OrderBy limit?: number + offset?: number } | undefined | null @@ -509,6 +511,7 @@ export function parseLoadSubsetOptions( filters: Array sorts: Array limit?: number + offset?: number } { if (!options) { return { filters: [], sorts: [] } @@ -518,5 +521,6 @@ export function parseLoadSubsetOptions( filters: extractSimpleComparisons(options.where), sorts: parseOrderByExpression(options.orderBy), limit: options.limit, + offset: options.offset, } } diff --git a/packages/db/src/query/live/collection-subscriber.ts b/packages/db/src/query/live/collection-subscriber.ts index 38614cb0a..4146963a3 100644 --- a/packages/db/src/query/live/collection-subscriber.ts +++ b/packages/db/src/query/live/collection-subscriber.ts @@ -195,10 +195,10 @@ export class CollectionSubscriber< // Normalize the orderBy clauses such that the references are relative to the collection const normalizedOrderBy = normalizeOrderByPaths(orderBy, this.alias) - // Load the first `offset + limit` values from the index - // i.e. the K items from the collection that fall into the requested range: [offset, offset + limit[ + // Load the items from the collection that fall into the requested range: [offset, offset + limit[ subscription.requestLimitedSnapshot({ - limit: offset + limit, + limit, + offset, orderBy: normalizedOrderBy, }) diff --git a/packages/db/src/types.ts b/packages/db/src/types.ts index f41492ec7..287271648 100644 --- a/packages/db/src/types.ts +++ b/packages/db/src/types.ts @@ -260,6 +260,8 @@ export type LoadSubsetOptions = { orderBy?: OrderBy /** The limit of the data to load */ limit?: number + /** The offset to start loading from */ + offset?: number /** * The subscription that triggered the load. * Advanced sync implementations can use this for: