Skip to content
This repository has been archived by the owner on Jul 6, 2020. It is now read-only.

Fix relayPagination helper to serve correct partial results #101

Merged
merged 2 commits into from
Sep 30, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 35 additions & 14 deletions src/extras/relayPagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ export interface PaginationParams {
}

interface PageInfo {
__typename: string;
endCursor: null | string;
startCursor: null | string;
hasNextPage: boolean;
hasPreviousPage: boolean;
}

interface Page {
__typename: string;
edges: NullArray<string>;
pageInfo: PageInfo;
}

const defaultPageInfo: PageInfo = {
__typename: 'PageInfo',
endCursor: null,
startCursor: null,
hasNextPage: false,
Expand Down Expand Up @@ -56,23 +59,28 @@ const getPage = (cache: Cache, linkKey: string): Page | null => {
const link = ensureKey(cache.resolveValueOrLink(linkKey));
if (!link) return null;

const typename = cache.resolve(link, '__typename') as string;
const edges = cache.resolve(link, 'edges') as NullArray<string>;
if (
!Array.isArray(edges) ||
!edges.every(x => x === null || typeof x === 'string')
) {
if (typeof typename !== 'string' || !Array.isArray(edges)) {
return null;
}

const page: Page = { edges, pageInfo: defaultPageInfo };
const page: Page = {
__typename: typename,
edges,
pageInfo: defaultPageInfo,
};

const pageInfoKey = cache.resolve(link, 'pageInfo');
if (typeof pageInfoKey === 'string') {
const pageInfoType = ensureKey(cache.resolve(pageInfoKey, '__typename'));
const endCursor = ensureKey(cache.resolve(pageInfoKey, 'endCursor'));
const startCursor = ensureKey(cache.resolve(pageInfoKey, 'startCursor'));
const hasNextPage = cache.resolve(pageInfoKey, 'hasNextPage');
const hasPreviousPage = cache.resolve(pageInfoKey, 'hasPreviousPage');

const pageInfo: PageInfo = (page.pageInfo = {
__typename: typeof pageInfoType === 'string' ? pageInfoType : 'PageInfo',
hasNextPage: typeof hasNextPage === 'boolean' ? hasNextPage : !!endCursor,
hasPreviousPage:
typeof hasPreviousPage === 'boolean' ? hasPreviousPage : !!startCursor,
Expand Down Expand Up @@ -113,14 +121,7 @@ export const relayPagination = (params: PaginationParams = {}): Resolver => {
return undefined;
}

const typename = cache.resolve(entityKey, '__typename');

const pageInfoKey = ensureKey(cache.resolve(entityKey, 'pageInfo'));
const pageInfoTypename = cache.resolve(pageInfoKey, '__typename');
if (typeof typename !== 'string' || typeof pageInfoTypename !== 'string') {
return undefined;
}

let typename = '';
let startEdges: NullArray<string> = [];
let endEdges: NullArray<string> = [];
let pageInfo: PageInfo = { ...defaultPageInfo };
Expand All @@ -145,6 +146,26 @@ export const relayPagination = (params: PaginationParams = {}): Resolver => {
startEdges = concatEdges(cache, startEdges, page.edges);
pageInfo = page.pageInfo;
}

if (page.pageInfo.__typename !== pageInfo.__typename)
pageInfo.__typename = page.pageInfo.__typename;
if (typename !== page.__typename) typename = page.__typename;
}

if (
typeof typename !== 'string' ||
startEdges.length + endEdges.length === 0
) {
return undefined;
}

const hasCurrentPage = !!cache.resolve(entityKey, '__typename');
if (!hasCurrentPage) {
if ((info as any).schemaPredicates === undefined) {
return undefined;
} else {
info.partial = true;
}
}

return {
Expand All @@ -154,7 +175,7 @@ export const relayPagination = (params: PaginationParams = {}): Resolver => {
? concatEdges(cache, startEdges, endEdges)
: concatEdges(cache, endEdges, startEdges),
pageInfo: {
__typename: pageInfoTypename,
__typename: pageInfo.__typename,
endCursor: pageInfo.endCursor,
startCursor: pageInfo.startCursor,
hasNextPage: pageInfo.hasNextPage,
Expand Down