@ldhop/react
Version:
Follow your nose through linked data resources - for React
124 lines • 6.02 kB
JavaScript
import { fetchRdfDocument, getVariableNames, LdhopEngine, } from '@ldhop/core';
import { useQueries } from '@tanstack/react-query';
import { Quad, Store } from 'n3';
import { useEffect, useMemo, useRef, useState } from 'react';
export const DEFAULT_QUERY_KEY = 'rdfDocument';
const defaultQueryKeyFn = (resource) => [
DEFAULT_QUERY_KEY,
resource,
];
let globalQueryKeyFn = defaultQueryKeyFn;
export const configureQueryKey = (fn) => {
globalQueryKeyFn = fn;
};
const getEmptyVariables = (query) => {
return Object.fromEntries(Array.from(getVariableNames(query)).map(v => [v.substring(1), new Set()]));
};
export const useLdhopQuery = ({ query: queryInput, variables, fetch, getQueryKey = globalQueryKeyFn, staleTime = Infinity, }) => {
const [resources, setResources] = useState([]);
// convert query to array format
const query = useMemo(() => [...queryInput], [queryInput]);
const [outputVariables, setOutputVariables] = useState(getEmptyVariables(query));
const [outputStore, setOutputStore] = useState(new Store());
const [outputQuads, setOutputQuads] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [isFetching, setIsFetching] = useState(true);
// added resources with their hashed values
const resourceRef = useRef(new Map());
const engineRef = useRef(null);
useEffect(() => {
setIsLoading(true);
const store = new Store();
setResources([]);
setOutputStore(store);
setOutputQuads([]);
setOutputVariables(getEmptyVariables(query));
resourceRef.current = new Map();
engineRef.current = new LdhopEngine(query, variables, store, {
onNeedResource: uri => {
setIsLoading(true);
setResources(resources => resources.includes(uri) ? resources : [...resources, uri]);
},
onDropResource: uri => {
var _a;
setResources(resources => resources.includes(uri)
? resources.filter(resource => resource !== uri)
: resources);
(_a = resourceRef.current) === null || _a === void 0 ? void 0 : _a.delete(uri);
},
onVariableAdded() {
const ov = this.getAllPlainVariables();
if (ov)
setOutputVariables(ov);
},
onVariableRemoved() {
const ov = this.getAllPlainVariables();
if (ov)
setOutputVariables(ov);
},
onQueryComplete() {
setIsLoading(false);
},
onQuadsChanged() {
var _a;
const quads = (_a = this.store.getQuads(null, null, null, null)) !== null && _a !== void 0 ? _a : [];
setOutputQuads(quads);
},
});
setOutputStore(engineRef.current.store);
return () => {
var _a, _b, _c, _d, _e, _f;
(_a = engineRef.current) === null || _a === void 0 ? true : delete _a.onDropResource;
(_b = engineRef.current) === null || _b === void 0 ? true : delete _b.onNeedResource;
(_c = engineRef.current) === null || _c === void 0 ? true : delete _c.onQuadsChanged;
(_d = engineRef.current) === null || _d === void 0 ? true : delete _d.onQueryComplete;
(_e = engineRef.current) === null || _e === void 0 ? true : delete _e.onVariableAdded;
(_f = engineRef.current) === null || _f === void 0 ? true : delete _f.onVariableRemoved;
engineRef.current = null;
};
}, [query, variables]);
const results = useQueries(useMemo(() => ({
queries: resources.map(resource => ({
queryKey: getQueryKey(resource),
queryFn: () => fetchRdfDocument(resource, fetch),
staleTime,
})),
}), [fetch, getQueryKey, resources, staleTime]));
useEffect(() => {
var _a, _b;
const graphs = (_b = (_a = engineRef.current) === null || _a === void 0 ? void 0 : _a.getGraphs()) !== null && _b !== void 0 ? _b : new Set();
results.forEach((result, i) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
const resource = resources[i];
// if the resource is not needed, don't add it
if (!graphs.has(resource))
return;
if (result.isSuccess) {
// if the exact same graph is already added, ignore
if (((_a = resourceRef.current) === null || _a === void 0 ? void 0 : _a.get(resource)) === ((_b = result.data) === null || _b === void 0 ? void 0 : _b.hash))
return;
(_c = engineRef.current) === null || _c === void 0 ? void 0 : _c.addGraph((_e = (_d = result.data.response) === null || _d === void 0 ? void 0 : _d.url) !== null && _e !== void 0 ? _e : resources[i], result.data.data, resources[i]);
// remember the graph
(_f = resourceRef.current) === null || _f === void 0 ? void 0 : _f.set(resource, result.data.hash);
}
else if (result.isError) {
if (((_g = resourceRef.current) === null || _g === void 0 ? void 0 : _g.get(resource)) === 'error')
return;
(_h = engineRef.current) === null || _h === void 0 ? void 0 : _h.addGraph(resources[i], []);
(_j = resourceRef.current) === null || _j === void 0 ? void 0 : _j.set(resource, 'error');
}
});
const isFetching = results.some(r => r.isFetching);
setIsFetching(isFetching);
}, [resources, results]);
return useMemo(() => ({
store: outputStore,
quads: outputQuads,
variables: outputVariables,
engine: engineRef.current,
isLoading,
isMissing: false,
isFetching,
}), [isFetching, isLoading, outputQuads, outputStore, outputVariables]);
};
//# sourceMappingURL=useLdhopQuery.js.map