.. _aql: AQL Generation & Configurable Queries ====================================== When openFHIR receives a /toAql request with the FHIR Query/path (e.g. ``Observation?category=laboratory``), it must translate that request into an openEHR AQL query. By default, openFHIR dynamically builds this AQL from the FHIR Connect mapping definitions. However, there are cases where this dynamic generation is insufficient or too generic — for example, when a complex IPS ``$summary`` operation requires a hand-crafted AQL that spans multiple archetypes, or when a specific query pattern needs a fine-tuned AQL for performance or correctness reasons. The ``_query`` property in context mapping files solves this problem by allowing administrators to pin specific FHIR request patterns to hand-crafted AQL templates that are returned directly, bypassing the dynamic AQL generation. The ``_query`` Property ------------------------ ``_query`` is an optional list defined inside the ``context`` block of a ``.context.yaml`` file. Each entry contains: - ``aql`` — the hardcoded AQL string to return when the rule matches - ``rules`` — a list of one or more matching patterns; if **any** rule matches the incoming request, the ``aql`` is returned immediately Example: .. code-block:: yaml context: template: id: International Patient Summary start: openEHR-EHR-COMPOSITION.health_summary.v1 _query: - aql: "SELECT c FROM EHR e[ehr_id/value='{{ehrid}}'] CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.health_summary.v1]" rules: - "$summary" - aql: "SELECT o FROM EHR e[ehr_id/value='{{ehrid}}'] CONTAINS COMPOSITION c CONTAINS OBSERVATION o[openEHR-EHR-OBSERVATION.body_weight.v2]" rules: - "Observation?category=body-weight" - aql: "SELECT o FROM EHR e[ehr_id/value='{{ehrid}}'] CONTAINS COMPOSITION c CONTAINS OBSERVATION o" rules: - "Observation" Rule Matching -------------- Rules are evaluated in order. The first entry whose ``rules`` list contains at least one match wins and its ``aql`` is returned. Rule strings follow one of three formats: **1. Operation rule** — starts with ``$`` Matches when the incoming FHIR URL contains the named operation. .. code-block:: yaml rules: - "$summary" # matches GET /Patient/123/$summary **2. Resource-only rule** — resource type name, no query parameters Matches any request for the given resource type, regardless of query parameters. .. code-block:: yaml rules: - "Observation" # matches GET /Observation, GET /Observation?patient=xyz, etc. **3. Resource with parameters rule** — ``ResourceType?param=value[¶m2=value2]`` Matches when the resource type matches **and** all specified key-value pairs are present in the request query string. Extra query parameters in the request are ignored; the rule only requires its own params to be present. .. code-block:: yaml rules: - "Observation?category=laboratory" # matches GET /Observation?category=laboratory - "Observation?code=abc&category=lab" # all listed params must be present AQL Template Variables ----------------------- The ``aql`` string supports the ``{{ehrid}}`` placeholder, which is replaced at runtime with the EHR ID of the patient being queried. Use this to scope the query to a specific patient. .. code-block:: yaml aql: "SELECT c FROM EHR e[ehr_id/value='{{ehrid}}'] CONTAINS COMPOSITION c[openEHR-EHR-COMPOSITION.health_summary.v1]" Why Use ``_query`` ------------------- - **Escape hatch for complex scenarios** — dynamic AQL generation works well for simple mappings, but operations like ``$summary`` or ``$everything`` typically need a single AQL that retrieves data across many archetypes at once. Hand-crafting this AQL and binding it via ``_query`` is far more practical. - **Performance** — a carefully written AQL with explicit archetype paths and ``CONTAINS`` chains can be significantly faster than the generically generated one. - **Correctness** — some openEHR templates have subtleties (slot usage, optional sections) that the generic AQL builder cannot account for. A hand-written AQL ensures the right data is retrieved. - **Predictability** — when you need deterministic behavior for a specific request pattern (e.g. a national use case with a fixed AQL), ``_query`` pins that behavior regardless of mapping file changes. Precedence ----------- ``_query`` entries are evaluated **before** dynamic AQL generation. If any rule matches, the hardcoded AQL is returned immediately and no dynamic mapping is performed. If no rule matches, openFHIR falls back to its standard AQL generation from the mapping definitions. This means ``_query`` is purely additive — it does not affect requests that do not match any rule.