process¶
Process performed OPTIMADE queries.
process_db_response(response, database_id, query, gateway)
async
¶
Process an OPTIMADE database response.
The passed query
will be updated with the top-level meta
information:
data_available
, data_returned
, and more_data_available
.
Since, only either data
or errors
should ever be present, one or the other will
be either an empty list or None
.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
response |
Union[ErrorResponse, EntryResponseMany, EntryResponseOne] |
The OPTIMADE database response to be processed. |
required |
database_id |
str |
The database's |
required |
query |
QueryResource |
A resource representing the performed query. |
required |
gateway |
GatewayResource |
A resource representing the gateway that was queried. |
required |
Returns:
Type | Description |
---|---|
Union[List[EntryResource], List[Dict[str, Any]], EntryResource, Dict[str, Any], None] |
The response's |
Source code in optimade_gateway/queries/process.py
async def process_db_response(
response: "Union[ErrorResponse, EntryResponseMany, EntryResponseOne]",
database_id: str,
query: "QueryResource",
gateway: "GatewayResource",
) -> "Union[List[EntryResource], List[Dict[str, Any]], EntryResource, Dict[str, Any], None]": # pylint: disable=line-too-long
"""Process an OPTIMADE database response.
The passed `query` will be updated with the top-level `meta` information:
`data_available`, `data_returned`, and `more_data_available`.
Since, only either `data` or `errors` should ever be present, one or the other will
be either an empty list or `None`.
Parameters:
response: The OPTIMADE database response to be processed.
database_id: The database's `id` under which the returned resources or errors
will be delivered.
query: A resource representing the performed query.
gateway: A resource representing the gateway that was queried.
Returns:
The response's `data`.
"""
results = []
errors = []
LOGGER.debug("Starting to process database_id: %s", database_id)
if isinstance(response, ErrorResponse):
for error in response.errors:
if isinstance(error.id, str) and error.id.startswith("OPTIMADE_GATEWAY"):
warn(error.detail, OptimadeGatewayWarning)
else:
# The model `ErrorResponse` does not allow the objects in the top-level
# `errors` list to be parsed as dictionaries - they must be a pydantic
# model.
meta_error = {}
if error.meta:
meta_error = error.meta.dict()
meta_error.update(
{
f"_{CONFIG.provider.prefix}_source_gateway": {
"id": gateway.id,
"type": gateway.type,
"links": {"self": gateway.links.self},
},
f"_{CONFIG.provider.prefix}_source_database": {
"id": database_id,
"type": "links",
"links": {
"self": (
str(gateway.links.self).split(
"gateways", maxsplit=1
)[0]
+ f"databases/{database_id}"
)
},
},
}
)
error.meta = Meta(**meta_error)
errors.append(error)
data_returned = 0
more_data_available = False
else:
results = response.data
if isinstance(results, list):
data_returned = response.meta.data_returned or len(results)
else:
data_returned = response.meta.data_returned or (0 if not results else 1)
more_data_available = response.meta.more_data_available or False
data_available = response.meta.data_available or 0
extra_updates = {
"$inc": {
"response.meta.data_available": data_available,
"response.meta.data_returned": data_returned,
}
}
if not get_resource_attribute(
query,
"attributes.response.meta.more_data_available",
False,
disambiguate=False, # Extremely minor speed-up
):
# Keep it True, if set to True once.
extra_updates.update(
{"$set": {"response.meta.more_data_available": more_data_available}}
)
# This ensures an empty list under `response.data.{database_id}` is returned if the
# case is simply that there are no results to return.
if errors:
extra_updates.update({"$addToSet": {"response.errors": {"$each": errors}}})
await update_query(
query,
f"response.data.{database_id}",
results,
operator=None,
**extra_updates,
)
return results