in packages/graph-explorer/src/connector/sparql/fetchNeighbors/oneHopNeighborsTemplate.ts [82:205]
export function oneHopNeighborsTemplate({
resourceURI,
subjectClasses = [],
filterCriteria = [],
excludedVertices = new Set(),
limit = 0,
offset = 0,
}: SPARQLNeighborsRequest): string {
const resourceTemplate = idParam(resourceURI);
// templates for filtering by value
const hasFilters = filterCriteria.length > 0;
const filterCriteriaTemplate = filterCriteria
.map(
c =>
`(?pValue=${idParam(c.predicate)} && regex(str(?value), "${c.object}", "i"))`
)
.join(" ||\n");
const filterTemplate = hasFilters
? query`
FILTER(
isLiteral(?value) && (
${filterCriteriaTemplate}
)
)
`
: "";
const valueBindingTemplate = hasFilters ? `?neighbor ?pValue ?value .` : "";
// templates for filtering by class
const subjectClassesTemplate = subjectClasses.length
? `VALUES ?class { ${subjectClasses.map(idParam).join(" ")} }`
: "";
const classBindingTemplate = subjectClasses.length
? `?neighbor a ?class .`
: "";
const limitTemplate = getLimit(limit, offset);
const rdfTypeUriTemplate = idParam(rdfTypeUri);
// Excluded vertices
const excludedVerticesTemplate = excludedVertices.size
? query`FILTER NOT EXISTS {
VALUES ?neighbor {
${excludedVertices.values().map(idParam).toArray().join(" ")}
}
}`
: "";
return query`
SELECT DISTINCT ?subject ?p ?value
WHERE {
{
# This sub-query will give us all unique neighbors within the given limit
SELECT DISTINCT ?neighbor
WHERE {
BIND(${resourceTemplate} AS ?source)
${subjectClassesTemplate}
{
# Incoming neighbors
?neighbor ?pIncoming ?source .
}
UNION
{
# Outgoing neighbors
?source ?pOutgoing ?neighbor .
}
${classBindingTemplate}
${valueBindingTemplate}
${filterTemplate}
${excludedVerticesTemplate}
# Remove any classes from the list of neighbors
FILTER NOT EXISTS {
?anySubject a ?neighbor .
}
}
ORDER BY ?neighbor
${limitTemplate}
}
# Using the ?neighbor gathered above we can start getting
# the information we are really interested in
#
# - predicate to source from neighbor
# - predicate from source to neighbor
# - neighbor class
# - neighbor values
{
# Incoming connection predicate
BIND(${resourceTemplate} AS ?source)
?neighbor ?pToSource ?source
BIND(?neighbor as ?subject)
BIND(?pToSource as ?p)
BIND(?source as ?value)
}
UNION
{
# Outgoing connection predicate
BIND(${resourceTemplate} AS ?source)
?source ?pFromSource ?neighbor
BIND(?neighbor as ?value)
BIND(?pFromSource as ?p)
BIND(?source as ?subject)
}
UNION
{
# Values and types
?neighbor ?p ?value
FILTER(isLiteral(?value) || ?p = ${rdfTypeUriTemplate})
BIND(?neighbor as ?subject)
}
UNION
{
# Source types
BIND(${resourceTemplate} AS ?source)
?source ?p ?value
FILTER(?p = ${rdfTypeUriTemplate})
BIND(?source as ?subject)
}
}
ORDER BY ?subject
`;
}