UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines 26.9 kB
{"version":3,"file":"ordered-source-loader.cjs","sources":["../../../../src/query/live/ordered-source-loader.ts"],"sourcesContent":["import {\n buildCursorCurrent,\n canExpressCursorOrder,\n} from '../../utils/cursor.js'\nimport { normalizeError } from '../../utils/error.js'\nimport { runAllCallbacks } from '../../utils/callbacks.js'\nimport { normalizeOrderByPaths } from '../compiler/expressions.js'\nimport type {\n CollectionSubscription,\n ReleaseLoadSubset,\n} from '../../collection/subscription.js'\nimport type {\n ChangeMessage,\n LoadSubsetOptions,\n LoadSubsetRequestResult,\n} from '../../types.js'\nimport type { OrderByOptimizationInfo } from '../compiler/order-by.js'\n\ntype OrderedRequestKind = `ordered` | `boundary` | `full-source`\n\n/** Owns the conservative provider-loading policy for one ordered source. */\nexport class OrderedSourceLoader {\n private pending: Promise<unknown> | undefined\n // Exact request settlement is not provider extent. This latch only records\n // that some request once completed; reset may discard the boundary, and an\n // empty page retains it. A failure never reads it before a full-source\n // completion sets it again, so it never needs clearing.\n private hasSettledSourceRequest = false\n private settledSourceBoundary: Record<string, unknown> | undefined\n // Independent of finite success: only full-source success repairs ordering.\n private needsFullSourceRecovery = false\n private requesting = false\n // Retaining a demand does not prove it succeeded. Async failure retains it\n // (`failed`) for replay; a synchronous startup failure retains nothing.\n private fullSource: `none` | `held` | `complete` | `failed` = `none`\n // Keep callbacks, not copied requests or rows. Successful full-source work\n // subsumes these logical owners; unfinished transports remain observed.\n private settledFiniteAcquisitions = new Set<ReleaseLoadSubset>()\n // The record's presence blocks automatic retry, including initial requests\n // that have no explicit window-operation generation.\n private failedRequest:\n | { windowOperationGeneration: number | undefined }\n | undefined\n private failedAcquisitions = new Map<ReleaseLoadSubset, OrderedRequestKind>()\n private active = true\n private generation = 0\n private lastPage: { count: number; boundary: unknown } | undefined\n private lastPrefixCount: number | undefined\n private lastBoundary: unknown\n\n constructor(\n private readonly info: OrderByOptimizationInfo,\n private readonly subscription: CollectionSubscription,\n private readonly alias: string,\n private readonly onResult: (\n result: LoadSubsetRequestResult,\n holdPublication: boolean,\n ) => void = () => {},\n ) {\n this.info.isRequesting = () => this.requesting\n }\n\n /** Derive invalidation from actual contributions, not a second cursor. */\n onSourceChanges(\n changes: Array<ChangeMessage<Record<string, unknown>, string | number>>,\n sentRows: ReadonlyMap<string | number, Record<string, unknown>> | undefined,\n ): void {\n let hasNewRows = false\n for (const change of changes) {\n const previous = sentRows?.get(change.key)\n if (\n change.type !== `insert` &&\n previous !== undefined &&\n (change.type === `delete` ||\n this.info.comparator(previous, change.value) !== 0)\n ) {\n this.invalidateSourceOrdering()\n return\n }\n if (change.type !== `delete` && previous === undefined) hasNewRows = true\n }\n // New keys, including ties, may need another page. Duplicate delivery or\n // an order-equal update cannot invalidate an already attempted request.\n if (hasNewRows) this.invalidateCursor()\n }\n\n start(): void {\n const { index, limit, offset, orderBy, requiresFullSource } = this.info\n if (index) this.subscription.setOrderByIndex(index)\n if (limit === 0) return\n if (requiresFullSource) {\n this.loadFullSource()\n return\n }\n if (!index || orderBy.length !== 1) {\n this.loadPrefix(offset + limit)\n return\n }\n this.loadPage(offset + limit)\n }\n\n loadMore(windowOperationGeneration?: number): Promise<unknown> | undefined {\n if (!this.active || this.info.limit === 0 || this.requesting) return\n const mayRetryFailure =\n this.failedRequest === undefined ||\n (windowOperationGeneration !== undefined &&\n windowOperationGeneration !==\n this.failedRequest.windowOperationGeneration)\n if (!mayRetryFailure) return this.pending\n if (\n (this.failedRequest || this.failedAcquisitions.size > 0) &&\n windowOperationGeneration !== undefined\n ) {\n // Move ownership to the explicit replacement before releasing the old\n // lease. Adapter cleanup may reenter the loader.\n if (this.failedRequest) {\n this.failedRequest.windowOperationGeneration = windowOperationGeneration\n }\n const failedAcquisitions = this.failedAcquisitions\n this.failedAcquisitions = new Map()\n if (failedAcquisitions.size > 0) {\n this.requesting = true\n try {\n runAllCallbacks(failedAcquisitions.keys())\n } finally {\n this.requesting = false\n }\n // Adapter cleanup can synchronously tear down this loader.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!this.active) return\n }\n }\n if (this.fullSource === `failed`) this.fullSource = `none`\n else if (this.fullSource !== `none`) return this.pending\n if (this.needsFullSourceRecovery || this.info.requiresFullSource) {\n this.loadFullSource(windowOperationGeneration)\n return this.pending\n }\n if (!this.info.index || this.info.orderBy.length !== 1) {\n this.loadPrefix(\n this.info.offset + this.info.limit,\n windowOperationGeneration,\n )\n return this.pending\n }\n if (!this.info.dataNeeded || this.pending) return this.pending\n // A recorded failure always carries recovery debt, so it cannot reach this\n // finite path; only the first request needs the whole prefix here.\n let count = Math.max(\n this.info.dataNeeded(),\n this.hasSettledSourceRequest ? 0 : this.info.offset + this.info.limit,\n )\n if (\n windowOperationGeneration !== undefined &&\n this.settledSourceBoundary !== undefined\n ) {\n const needed = this.info.offset + this.info.limit\n count = Math.max(count, needed - this.countAcquiredRows())\n }\n if (count > 0) {\n this.loadPage(count, windowOperationGeneration)\n }\n return this.pending\n }\n\n loadFullSource(windowOperationGeneration?: number): void {\n if (!this.active || this.fullSource !== `none`) return\n this.fullSource = `held`\n this.requestAndObserve(\n (onLoadSubsetResult) => {\n this.subscription.requestSnapshot({\n trackLoadSubsetPromise: false,\n onLoadSubsetResult,\n })\n },\n `full-source`,\n windowOperationGeneration,\n )\n }\n\n private loadPrefix(count: number, windowOperationGeneration?: number): void {\n if (!this.active || this.pending) return\n if (this.lastPrefixCount === count) {\n if ((this.info.dataNeeded?.() ?? 0) > 0) {\n this.loadFullSource(windowOperationGeneration)\n }\n return\n }\n this.requestAndObserve(\n (onLoadSubsetResult) => {\n this.subscription.requestSnapshot({\n orderBy: normalizeOrderByPaths(this.info.orderBy, this.alias),\n limit: count,\n trackLoadSubsetPromise: false,\n onLoadSubsetResult,\n })\n },\n `ordered`,\n windowOperationGeneration,\n )\n this.lastPrefixCount = count\n }\n\n resetCursor(): void {\n this.generation++\n if (this.fullSource === `complete`) this.fullSource = `held`\n this.pending = undefined\n this.lastBoundary = undefined\n this.settledSourceBoundary = undefined\n this.invalidateCursor()\n }\n\n settleFullSourceReplay(): void {\n // Replay repaired the retained logical acquisition. A later window retry\n // must not release that now-successful source demand. A failed finite\n // page is still obsolete and must be released by that retry.\n if (this.fullSource === `failed`) {\n for (const [release, kind] of this.failedAcquisitions) {\n if (kind === `full-source`) this.failedAcquisitions.delete(release)\n }\n this.fullSource = `held`\n }\n if (this.fullSource !== `none`) {\n this.fullSource = `complete`\n this.retireSettledFiniteAcquisitions()\n }\n }\n\n private retireSettledFiniteAcquisitions(): void {\n if (\n this.fullSource !== `complete` ||\n this.subscription.hasPendingTruncateReplacement\n )\n return\n const generation = this.generation\n runAllCallbacks(\n Array.from(this.settledFiniteAcquisitions, (release) => () => {\n if (!this.active || generation !== this.generation) return\n this.settledFiniteAcquisitions.delete(release)\n release()\n }),\n )\n }\n\n invalidateCursor(): void {\n this.lastPage = undefined\n this.lastPrefixCount = undefined\n }\n\n invalidateSourceOrdering(): void {\n this.invalidateCursor()\n this.requireFullSourceRecovery()\n }\n\n dispose(): void {\n this.active = false\n this.resetCursor()\n this.failedAcquisitions.clear()\n this.settledFiniteAcquisitions.clear()\n }\n\n private countAcquiredRows(): number {\n return this.subscription\n .readOrderedSnapshot({\n orderBy: normalizeOrderByPaths(this.info.orderBy, this.alias),\n limit: this.info.offset + this.info.limit,\n })\n .filter(\n ({ value }) =>\n this.info.comparator(value, this.settledSourceBoundary) <= 0,\n ).length\n }\n\n private loadPage(count: number, windowOperationGeneration?: number): void {\n if (!this.active || this.pending) return\n // Rows observed before the first provider request do not prove ordered\n // source coverage. In particular, a row inserted while limit is zero must\n // not become the cursor when that window first opens.\n const startsFromSourcePrefix = this.settledSourceBoundary === undefined\n const biggest = this.settledSourceBoundary\n let minValues: Array<unknown> | undefined\n if (biggest !== undefined) {\n const value = this.info.valueExtractorForRawRow(biggest)\n if (!canExpressCursorOrder(this.info.orderBy, [value])) {\n this.loadPrefix(\n this.info.offset + this.info.limit,\n windowOperationGeneration,\n )\n return\n }\n minValues = [value]\n }\n const boundary = minValues?.[0]\n if (\n this.lastPage?.count === count &&\n Object.is(this.lastPage.boundary, boundary)\n ) {\n return\n }\n this.lastPage = { count, boundary }\n this.requestAndObserve(\n (onLoadSubsetResult) => {\n this.subscription.requestLimitedSnapshot({\n orderBy: normalizeOrderByPaths(this.info.orderBy, this.alias),\n limit: count,\n minValues,\n // Local rows seen before the first provider request prove neither\n // a cursor nor a remote offset. Start the first acquisition at zero.\n offset: startsFromSourcePrefix ? 0 : this.countAcquiredRows(),\n trackLoadSubsetPromise: false,\n onLoadSubsetResult,\n })\n },\n `ordered`,\n windowOperationGeneration,\n )\n }\n\n private observe(\n result: LoadSubsetRequestResult,\n releaseAcquisition: ReleaseLoadSubset,\n kind: OrderedRequestKind,\n windowOperationGeneration?: number,\n options?: LoadSubsetOptions,\n ): Promise<void> {\n const isFullSource = kind === `full-source`\n const generation = this.generation\n const complete = (): void => {\n if (this.pending === tracked) this.pending = undefined\n if (!this.active) return\n if (!isFullSource) {\n // A replay can replace the physical lease while this older transport\n // finishes. Retire its logical owner only outside the replay barrier.\n this.settledFiniteAcquisitions.add(releaseAcquisition)\n this.retireSettledFiniteAcquisitions()\n }\n if (generation !== this.generation) return\n // A finite request may finish behind an authoritative repair. It cannot\n // clear that repair's failure or resume finite refinement around it.\n if (!isFullSource && (this.failedRequest || this.fullSource !== `none`))\n return\n this.failedRequest = undefined\n if (kind !== `boundary`) {\n this.hasSettledSourceRequest = true\n // Source delivery can invalidate the in-flight prefix marker.\n if (options?.orderBy && !options.cursor) {\n this.lastPrefixCount = options.limit\n }\n if (!isFullSource && options?.orderBy) {\n try {\n this.settledSourceBoundary =\n this.subscription.readOrderedSnapshot(options).at(-1)?.value ??\n this.settledSourceBoundary\n } catch (error) {\n fail(error)\n }\n }\n }\n if (isFullSource) {\n this.needsFullSourceRecovery = false\n this.fullSource = `complete`\n this.retireSettledFiniteAcquisitions()\n }\n if (kind === `ordered`) {\n this.loadBoundary(windowOperationGeneration)\n return\n }\n // A boundary request may add tied rows without filling the query's\n // window. Resume forward loading once it settles.\n this.loadMore()\n }\n const settlesAsync = result instanceof Promise\n const request = settlesAsync ? result : Promise.resolve()\n const fail = (error: unknown) => {\n this.settledFiniteAcquisitions.delete(releaseAcquisition)\n if (this.pending === tracked) this.pending = undefined\n if (!this.active) return\n // A failed request may already have written only part of its result.\n // None of those rows is a safe continuation boundary.\n this.requireFullSourceRecovery()\n if (generation !== this.generation) return\n // A failed request proves no full-source coverage. An explicit window\n // move or later replay may retry it, but an ordinary graph pass must\n // not start an eager retry loop.\n if (isFullSource) this.fullSource = `failed`\n this.recordRequestFailure(windowOperationGeneration)\n this.failedAcquisitions.set(releaseAcquisition, kind)\n throw error\n }\n const tracked = request.then(complete, fail)\n this.pending = tracked\n void tracked.catch(() => {})\n // Register each request separately. The operation tracker observes the\n // next request before this promise settles, so the logical chain remains\n // pending without retaining every ancestor promise until the final page.\n this.onResult(\n tracked,\n settlesAsync && isFullSource && this.needsFullSourceRecovery,\n )\n return tracked\n }\n\n private loadBoundary(\n windowOperationGeneration?: number,\n ): Promise<unknown> | undefined {\n const biggest = this.settledSourceBoundary\n if (biggest === undefined) return\n const value = this.info.valueExtractorForRawRow(biggest)\n const orderBy = normalizeOrderByPaths(this.info.orderBy, this.alias)\n if (!canExpressCursorOrder(orderBy.slice(0, 1), [value])) {\n this.loadFullSource(windowOperationGeneration)\n return this.pending\n }\n // Undefined is not an expressible cursor boundary, so it denotes that no\n // tie request has been attempted. Other falsy values remain valid keys.\n if (Object.is(this.lastBoundary, value)) {\n return this.loadMore()\n }\n const where = buildCursorCurrent(orderBy, [value])\n if (!where) {\n this.loadFullSource(windowOperationGeneration)\n return this.pending\n }\n this.lastBoundary = value\n return this.requestAndObserve(\n (onLoadSubsetResult) => {\n this.subscription.requestSnapshot({\n where,\n trackLoadSubsetPromise: false,\n onLoadSubsetResult,\n })\n },\n `boundary`,\n windowOperationGeneration,\n )\n }\n\n private requireFullSourceRecovery(): void {\n this.settledSourceBoundary = undefined\n this.needsFullSourceRecovery = true\n }\n\n private failRequest(\n observed:\n | {\n result: LoadSubsetRequestResult\n options: LoadSubsetOptions\n release: ReleaseLoadSubset\n }\n | undefined,\n error: Error,\n isFullSource: boolean,\n windowOperationGeneration?: number,\n cancelObservedSettlement = false,\n ): Error {\n if (cancelObservedSettlement) {\n this.generation++\n this.pending = undefined\n }\n this.requireFullSourceRecovery()\n this.recordRequestFailure(windowOperationGeneration)\n if (isFullSource) this.fullSource = `none`\n try {\n observed?.release({ error })\n } catch {\n // Cleanup is attempted once and must not replace the request failure.\n }\n return error\n }\n\n /** A failed request blocks ordinary refinement until a new operation. */\n private recordRequestFailure(windowOperationGeneration?: number): void {\n this.failedRequest = { windowOperationGeneration }\n this.invalidateCursor()\n this.lastBoundary = undefined\n }\n\n /** Observe settlement only after all synchronous request work succeeds. */\n private requestAndObserve(\n request: (\n onResult: (\n result: LoadSubsetRequestResult,\n options: LoadSubsetOptions,\n release: ReleaseLoadSubset,\n ) => void,\n ) => void,\n kind: OrderedRequestKind,\n windowOperationGeneration?: number,\n ): Promise<void> | undefined {\n const isFullSource = kind === `full-source`\n let observed:\n | {\n result: LoadSubsetRequestResult\n options: LoadSubsetOptions\n release: ReleaseLoadSubset\n }\n | undefined\n this.requesting = true\n let observing = false\n try {\n try {\n request((result, options, release) => {\n observed = { result, options, release }\n })\n } finally {\n this.requesting = false\n }\n if (!observed) return\n observing = true\n return this.observe(\n observed.result,\n observed.release,\n kind,\n windowOperationGeneration,\n observed.options,\n )\n } catch (error) {\n // Both request and settlement callbacks may reenter through cleanup.\n // Keep refinement blocked until failure and release finish unwinding.\n this.requesting = true\n try {\n throw this.failRequest(\n observed,\n normalizeError(error),\n isFullSource,\n windowOperationGeneration,\n observing,\n )\n } finally {\n this.requesting = false\n }\n }\n }\n}\n"],"names":["runAllCallbacks","normalizeOrderByPaths","canExpressCursorOrder","error","buildCursorCurrent","normalizeError"],"mappings":"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"}