UNPKG

@urql/exchange-graphcache

Version:

A normalized and configurable cache exchange for urql

330 lines (322 loc) 11.6 kB
Object.defineProperty(exports, '__esModule', { value: true }); var core = require('@urql/core'); /** Input parameters for the {@link relayPagination} factory. */ var defaultPageInfo = { __typename: 'PageInfo', endCursor: null, startCursor: null, hasNextPage: false, hasPreviousPage: false }; var ensureKey = x => typeof x === 'string' ? x : null; var concatEdges = (cache, leftEdges, rightEdges) => { var ids = new Set(); for (var i = 0, l = leftEdges.length; i < l; i++) { var edge = leftEdges[i]; var node = cache.resolve(edge, 'node'); if (typeof node === 'string') ids.add(node); } var newEdges = leftEdges.slice(); for (var _i = 0, _l = rightEdges.length; _i < _l; _i++) { var _edge = rightEdges[_i]; var _node = cache.resolve(_edge, 'node'); if (typeof _node === 'string' && !ids.has(_node)) { ids.add(_node); newEdges.push(_edge); } } return newEdges; }; var concatNodes = (leftNodes, rightNodes) => { var ids = new Set(); for (var i = 0, l = leftNodes.length; i < l; i++) { var node = leftNodes[i]; if (typeof node === 'string') ids.add(node); } var newNodes = leftNodes.slice(); for (var _i2 = 0, _l2 = rightNodes.length; _i2 < _l2; _i2++) { var _node2 = rightNodes[_i2]; if (typeof _node2 === 'string' && !ids.has(_node2)) { ids.add(_node2); newNodes.push(_node2); } } return newNodes; }; var compareArgs = (fieldArgs, connectionArgs) => { for (var key in connectionArgs) { if (key === 'first' || key === 'last' || key === 'after' || key === 'before') { continue; } else if (!(key in fieldArgs)) { return false; } var argA = fieldArgs[key]; var argB = connectionArgs[key]; if (typeof argA !== typeof argB || typeof argA !== 'object' ? argA !== argB : core.stringifyVariables(argA) !== core.stringifyVariables(argB)) { return false; } } for (var _key in fieldArgs) { if (_key === 'first' || _key === 'last' || _key === 'after' || _key === 'before') { continue; } if (!(_key in connectionArgs)) return false; } return true; }; var getPage = (cache, entityKey, fieldKey) => { var link = ensureKey(cache.resolve(entityKey, fieldKey)); if (!link) return null; var typename = cache.resolve(link, '__typename'); var edges = cache.resolve(link, 'edges') || []; var nodes = cache.resolve(link, 'nodes') || []; if (typeof typename !== 'string') { return null; } var page = { __typename: typename, edges, nodes, pageInfo: defaultPageInfo }; var pageInfoKey = cache.resolve(link, 'pageInfo'); if (typeof pageInfoKey === 'string') { var pageInfoType = ensureKey(cache.resolve(pageInfoKey, '__typename')); var endCursor = ensureKey(cache.resolve(pageInfoKey, 'endCursor')); var startCursor = ensureKey(cache.resolve(pageInfoKey, 'startCursor')); var hasNextPage = cache.resolve(pageInfoKey, 'hasNextPage'); var hasPreviousPage = cache.resolve(pageInfoKey, 'hasPreviousPage'); var pageInfo = page.pageInfo = { __typename: typeof pageInfoType === 'string' ? pageInfoType : 'PageInfo', hasNextPage: typeof hasNextPage === 'boolean' ? hasNextPage : !!endCursor, hasPreviousPage: typeof hasPreviousPage === 'boolean' ? hasPreviousPage : !!startCursor, endCursor, startCursor }; if (pageInfo.endCursor === null) { var edge = edges[edges.length - 1]; if (edge) { var _endCursor = cache.resolve(edge, 'cursor'); pageInfo.endCursor = ensureKey(_endCursor); } } if (pageInfo.startCursor === null) { var _edge2 = edges[0]; if (_edge2) { var _startCursor = cache.resolve(_edge2, 'cursor'); pageInfo.startCursor = ensureKey(_startCursor); } } } return page; }; /** Creates a {@link Resolver} that combines pages that comply to the Relay pagination spec. * * @param params - A {@link PaginationParams} configuration object. * @returns the created Relay pagination {@link Resolver}. * * @remarks * `relayPagination` is a factory that creates a {@link Resolver} that can combine * multiple pages on a field that complies to the Relay pagination spec into a single, * combined list for infinite scrolling. * * This resolver will only work on fields that return a `Connection` GraphQL object * type, according to the Relay pagination spec. * * Hint: It's not recommended to use this when you can handle infinite scrolling * in your UI code instead. * * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers#relay-pagination} for more information. * @see {@link https://urql.dev/goto/docs/basics/ui-patterns/#infinite-scrolling} for an alternate approach. */ var relayPagination = (params = {}) => { var mergeMode = params.mergeMode || 'inwards'; return (_parent, fieldArgs, cache, info) => { var { parentKey: entityKey, fieldName } = info; var allFields = cache.inspectFields(entityKey); var fieldInfos = allFields.filter(info => info.fieldName === fieldName); var size = fieldInfos.length; if (size === 0) { return undefined; } var typename = null; var startEdges = []; var endEdges = []; var startNodes = []; var endNodes = []; var pageInfo = { ...defaultPageInfo }; for (var i = 0; i < size; i++) { var { fieldKey, arguments: args } = fieldInfos[i]; if (args === null || !compareArgs(fieldArgs, args)) { continue; } var page = getPage(cache, entityKey, fieldKey); if (page === null) { continue; } if (page.nodes.length === 0 && page.edges.length === 0 && typename) { continue; } if (mergeMode === 'inwards' && typeof args.last === 'number' && typeof args.first === 'number') { var firstEdges = page.edges.slice(0, args.first + 1); var lastEdges = page.edges.slice(-args.last); var firstNodes = page.nodes.slice(0, args.first + 1); var lastNodes = page.nodes.slice(-args.last); startEdges = concatEdges(cache, startEdges, firstEdges); endEdges = concatEdges(cache, lastEdges, endEdges); startNodes = concatNodes(startNodes, firstNodes); endNodes = concatNodes(lastNodes, endNodes); pageInfo = page.pageInfo; } else if (args.after) { startEdges = concatEdges(cache, startEdges, page.edges); startNodes = concatNodes(startNodes, page.nodes); pageInfo.endCursor = page.pageInfo.endCursor; pageInfo.hasNextPage = page.pageInfo.hasNextPage; } else if (args.before) { endEdges = concatEdges(cache, page.edges, endEdges); endNodes = concatNodes(page.nodes, endNodes); pageInfo.startCursor = page.pageInfo.startCursor; pageInfo.hasPreviousPage = page.pageInfo.hasPreviousPage; } else if (typeof args.last === 'number') { endEdges = concatEdges(cache, page.edges, endEdges); endNodes = concatNodes(page.nodes, endNodes); pageInfo = page.pageInfo; } else { startEdges = concatEdges(cache, startEdges, page.edges); startNodes = concatNodes(startNodes, page.nodes); 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') { return undefined; } var hasCurrentPage = !!ensureKey(cache.resolve(entityKey, fieldName, fieldArgs)); if (!hasCurrentPage) { if (!info.store.schema) { return undefined; } else { info.partial = true; } } return { __typename: typename, edges: mergeMode === 'inwards' ? concatEdges(cache, startEdges, endEdges) : concatEdges(cache, endEdges, startEdges), nodes: mergeMode === 'inwards' ? concatNodes(startNodes, endNodes) : concatNodes(endNodes, startNodes), pageInfo: { __typename: pageInfo.__typename, endCursor: pageInfo.endCursor, startCursor: pageInfo.startCursor, hasNextPage: pageInfo.hasNextPage, hasPreviousPage: pageInfo.hasPreviousPage } }; }; }; /** Input parameters for the {@link simplePagination} factory. */ /** Creates a {@link Resolver} that combines pages of a primitive pagination field. * * @param options - A {@link PaginationParams} configuration object. * @returns the created pagination {@link Resolver}. * * @remarks * `simplePagination` is a factory that creates a {@link Resolver} that can combine * multiple lists on a paginated field into a single, combined list for infinite * scrolling. * * Hint: It's not recommended to use this when you can handle infinite scrolling * in your UI code instead. * * @see {@link https://urql.dev/goto/docs/graphcache/local-resolvers#simple-pagination} for more information. * @see {@link https://urql.dev/goto/docs/basics/ui-patterns/#infinite-scrolling} for an alternate approach. */ var simplePagination = ({ offsetArgument = 'skip', limitArgument = 'limit', mergeMode = 'after' } = {}) => { var compareArgs = (fieldArgs, connectionArgs) => { for (var key in connectionArgs) { if (key === offsetArgument || key === limitArgument) { continue; } else if (!(key in fieldArgs)) { return false; } var argA = fieldArgs[key]; var argB = connectionArgs[key]; if (typeof argA !== typeof argB || typeof argA !== 'object' ? argA !== argB : core.stringifyVariables(argA) !== core.stringifyVariables(argB)) { return false; } } for (var _key in fieldArgs) { if (_key === offsetArgument || _key === limitArgument) { continue; } if (!(_key in connectionArgs)) return false; } return true; }; return (_parent, fieldArgs, cache, info) => { var { parentKey: entityKey, fieldName } = info; var allFields = cache.inspectFields(entityKey); var fieldInfos = allFields.filter(info => info.fieldName === fieldName); var size = fieldInfos.length; if (size === 0) { return undefined; } var visited = new Set(); var result = []; var prevOffset = null; for (var i = 0; i < size; i++) { var { fieldKey, arguments: args } = fieldInfos[i]; if (args === null || !compareArgs(fieldArgs, args)) { continue; } var links = cache.resolve(entityKey, fieldKey); var currentOffset = args[offsetArgument]; if (links === null || links.length === 0 || typeof currentOffset !== 'number') { continue; } var tempResult = []; for (var j = 0; j < links.length; j++) { var link = links[j]; if (visited.has(link)) continue; tempResult.push(link); visited.add(link); } if ((!prevOffset || currentOffset > prevOffset) === (mergeMode === 'after')) { result = [...result, ...tempResult]; } else { result = [...tempResult, ...result]; } prevOffset = currentOffset; } var hasCurrentPage = cache.resolve(entityKey, fieldName, fieldArgs); if (hasCurrentPage) { return result; } else if (!info.store.schema) { return undefined; } else { info.partial = true; return result; } }; }; exports.relayPagination = relayPagination; exports.simplePagination = simplePagination; //# sourceMappingURL=urql-exchange-graphcache-extras.js.map