Skip to content

Commit

Permalink
feat: allow multiple template SPARQL queries for an object/item endpo…
Browse files Browse the repository at this point in the history
…int. Remove unused file based template queries - configuration was complicated with having to specify file paths - and not currently used by anyone. Only data repo template queries are now supported. (#319)
  • Loading branch information
recalcitrantsupplant authored Jan 9, 2025
1 parent f13190b commit a26c895
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README-Dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ PREFIX prez: <https://prez.dev/ont/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
INSERT DATA { GRAPH <https://prez/system> {
[ a prez:TemplateQuery ;
rdf:value """<template_query>
rdf:value """<template_queries>
""" ;
prez:forEndpoint "http://www.opengis.net/ogcapi-features-1/1.0/feature" ;
]
Expand Down
1 change: 0 additions & 1 deletion prez/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ class Settings(BaseSettings):
custom_endpoints: bool = False
configuration_mode: bool = False
temporal_predicate: Optional[URIRef] = SDO.temporal
endpoint_to_template_query_filename: Optional[Dict[str, str]] = {}
prez_ui_url: Optional[str] = None
search_method: SearchMethod = SearchMethod.DEFAULT
required_header: dict[str, str] | None = None
Expand Down
16 changes: 6 additions & 10 deletions prez/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,24 +626,20 @@ async def get_ogc_features_mediatype(
return default_mt


async def get_template_query(
async def get_template_queries(
endpoint_uri_type: tuple[URIRef, URIRef] = Depends(get_endpoint_uri_type),
):
) -> list[str] | None:
endpoint_uri = endpoint_uri_type[0]
filename = settings.endpoint_to_template_query_filename.get(str(endpoint_uri))

# check local files
if filename:
return (
Path(__file__).parent / "reference_data/template_queries" / filename
).read_text()

template_queries = []
# check prez_system_graph
for s in prez_system_graph.subjects(RDF.type, ONT.TemplateQuery):
endpoint_in_sys_graph = prez_system_graph.value(s, ONT.forEndpoint, None)
if str(endpoint_uri) == str(endpoint_in_sys_graph):
template_query = prez_system_graph.value(s, RDF.value, None)
return str(template_query)
template_queries.append(str(template_query))
if template_queries:
return template_queries
return None


Expand Down
6 changes: 3 additions & 3 deletions prez/routers/ogc_features_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
get_ogc_features_path_params,
get_profile_nodeshape,
get_system_repo,
get_template_query,
get_template_queries,
get_url,
)
from prez.exceptions.model_exceptions import (
Expand Down Expand Up @@ -190,7 +190,7 @@ async def listings_with_feature_collection(
openapi_extra=ogc_features_openapi_extras.get("feature"),
)
async def objects(
template_query: Optional[str] = Depends(get_template_query),
template_queries: Optional[str] = Depends(get_template_queries),
mediatype: str = Depends(get_ogc_features_mediatype),
url: str = Depends(get_url),
path_params: dict = Depends(get_ogc_features_path_params),
Expand All @@ -199,7 +199,7 @@ async def objects(
):
try:
content, headers = await ogc_features_object_function(
template_query,
template_queries,
mediatype,
url,
data_repo,
Expand Down
48 changes: 27 additions & 21 deletions prez/services/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@


async def object_function(
data_repo,
system_repo,
endpoint_structure,
pmts,
profile_nodeshape,
data_repo,
system_repo,
endpoint_structure,
pmts,
profile_nodeshape,
):
if pmts.selected["profile"] == ALTREXT["alt-profile"]:
none_keys = [
Expand Down Expand Up @@ -126,23 +126,27 @@ def create_parent_link(url):


async def ogc_features_object_function(
template_query,
selected_mediatype,
url,
data_repo,
system_repo,
path_params,
template_queries,
selected_mediatype,
url,
data_repo,
system_repo,
path_params,
):
collection_uri = path_params.get("collection_uri")
feature_uri = path_params.get("feature_uri")
if template_query:
queries = []
if template_queries:
if feature_uri:
focus_uri = feature_uri
else:
focus_uri = collection_uri
query = template_query.replace(
"VALUES ?focusNode { UNDEF }", f"VALUES ?focusNode {{ {focus_uri.n3()} }}"
)
for query in template_queries:
queries.append(
query.replace(
"VALUES ?focusNode { UNDEF }", f"VALUES ?focusNode {{ {focus_uri.n3()} }}"
)
)
else:
if feature_uri is None: # feature collection
collection_iri = IRI(value=collection_uri)
Expand All @@ -167,13 +171,15 @@ async def ogc_features_object_function(
construct_tss_list = [
TriplesSameSubject.from_spo(*triple) for triple in triples
]
query = PrezQueryConstructor(
construct_tss_list=construct_tss_list,
profile_triples=tssp_list,
).to_string()
queries.append(
PrezQueryConstructor(
construct_tss_list=construct_tss_list,
profile_triples=tssp_list,
).to_string()
)

query_start_time = time.time()
item_graph, _ = await data_repo.send_queries([query], [])
item_graph, _ = await data_repo.send_queries(queries, [])
if len(item_graph) == 0:
uri = feature_uri if feature_uri else collection_uri
raise URINotFoundException(uri=uri)
Expand All @@ -182,7 +188,7 @@ async def ogc_features_object_function(

link_headers = None
if selected_mediatype == "application/sparql-query":
content = io.BytesIO(query.encode("utf-8"))
content = io.BytesIO("\n".join(queries).encode("utf-8"))
elif selected_mediatype == "application/json":
collectionId = get_curie_id_for_uri(collection_uri)
collection = create_collection_json(
Expand Down

0 comments on commit a26c895

Please sign in to comment.