convex
Version:
Client for the Convex Cloud
275 lines (274 loc) • 8.78 kB
JavaScript
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
;