upend/ui/src/lib/entity.ts

107 lines
3.1 KiB
TypeScript
Raw Normal View History

2021-11-11 23:37:42 +01:00
// 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";
2021-12-18 15:12:22 +01:00
import { listingAsOrdered, UpEntry } from "upend";
2021-11-11 23:37:42 +01:00
import LRU from "lru-cache";
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> } = {};
2021-11-11 23:37:42 +01:00
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) => {
2021-11-28 17:25:39 +01:00
const response = await fetch(url, { keepalive: true });
resolve(listingAsOrdered(await response.json()));
});
} else {
console.debug(`Chaining request for ${query}...`);
}
return await inFlightRequests[url];
2021-11-11 23:37:42 +01:00
} else {
console.debug(`Returning cached: ${query}`);
return cacheResult;
}
}
export async function identify(
2021-12-18 15:12:22 +01:00
attributes: UpEntry[],
backlinks: UpEntry[]
2021-12-02 23:21:03 +01:00
): Promise<string[]> {
2021-11-11 23:37:42 +01:00
// Get all entries where the object is linked
const hasEntries = backlinks
2021-12-18 15:12:22 +01:00
.filter((entry) => entry.attribute === "HAS")
.map((entry) => entry.address);
2021-11-11 23:37:42 +01:00
// Out of those relations, retrieve their ALIAS attrs
const hasAliases = hasEntries.length
? await queryOnce(
`(matches (in ${hasEntries.map((e) => `"${e}"`).join(" ")}) "ALIAS" ?)`
)
: [];
2021-12-18 15:12:22 +01:00
const aliasValues = hasAliases.map(([_, entry]) => String(entry.value.c));
2021-11-11 23:37:42 +01:00
2021-12-02 23:21:03 +01:00
// Return all LBLs concatenated with named aliases
return attributes
2021-12-18 15:12:22 +01:00
.filter((attr) => attr.attribute === "LBL")
.map((attr) => String(attr.value.c))
2021-12-02 23:21:03 +01:00
.concat(aliasValues);
2021-11-11 23:37:42 +01:00
}