diff --git a/packages/ember/src/-private/pagination-state.ts b/packages/ember/src/-private/pagination-state.ts new file mode 100644 index 00000000000..acf36e640e1 --- /dev/null +++ b/packages/ember/src/-private/pagination-state.ts @@ -0,0 +1,91 @@ +import { cached, tracked } from '@glimmer/tracking'; + +import type { + Future, + ImmutableRequestInfo, + ResponseInfo, + StructuredDocument, + StructuredErrorDocument, +} from '@ember-data/request'; +import type { Document } from '@ember-data/store'; + +import type { RequestState } from './request-state'; +import { getRequestState } from './request-state'; + +const RequestCache = new WeakMap, PaginationState>(); + +type FirstLink = { + prev: null; + self: RequestState; + next: Link | PlaceholderLink | null; + isVirtual: false; +}; + +type Link = { + prev: Link | PlaceholderLink | FirstLink; + self: RequestState; + next: Link | PlaceholderLink | null; + isVirtual: false; +}; + +type PlaceholderLink = { + prev: Link | FirstLink; + self: null; + next: Link; + isVirtual: true; +}; + +class PaginationState = Document> { + #pageList!: FirstLink; + + @tracked pages: Document[] = []; + @tracked data: T[] = []; + + constructor(request: Future) { + this.#pageList = { + prev: null, + self: getRequestState(request), + next: null, + isVirtual: false, + }; + } + + @cached + get isLoading() { + return this.pages.some((page) => page.isLoading); + } + + @cached + get isSuccess() { + return !this.isError; + } + + @cached + get isError() { + return this.pages.some((page) => page.isError); + } + + #addPage(page: Document) { + this.pages.push(page); + this.data = this.data.concat(page.data!); + } + + async next() { + const page = this.pages.at(-1); + const result = await page?.next(); + if (result) { + this.#addPage(result); + } + } +} + +export function getPaginationState>(future: Future): PaginationState { + let state = RequestCache.get(future) as PaginationState | undefined; + + if (!state) { + state = new PaginationState(future); + RequestCache.set(future, state); + } + + return state; +}