109 lines
3.2 KiB
TypeScript
109 lines
3.2 KiB
TypeScript
// import { useSWR } from "sswr";
|
|
import { useSWR } from "../util/fetch";
|
|
import { derived, Readable, readable, writable } from "svelte/store";
|
|
import type { IEntry, ListingResult, OrderedListing } from "upend/types";
|
|
import { listingAsOrdered } from "upend";
|
|
import LRU from "lru-cache";
|
|
import { attr } from "svelte/internal";
|
|
|
|
export function useEntity(
|
|
address: string | (() => string),
|
|
condition?: () => Boolean
|
|
) {
|
|
const { data, error, revalidate } = useSWR<ListingResult, unknown>(() =>
|
|
condition === undefined || condition()
|
|
? `/api/obj/${typeof address === "string" ? address : address()}`
|
|
: null
|
|
);
|
|
|
|
const entries = derived(data, ($values) =>
|
|
$values ? listingAsOrdered($values) : []
|
|
);
|
|
const attributes = derived(entries, ($entries) => {
|
|
const addr = typeof address === "string" ? address : address();
|
|
return $entries.filter(([_, e]) => e.entity === addr);
|
|
});
|
|
const backlinks = derived(entries, ($entries) => {
|
|
const addr = typeof address === "string" ? address : address();
|
|
return $entries.filter(([_, e]) => e.entity !== addr);
|
|
});
|
|
|
|
return {
|
|
entries,
|
|
attributes,
|
|
backlinks,
|
|
data,
|
|
error,
|
|
revalidate,
|
|
};
|
|
}
|
|
|
|
export function query(query: () => string) {
|
|
let queryString = typeof query === "string" ? query : query();
|
|
console.debug(`Querying: ${queryString}`);
|
|
const { data, error, revalidate } = useSWR<ListingResult, unknown>(
|
|
() => `/api/obj?query=${query()}`
|
|
);
|
|
|
|
const result = derived(data, ($values) => {
|
|
return $values ? listingAsOrdered($values) : [];
|
|
});
|
|
|
|
return {
|
|
result,
|
|
data,
|
|
error,
|
|
revalidate,
|
|
};
|
|
}
|
|
|
|
const queryOnceLRU = new LRU<string, OrderedListing>(128);
|
|
const inFlightRequests: { [key: string]: Promise<OrderedListing> } = {};
|
|
|
|
export async function queryOnce(query: string): Promise<OrderedListing> {
|
|
const cacheResult = queryOnceLRU.get(query);
|
|
if (!cacheResult) {
|
|
const url = `/api/obj?query=${query}`;
|
|
let response;
|
|
if (!inFlightRequests[url]) {
|
|
console.debug(`Querying: ${query}`);
|
|
inFlightRequests[url] = new Promise(async (resolve, reject) => {
|
|
const response = await fetch(url, { keepalive: true });
|
|
resolve(listingAsOrdered(await response.json()));
|
|
});
|
|
} else {
|
|
console.debug(`Chaining request for ${query}...`);
|
|
}
|
|
return await inFlightRequests[url];
|
|
} else {
|
|
console.debug(`Returning cached: ${query}`);
|
|
return cacheResult;
|
|
}
|
|
}
|
|
|
|
export async function identify(
|
|
attributes: OrderedListing,
|
|
backlinks: OrderedListing
|
|
): Promise<string[]> {
|
|
// Get all entries where the object is linked
|
|
const hasEntries = backlinks
|
|
.filter(([_, entry]) => entry.attribute === "HAS")
|
|
.map(([addr, _]) => addr);
|
|
|
|
// Out of those relations, retrieve their ALIAS attrs
|
|
const hasAliases = hasEntries.length
|
|
? await queryOnce(
|
|
`(matches (in ${hasEntries.map((e) => `"${e}"`).join(" ")}) "ALIAS" ?)`
|
|
)
|
|
: [];
|
|
|
|
const aliasValues = hasAliases.map(([_, entry]) => {
|
|
return entry.value.c;
|
|
});
|
|
|
|
// Return all LBLs concatenated with named aliases
|
|
return attributes
|
|
.filter(([_, attr]) => attr.attribute === "LBL")
|
|
.map(([_, attr]) => attr.value.c)
|
|
.concat(aliasValues);
|
|
}
|