Skip to content

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 ErrorResponse | EntryResponseMany | EntryResponseOne

The OPTIMADE database response to be processed.

required
database_id str

The database's id under which the returned resources or errors will be delivered.

required
query QueryResource

A resource representing the performed query.

required
gateway GatewayResource

A resource representing the gateway that was queried.

required

Returns:

Type Description
list[EntryResource] | list[dict[str, Any]] | EntryResource | dict[str, Any] | None

The response's data.

Source code in optimade_gateway/queries/process.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
async def process_db_response(
    response: ErrorResponse | EntryResponseMany | EntryResponseOne,
    database_id: str,
    query: QueryResource,
    gateway: GatewayResource,
) -> list[EntryResource] | list[dict[str, Any]] | EntryResource | dict[str, Any] | None:
    """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.model_dump()
                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