hra-api
Version:
The Human Reference Atlas (HRA) API deployed to https://apps.humanatlas.io/api/
337 lines (326 loc) • 14.6 kB
JavaScript
// src/library/hra-kg/operations/digital-objects.js
import { coerce, rsort } from "semver";
// src/library/shared/utils/sparql.js
import jsonld from "jsonld";
import Papa from "papaparse";
jsonld.documentLoader = async (documentUrl) => {
const document = await fetch(documentUrl).then((r) => r.json());
return {
contextUrl: null,
document,
documentUrl
};
};
function fetchSparql(query, endpoint, mimetype) {
const body = new URLSearchParams({ query });
return fetch(endpoint, {
method: "POST",
headers: {
Accept: mimetype,
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": body.toString().length.toString()
},
body
});
}
async function select(query, endpoint) {
const resp = await fetchSparql(query, endpoint, "text/csv");
const text = await resp.text();
const { data } = Papa.parse(text, { header: true, skipEmptyLines: true, dynamicTyping: true });
return data || [];
}
async function construct(query, endpoint, frame = void 0) {
const resp = await fetchSparql(query, endpoint, "application/ld+json");
const json = await resp.json();
if (frame) {
return await jsonld.frame(json, frame);
} else {
return json;
}
}
// src/library/v1/utils/jsonld-compat.js
function expandIri(iri) {
return iri && typeof iri === "string" ? iri.replace("ccf:", "http://purl.org/ccf/").replace("ccf1:", "http://purl.org/\
ccf/latest/ccf.owl#").replace("../sig/ont/fma/fma", "http://purl.org/sig/ont/fma/fma").replace("fma:", "http://purl.org/\
sig/ont/fma/fma").replace("http://purl.obolibrary.org/obo/FMA_", "http://purl.org/sig/ont/fma/fma") : iri;
}
var DEFAULT_STRING_FIELDS = ["creator", "creator_first_name", "creator_last_name"];
function normalizeJsonLd(jsonld2, arrayFields = /* @__PURE__ */ new Set(), stringFields = new Set(DEFAULT_STRING_FIELDS), singleValueFields = /* @__PURE__ */ new Set()) {
return JSON.parse(JSON.stringify(jsonld2), (key, value) => {
if (singleValueFields.has(key)) {
value = ensureSingleValue(value);
}
if (arrayFields.has(key)) {
value = ensureArray(value);
}
if (stringFields.has(key)) {
value = ensureString(value);
}
if (typeof value === "object" && value?.["@type"] && value["@value"] && (value["@type"].startsWith("xsd:") || value["\
@type"].startsWith("http://www.w3.org/2001/XMLSchema#"))) {
switch (value["@type"]) {
case "http://www.w3.org/2001/XMLSchema#integer":
case "http://www.w3.org/2001/XMLSchema#double":
case "http://www.w3.org/2001/XMLSchema#decimal":
case "xsd:integer":
case "xsd:double":
case "xsd:decimal":
return Number(value["@value"]);
case "http://www.w3.org/2001/XMLSchema#date":
case "xsd:date":
return value["@value"];
default:
return value;
}
} else if (Array.isArray(value)) {
return value.map(expandIri);
} else {
return expandIri(value);
}
});
}
function ensureSingleValue(value) {
if (Array.isArray(value)) {
return value[0];
} else {
return value;
}
}
function ensureString(value, arrayElementSeparator = "; ") {
if (Array.isArray(value)) {
return value.map(ensureString).join(arrayElementSeparator);
} else if (value?.["@value"]) {
return value["@value"];
} else {
return value;
}
}
function ensureArray(thing) {
if (Array.isArray(thing)) {
return thing;
} else if (thing) {
return [thing];
} else {
return [];
}
}
function ensureNumber(value) {
if (value?.["@type"]) {
return Number(value["@value"]);
} else if (typeof value === "string") {
return Number(value);
} else {
return value;
}
}
function ensureGraphArray(results) {
if (results?.["@graph"]) {
return results["@graph"];
} else if (results?.["@id"]) {
delete results["@context"];
return [results];
} else {
return [];
}
}
// src/library/hra-kg/frames/digital-objects.jsonld
var digital_objects_default = {
"@context": {
dcat: "http://www.w3.org/ns/dcat#",
dct: "http://purl.org/dc/terms/",
schema: "http://schema.org/",
ccf: "http://purl.org/ccf/",
rdfs: "http://www.w3.org/2000/01/rdf-schema#",
purl: {
"@id": "rdfs:seeAlso",
"@type": "@id"
},
lod: {
"@id": "dcat:last",
"@type": "@id"
},
title: "dct:title",
doType: "schema:additionalType",
doName: "schema:name",
doVersion: "ccf:latestVersion",
lastUpdated: "schema:dateCreated",
hraVersions: {
"@id": "ccf:hraVersion"
},
versions: {
"@id": "schema:version"
},
datasets: {
"@id": "dcat:dataset",
"@type": "@id"
},
cell_count: {
"@id": "ccf:cell_count",
"@type": "http://www.w3.org/2001/XMLSchema#integer"
},
biomarker_count: {
"@id": "ccf:biomarker_count",
"@type": "http://www.w3.org/2001/XMLSchema#integer"
},
organs: "ccf:organ",
organIds: {
"@id": "ccf:organ_id",
"@type": "@id"
}
},
"@type": "dcat:Catalog"
};
// src/library/hra-kg/queries/digital-objects.rq
var digital_objects_default2 = "PREFIX ccf: <http://purl.org/ccf/>\nPREFIX dcat: <http://www.w3.org/ns/dcat#>\nPREFIX dct:\
<http://purl.org/dc/terms/>\nPREFIX hint: <http://www.bigdata.com/queryHints#> \nPREFIX owl: <http://www.w3.org/2002/07/o\
wl#>\nPREFIX prov: <http://www.w3.org/ns/prov#>\nPREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\nPREFIX skos: <http:/\
/www.w3.org/2004/02/skos/core#>\nPREFIX schema: <http://schema.org/>\nPREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\nPREF\
IX LOD: <https://lod.humanatlas.io>\nPREFIX HRA: <https://purl.humanatlas.io/collection/hra-api>\nPREFIX body: <http://pur\
l.obolibrary.org/obo/UBERON_0013702>\n\nCONSTRUCT {\n ?lod a dcat:Catalog ;\n dcat:last ?latestLodPurl ;\n rdfs:seeAls\
o ?graphPurl ;\n dct:title ?title ;\n schema:additionalType ?doType ;\n schema:name ?doName ;\n ccf:latestVersio\
n ?doVersion ;\n ccf:hraVersion ?hraVersion ;\n schema:version ?version ;\n schema:dateCreated ?lastUpdated ;\n \
dcat:dataset ?lodPurl ;\n ccf:organ ?organ ;\n ccf:organ_id ?organ_id ;\n ccf:cell_count ?unique_cells ;\n ccf:b\
iomarker_count ?unique_biomarkers .\n}\nWHERE {\n GRAPH LOD: {\n ?lod a dcat:Catalog ;\n dcat:dataset ?lodPurl .\n \n\
?lodPurl a dcat:Dataset ;\n schema:version ?version ;\n rdfs:seeAlso ?graphPurlVersioned .\n\n BIND(IRI(STR\
BEFORE(STR(?graphPurlVersioned), CONCAT('/', ?version))) as ?graphPurl)\n }\n\n {\n SELECT DISTINCT *\n WHERE {\n \
GRAPH ?graphPurl {\n ?graphPurl rdfs:seeAlso ?latestLodPurl .\n }\n\n GRAPH LOD: {\n # organ, unique\
_cells, unique_biomarkers\n ?lod a dcat:Catalog ;\n dcat:dataset ?latestLodPurl .\n \n ?latest\
LodPurl\n schema:additionalType ?doType ;\n schema:name ?doName ;\n schema:version ?doVersion ;\n\
prov:wasDerivedFrom [\n dct:title ?title ;\n schema:dateCreated ?lastUpdated ;\n ]\
.\n }\n }\n }\n\n OPTIONAL {\n GRAPH LOD: {\n [] a dcat:Dataset ;\n schema:additionalType ?hraType ;\
\n schema:name ?hraName ;\n schema:version ?hraVersion ;\n prov:hadMember ?graphPurlVersioned .\n\
FILTER(?hraType = 'collection' && ?hraName = 'hra')\n }\n }\n\n OPTIONAL {\n SELECT DISTINCT ?graphPurl ?organ \
?organ_id {\n {\n SELECT (SAMPLE(?organ) as ?organ) ?organ_id\n WHERE {\n GRAPH HRA: {\n \
?refOrgan a ccf:SpatialEntity ;\n ccf:has_reference_organ ?refOrgan ;\n ccf:representatio\
n_of ?refOrganTerm .\n \n ?organ_id ccf:ccf_part_of body: .\n ?organ_id ccf:ccf_pref_label\
?organ_label .\n ?refOrganTerm ccf:ccf_part_of* ?organ_id .\n FILTER(!CONTAINS(STR(?organ_label), '\
system'))\n \n BIND(LCASE(?organ_label) as ?organ)\n }\n }\n GROUP BY ?organ_id\n \
ORDER BY ?organ\n }\n GRAPH HRA: {\n ?organ_id dct:isReferencedBy ?graphPurl .\n }\n }\n }\n\n \
OPTIONAL {\n SELECT ?graphPurl (COUNT(DISTINCT ?cell_id) as ?unique_cells) {\n GRAPH HRA: {\n ?cell_id ccf:\
ccf_asctb_type ?type ;\n dct:isReferencedBy ?graphPurl .\n FILTER(?type = 'CT')\n }\n }\n GROUP BY\
?graphPurl\n }\n\n OPTIONAL {\n SELECT ?graphPurl (COUNT(DISTINCT ?biomarker) as ?unique_biomarkers) {\n GRAPH HRA\
: {\n ?biomarker ccf:ccf_asctb_type ?type ;\n dct:isReferencedBy ?graphPurl .\n FILTER(?type = 'BM')\
\n }\n }\n GROUP BY ?graphPurl\n }\n}";
// src/library/hra-kg/operations/digital-objects.js
function reformatResponse(jsonld2) {
const results = normalizeJsonLd(ensureGraphArray(jsonld2), /* @__PURE__ */ new Set(["hraVersions", "versions", "organs",
"organIds"]));
for (const result of results) {
result.hraVersions = sortVersions(result.hraVersions || []);
result.versions = sortVersions(result.versions);
results.cell_count = ensureNumber(results.cell_count) || 0;
results.biomarker_count = ensureNumber(results.biomarker_count) || 0;
}
return {
"@context": jsonld2["@context"],
"@graph": results
};
}
async function getDigitalObjects(endpoint = "https://lod.humanatlas.io/sparql") {
endpoint = "https://lod.humanatlas.io/sparql";
return reformatResponse(await construct(digital_objects_default2, endpoint, digital_objects_default));
}
function sortVersions(versions) {
return rsort(
versions.map((version) => {
const semver = coerce(version, true);
semver.original = version;
return semver;
})
).map((semver) => semver.original);
}
// src/library/hra-kg/queries/do-search.rq
var do_search_default = "PREFIX ccf: <http://purl.org/ccf/>\nPREFIX dcat: <http://www.w3.org/ns/dcat#>\nPREFIX dct: <http:\
//purl.org/dc/terms/>\nPREFIX hint: <http://www.bigdata.com/queryHints#> \nPREFIX owl: <http://www.w3.org/2002/07/owl#>\nPR\
EFIX prov: <http://www.w3.org/ns/prov#>\nPREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\nPREFIX skos: <http://www.w3\
.org/2004/02/skos/core#>\nPREFIX schema: <http://schema.org/>\nPREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\nPREFIX LOD:\
<https://lod.humanatlas.io>\nPREFIX HRA: <https://purl.humanatlas.io/collection/hra-api>\nPREFIX body: <http://purl.oboli\
brary.org/obo/UBERON_0013702>\n\nSELECT DISTINCT ?purl\nWHERE {\n GRAPH LOD: {\n ?lod a dcat:Catalog ;\n dcat:dataset\
?lodPurl .\n \n ?lodPurl a dcat:Dataset ;\n schema:version ?version ;\n rdfs:seeAlso ?graphPurlVersioned .\n\n \
BIND(IRI(STRBEFORE(STR(?graphPurlVersioned), CONCAT('/', ?version))) as ?purl)\n }\n #{{FILTER}}\n}\nORDER BY ?purl\n";
// src/library/hra-kg/utils/filter-sparql-query.js
function termFilter(terms) {
const quotedTerms = terms.map((s) => `(<${s}>)`).join(" ");
return `
{
SELECT DISTINCT ?purl
WHERE {
VALUES (?term) { ${quotedTerms} }
GRAPH HRA: {
?term dct:isReferencedBy ?purl .
}
}
}`;
}
function hraVersionFilter(versions) {
const quotedVersions = versions.map((v) => `'${v}'`).join(", ");
return `
FILTER EXISTS {
GRAPH LOD: {
[] a dcat:Dataset ;
schema:version ?version ;
rdfs:seeAlso ?graphPurlVersioned .
[] a dcat:Dataset ;
schema:additionalType ?hraType ;
schema:name ?hraName ;
schema:version ?hraVersion ;
prov:hadMember ?graphPurlVersioned .
FILTER(?hraType = 'collection' && ?hraName = 'hra' && ?hraVersion IN (${quotedVersions}))
BIND(IRI(STRBEFORE(STR(?graphPurlVersioned), CONCAT('/', ?version))) as ?purl)
}
}
`;
}
function getFilterQuery(filter) {
const { ontologyTerms, cellTypeTerms, biomarkerTerms, hraVersions } = filter;
const filters = [];
if (ontologyTerms?.length > 0) {
filters.push(termFilter(ontologyTerms));
}
if (cellTypeTerms?.length > 0) {
filters.push(termFilter(cellTypeTerms));
}
if (biomarkerTerms?.length > 0) {
filters.push(termFilter(biomarkerTerms));
}
if (hraVersions?.length > 0) {
filters.push(hraVersionFilter(hraVersions));
}
return filters.join("\n");
}
async function filterSparqlQuery(sparqlQuery, filter = {}, endpoint = "https://lod.humanatlas.io/sparql") {
const sparqlFilter = getFilterQuery(filter, endpoint);
const filteredQuery = sparqlQuery.replace("#{{FILTER}}", sparqlFilter);
return filteredQuery;
}
// src/library/hra-kg/operations/do-search.js
function reformatResponse2(records) {
return records.map((row) => row.purl);
}
async function doSearch(filter, endpoint = "https://lod.humanatlas.io/sparql") {
const filteredQuery = await filterSparqlQuery(do_search_default, filter, endpoint);
const results = reformatResponse2(await select(filteredQuery, endpoint));
return results;
}
// src/library/hra-kg/queries/asctb-term-occurences.rq
var asctb_term_occurences_default = "PREFIX ccf: <http://purl.org/ccf/>\nPREFIX dcat: <http://www.w3.org/ns/dcat#>\nPREFIX\
dct: <http://purl.org/dc/terms/>\nPREFIX hint: <http://www.bigdata.com/queryHints#> \nPREFIX owl: <http://www.w3.org/2002\
/07/owl#>\nPREFIX prov: <http://www.w3.org/ns/prov#>\nPREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\nPREFIX skos: <h\
ttp://www.w3.org/2004/02/skos/core#>\nPREFIX schema: <http://schema.org/>\nPREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\
\nPREFIX LOD: <https://lod.humanatlas.io>\nPREFIX HRA: <https://purl.humanatlas.io/collection/hra-api>\nPREFIX body: <http:\
//purl.obolibrary.org/obo/UBERON_0013702>\n\nSELECT ?iri (COUNT(DISTINCT ?purl) as ?count)\nWHERE {\n GRAPH HRA: {\n ?iri\
ccf:ccf_asctb_type [] ;\n dct:isReferencedBy ?purl .\n #{{FILTER}}\n }\n}\nGROUP BY ?iri\n";
// src/library/hra-kg/operations/asctb-term-occurences.js
function reformatResponse3(records) {
return records.reduce((acc, row) => (acc[row["iri"]] = row["count"], acc), {});
}
async function getAsctbTermOccurences(filter, endpoint = "https://lod.humanatlas.io/sparql") {
const filteredQuery = await filterSparqlQuery(asctb_term_occurences_default, filter, endpoint);
const results = reformatResponse3(await select(filteredQuery, endpoint));
return results;
}
export {
doSearch,
getAsctbTermOccurences,
getDigitalObjects
};