UNPKG

convex

Version:

Client for the Convex Cloud

275 lines (274 loc) 8.78 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var use_paginated_query_exports = {}; __export(use_paginated_query_exports, { optimisticallyUpdateValueInPaginatedQuery: () => optimisticallyUpdateValueInPaginatedQuery, resetPaginationId: () => resetPaginationId, usePaginatedQuery: () => usePaginatedQuery }); module.exports = __toCommonJS(use_paginated_query_exports); var import_react = require("react"); var import_values = require("../values/index.js"); var import_use_queries = require("./use_queries.js"); var import_api = require("../server/api.js"); const splitQuery = (key, splitCursor, continueCursor) => (prevState) => { const queries = { ...prevState.queries }; const splitKey1 = prevState.nextPageKey; const splitKey2 = prevState.nextPageKey + 1; const nextPageKey = prevState.nextPageKey + 2; queries[splitKey1] = { query: prevState.query, args: { ...prevState.args, paginationOpts: { ...prevState.queries[key].args.paginationOpts, endCursor: splitCursor } } }; queries[splitKey2] = { query: prevState.query, args: { ...prevState.args, paginationOpts: { ...prevState.queries[key].args.paginationOpts, cursor: splitCursor, endCursor: continueCursor } } }; const ongoingSplits = { ...prevState.ongoingSplits }; ongoingSplits[key] = [splitKey1, splitKey2]; return { ...prevState, nextPageKey, queries, ongoingSplits }; }; const completeSplitQuery = (key) => (prevState) => { const completedSplit = prevState.ongoingSplits[key]; if (completedSplit === void 0) { return prevState; } const queries = { ...prevState.queries }; delete queries[key]; const ongoingSplits = { ...prevState.ongoingSplits }; delete ongoingSplits[key]; let pageKeys = prevState.pageKeys.slice(); const pageIndex = prevState.pageKeys.findIndex((v) => v === key); if (pageIndex >= 0) { pageKeys = [ ...prevState.pageKeys.slice(0, pageIndex), ...completedSplit, ...prevState.pageKeys.slice(pageIndex + 1) ]; } return { ...prevState, queries, pageKeys, ongoingSplits }; }; function usePaginatedQuery(query, args, options) { if (typeof options?.initialNumItems !== "number" || options.initialNumItems < 0) { throw new Error( `\`options.initialNumItems\` must be a positive number. Received \`${options?.initialNumItems}\`.` ); } const skip = args === "skip"; const argsObject = skip ? {} : args; const queryName = (0, import_api.getFunctionName)(query); const createInitialState = (0, import_react.useMemo)(() => { return () => { const id = nextPaginationId(); return { query, args: argsObject, id, nextPageKey: 1, pageKeys: skip ? [] : [0], queries: skip ? {} : { 0: { query, args: { ...argsObject, paginationOpts: { numItems: options.initialNumItems, cursor: null, id } } } }, ongoingSplits: {}, skip }; }; }, [ // eslint-disable-next-line react-hooks/exhaustive-deps JSON.stringify((0, import_values.convexToJson)(argsObject)), queryName, options.initialNumItems, skip ]); const [state, setState] = (0, import_react.useState)(createInitialState); let currState = state; if ((0, import_api.getFunctionName)(query) !== (0, import_api.getFunctionName)(state.query) || JSON.stringify((0, import_values.convexToJson)(argsObject)) !== JSON.stringify((0, import_values.convexToJson)(state.args)) || skip !== state.skip) { currState = createInitialState(); setState(currState); } const resultsObject = (0, import_use_queries.useQueries)(currState.queries); const [results, maybeLastResult] = (0, import_react.useMemo)(() => { let currResult = void 0; const allItems = []; for (const pageKey of currState.pageKeys) { currResult = resultsObject[pageKey]; if (currResult === void 0) { break; } if (currResult instanceof Error) { if (currResult.message.includes("InvalidCursor")) { console.warn( "usePaginatedQuery hit error, resetting pagination state: " + currResult.message ); setState(createInitialState); return [[], void 0]; } else { throw currResult; } } const ongoingSplit = currState.ongoingSplits[pageKey]; if (ongoingSplit !== void 0) { if (resultsObject[ongoingSplit[0]] !== void 0 && resultsObject[ongoingSplit[1]] !== void 0) { setState(completeSplitQuery(pageKey)); } } else if (currResult.splitCursor && (currResult.pageStatus === "SplitRecommended" || currResult.pageStatus === "SplitRequired" || currResult.page.length > options.initialNumItems * 2)) { setState( splitQuery( pageKey, currResult.splitCursor, currResult.continueCursor ) ); } if (currResult.pageStatus === "SplitRequired") { return [allItems, void 0]; } allItems.push(...currResult.page); } return [allItems, currResult]; }, [ resultsObject, currState.pageKeys, currState.ongoingSplits, options.initialNumItems, createInitialState ]); const statusObject = (0, import_react.useMemo)(() => { if (maybeLastResult === void 0) { if (currState.nextPageKey === 1) { return { status: "LoadingFirstPage", isLoading: true, loadMore: (_numItems) => { } }; } else { return { status: "LoadingMore", isLoading: true, loadMore: (_numItems) => { } }; } } if (maybeLastResult.isDone) { return { status: "Exhausted", isLoading: false, loadMore: (_numItems) => { } }; } const continueCursor = maybeLastResult.continueCursor; let alreadyLoadingMore = false; return { status: "CanLoadMore", isLoading: false, loadMore: (numItems) => { if (!alreadyLoadingMore) { alreadyLoadingMore = true; setState((prevState) => { const pageKeys = [...prevState.pageKeys, prevState.nextPageKey]; const queries = { ...prevState.queries }; queries[prevState.nextPageKey] = { query: prevState.query, args: { ...prevState.args, paginationOpts: { numItems, cursor: continueCursor, id: prevState.id } } }; return { ...prevState, nextPageKey: prevState.nextPageKey + 1, pageKeys, queries }; }); } } }; }, [maybeLastResult, currState.nextPageKey]); return { results, ...statusObject }; } let paginationId = 0; function nextPaginationId() { paginationId++; return paginationId; } function resetPaginationId() { paginationId = 0; } function optimisticallyUpdateValueInPaginatedQuery(localStore, query, args, updateValue) { const expectedArgs = JSON.stringify((0, import_values.convexToJson)(args)); for (const queryResult of localStore.getAllQueries(query)) { if (queryResult.value !== void 0) { const { paginationOpts: _, ...innerArgs } = queryResult.args; if (JSON.stringify((0, import_values.convexToJson)(innerArgs)) === expectedArgs) { const value = queryResult.value; if (typeof value === "object" && value !== null && Array.isArray(value.page)) { localStore.setQuery(query, queryResult.args, { ...value, page: value.page.map(updateValue) }); } } } } } //# sourceMappingURL=use_paginated_query.js.map