Files

85 lines
2.9 KiB
TypeScript
Raw Permalink Normal View History

import { useCallback, useEffect, useMemo, useState } from "react";
import { referenceOf, useCaminoQuery, type ExactReference } from "@quixos/camino-react";
import { queries } from "./gen/client.js";
import { asInterface, type JobNode } from "./model.js";
import { mergeCachedAnnotationEntries } from "./work.js";
type Entry = { node: JobNode };
/** Successes outlive request history. Read every retained page instead of
* treating the first bounded graph query as the entire semantic cache. */
export function useCachedAnnotations(reference?: ExactReference | null) {
const query = useCaminoQuery(queries.DocumentView, {
enabled: !!reference,
root: reference ? asInterface(reference, "document") : undefined,
input: {},
admission: { query: queries.DocumentInputs, input: {} },
});
const [pages, setPages] = useState<{ object: string; entries: Record<string, readonly Entry[]> }>({
object: "",
entries: {},
});
const report = useCallback(
(cursor: string, entries: readonly Entry[] | null) => {
const object = reference?.object ?? "";
setPages((previous) => {
const next = previous.object === object ? { ...previous.entries } : {};
if (entries) next[cursor] = entries;
else delete next[cursor];
return { object, entries: next };
});
},
[reference?.object],
);
const node =
query.status === "ready" && referenceOf(query.data.root).object === reference?.object ? query.data.root : null;
const entries = useMemo(
() =>
mergeCachedAnnotationEntries(
[
...(node?.results.entries ?? []),
...(pages.object === reference?.object ? Object.values(pages.entries).flat() : []),
],
node?.jobs.entries ?? [],
),
[node, pages, reference?.object],
);
return {
ready: !!node,
entries,
continuation:
node?.results.pageInfo.hasNextPage && node.results.pageInfo.endCursor ? (
<CachedResultsTail
key={reference!.object}
reference={reference!}
cursor={node.results.pageInfo.endCursor}
report={report}
/>
) : null,
};
}
function CachedResultsTail({
reference,
cursor,
report,
}: {
reference: ExactReference;
cursor: string;
report(cursor: string, entries: readonly Entry[] | null): void;
}) {
const query = useCaminoQuery(queries.CachedResultsView, {
root: asInterface(reference, "document"),
input: { after: cursor },
admission: { query: queries.CachedResultsInputs, input: { after: cursor } },
});
const results = query.status === "ready" ? query.data.root.results : null;
useEffect(() => {
if (results) report(cursor, results.entries);
return () => report(cursor, null);
}, [results, cursor, report]);
return results?.pageInfo.hasNextPage && results.pageInfo.endCursor ? (
<CachedResultsTail reference={reference} cursor={results.pageInfo.endCursor} report={report} />
) : null;
}