You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
4.6 KiB
159 lines
4.6 KiB
import type { Dataset, Literal, Quad, Quad_Object } from "@rdfjs/types";
|
|
import type { ObjectNode, PredicateNode, SubjectNode } from "@ldo/rdf-utils";
|
|
import { createDataset } from "@ldo/dataset";
|
|
import type { LanguageKey, LanguageOrdering } from "./languageTypes";
|
|
|
|
/**
|
|
*
|
|
* @param dataset
|
|
* @param subject
|
|
* @param predicate
|
|
* @param languageKey
|
|
* @returns
|
|
*/
|
|
export function languageMatch(
|
|
dataset: Dataset,
|
|
subject: ObjectNode,
|
|
predicate: PredicateNode,
|
|
languageKey: LanguageKey,
|
|
): Dataset<LiteralObjectQuad> {
|
|
const literalLanguage = languageKeyToLiteralLanguage(languageKey);
|
|
return dataset.match(subject, predicate).filter((quad) => {
|
|
return (
|
|
isLanguageLiteral(quad.object) && quad.object.language === literalLanguage
|
|
);
|
|
}) as Dataset<LiteralObjectQuad>;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param dataset
|
|
* @param subject
|
|
* @param predicate
|
|
* @param languageKey
|
|
*/
|
|
export function languageDeleteMatch(
|
|
dataset: Dataset,
|
|
subject: SubjectNode,
|
|
predicate: PredicateNode,
|
|
languageKey: LanguageKey,
|
|
): void {
|
|
const quadsToDelete = languageMatch(dataset, subject, predicate, languageKey);
|
|
quadsToDelete.forEach((quad) => {
|
|
dataset.delete(quad);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Given a node, will return true if that node is a literal that could have a
|
|
* language. This does not guarantee that it is a language literal.
|
|
* @param node the node to test
|
|
* @returns boolean
|
|
*/
|
|
export function isLanguageLiteral(node: Quad_Object): node is Literal {
|
|
return (
|
|
node.termType === "Literal" &&
|
|
(node.datatype.value ===
|
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#langString" ||
|
|
node.datatype.value === "http://www.w3.org/2001/XMLSchema#string")
|
|
);
|
|
}
|
|
|
|
export interface LiteralObjectQuad extends Quad {
|
|
object: Literal;
|
|
}
|
|
|
|
export function quadsToLanguageQuadMap(
|
|
quads: Dataset,
|
|
): Record<LanguageKey, Dataset<LiteralObjectQuad>> {
|
|
const languageQuadMap: Record<LanguageKey, Dataset<LiteralObjectQuad>> = {};
|
|
quads.forEach((quad) => {
|
|
const literal = quad.object;
|
|
if (isLanguageLiteral(literal)) {
|
|
const languageKey = literalLanguageToLanguageKey(literal.language);
|
|
if (!languageQuadMap[languageKey]) {
|
|
languageQuadMap[languageKey] =
|
|
createDataset() as Dataset<LiteralObjectQuad>;
|
|
}
|
|
languageQuadMap[languageKey].add(quad as LiteralObjectQuad);
|
|
}
|
|
});
|
|
return languageQuadMap;
|
|
}
|
|
|
|
export function filterQuadsByLanguageOrdering(
|
|
quads: Dataset,
|
|
languageOrdering: LanguageOrdering,
|
|
): Dataset {
|
|
const languageQuadMap = quadsToLanguageQuadMap(quads);
|
|
const validLanguages = new Set(languageOrdering);
|
|
const presentLanguages = new Set(Object.keys(languageQuadMap));
|
|
for (const currentLanguageKey of languageOrdering) {
|
|
if (presentLanguages.has(currentLanguageKey)) {
|
|
return languageQuadMap[currentLanguageKey];
|
|
}
|
|
if (currentLanguageKey === "@other") {
|
|
for (const presentLang of presentLanguages) {
|
|
if (!validLanguages.has(presentLang)) {
|
|
return languageQuadMap[presentLang];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return createDataset();
|
|
}
|
|
|
|
export function getLanguageKeyForWriteOperation(
|
|
languageOrdering: LanguageOrdering,
|
|
): LanguageKey | undefined {
|
|
return languageOrdering.find((lang) => lang !== "@other");
|
|
}
|
|
|
|
// function addToDatasetMap(
|
|
// key: string,
|
|
// value: Quad,
|
|
// map: Record<string, Dataset>
|
|
// ) {
|
|
// if (!map[key]) {
|
|
// map[key] = createDataset();
|
|
// }
|
|
// map[key].add(value);
|
|
// }
|
|
|
|
// export function filterDatasetByLanguageOrdering(
|
|
// dataset: Dataset,
|
|
// proxyContext: ProxyContext
|
|
// ): Dataset {
|
|
// // TODO: This is an O(n) task that could be reduced to O(1) if we cached some
|
|
// // of the processing
|
|
// const validLangs = new Set(proxyContext.languageOrdering);
|
|
// const sortedLangs: Record<string, Dataset> = {};
|
|
// dataset.forEach((quad) => {
|
|
// const literal = quad.object;
|
|
// if (isLangStringNode(literal)) {
|
|
// if (literal.language === "") {
|
|
// addToDatasetMap("@none", quad, sortedLangs);
|
|
// } else if (validLangs.has(literal.language)) {
|
|
// addToDatasetMap(literal.language, quad, sortedLangs);
|
|
// } else {
|
|
// addToDatasetMap("@other", quad, sortedLangs);
|
|
// }
|
|
// }
|
|
// });
|
|
// for (const language of proxyContext.languageOrdering) {
|
|
// if (sortedLangs[language]) {
|
|
// return sortedLangs[language];
|
|
// }
|
|
// }
|
|
// return createDataset();
|
|
// }
|
|
|
|
export function languageKeyToLiteralLanguage(
|
|
languageKey: string | symbol,
|
|
): string {
|
|
return (languageKey === "@none" ? "" : languageKey) as string;
|
|
}
|
|
|
|
export function literalLanguageToLanguageKey(literalLanguage: string): string {
|
|
return literalLanguage === "" ? "@none" : literalLanguage;
|
|
}
|
|
|