Skip to content

Commit 86c81c6

Browse files
authored
normalize all feature/record CQL filtering to CQL2 using pygeofilter (#1889)
* use pygeofilter and CQL2 for all CQL handling (#1557) * docs
1 parent 5aa75d9 commit 86c81c6

14 files changed

Lines changed: 211 additions & 1404 deletions

File tree

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ jobs:
6565
- name: Install and run OpenSearch 📦
6666
uses: esmarkowski/opensearch-github-action@v1.0.0
6767
with:
68-
version: 2.12.0
68+
version: 2.18.0
6969
security-disabled: true
7070
port: 9209
7171
- name: Install and run MongoDB

docs/source/cql.rst

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
CQL support
44
===========
55

6+
OGC Common Query Language (`CQL2`_) is a generic language designed to provide enhanced query and subset/filtering to (primarily) feature and record data.
7+
68
Providers
79
---------
810

9-
As of now the available providers supported for CQL filtering are limited to :ref:`Elasticsearch <Elasticsearch>` and :ref:`PostgreSQL <PostgreSQL>`.
10-
11+
CQL2 support is implemented in various pygeoapi feature and record providers. See the :ref:`feature <ogcapi-features>` and :ref:`metadata <ogcapi-records>` provider sections
12+
for current provider support.
13+
1114
Limitations
1215
-----------
1316

14-
Support of CQL is limited to `Simple CQL filter <https://portal.ogc.org/files/96288#cql-core>`_ and thus it allows to query with the
17+
Support of CQL is limited to `Basic CQL2 <https://docs.ogc.org/is/21-065r2/21-065r2.html#cql2-core>`_ and thus it allows to query with the
1518
following predicates:
1619

1720
* comparison predicates
@@ -21,20 +24,20 @@ following predicates:
2124
Formats
2225
-------
2326

24-
At the moment Elasticsearch supports only the CQL dialect with the JSON encoding `CQL-JSON <https://portal.ogc.org/files/96288#simple-cql-JSON>`_.
27+
Supported providers leverage the CQL2 dialect with the JSON encoding `CQL-JSON <https://docs.ogc.org/is/21-065r2/21-065r2.html#cql2-json>`_.
2528

26-
PostgreSQL supports both CQL-JSON and CQL-text dialects, `CQL-JSON <https://portal.ogc.org/files/96288#simple-cql-JSON>`_ and `CQL-TEXT <https://portal.ogc.org/files/96288#simple-cql-text>`_
29+
PostgreSQL supports both `CQL2 JSON <https://docs.ogc.org/is/21-065r2/21-065r2.html#cql2-json>`_ and `CQL text <https://docs.ogc.org/is/21-065r2/21-065r2.html#cql2-text>`_ dialects.
2730

2831
Queries
2932
^^^^^^^
3033

3134
The PostgreSQL provider uses `pygeofilter <https://github.com/geopython/pygeofilter>`_ allowing a range of filter expressions, see examples for:
3235

33-
* `Comparison predicates <https://portal.ogc.org/files/96288#simple-cql_comparison-predicates>`_
34-
* `Spatial predicates <https://portal.ogc.org/files/96288#enhanced-spatial-operators>`_
35-
* `Temporal predicates <https://portal.ogc.org/files/96288#simple-cql_temporal>`_
36+
* `Comparison predicates (`Advanced <https://docs.ogc.org/is/21-065r2/21-065r2.html#advanced-comparison-operators>`_, `Case-insensitive <https://docs.ogc.org/is/21-065r2/21-065r2.html#case-insensitive-comparison>`_)
37+
* `Spatial predicates <https://docs.ogc.org/is/21-065r2/21-065r2.html#spatial-functions>`_
38+
* `Temporal predicates <https://docs.ogc.org/is/21-065r2/21-065r2.html#temporal-functions>`_
3639

37-
Using Elasticsearch the following type of queries are supported right now:
40+
Using Elasticsearch the following type of queries are supported currently:
3841

3942
* ``between`` predicate query
4043
* Logical ``and`` query with ``between`` and ``eq`` expression
@@ -59,11 +62,11 @@ A ``BETWEEN`` example for a specific property through an HTTP POST request:
5962
curl --location --request POST 'http://localhost:5000/collections/nhsl_hazard_threat_all_indicators_s_bc/items?f=json&limit=50&filter-lang=cql-json' \
6063
--header 'Content-Type: application/query-cql-json' \
6164
--data-raw '{
62-
"between": {
63-
"value": { "property": "properties.MHn_Intensity" },
64-
"lower": 0.59,
65-
"upper": 0.60
66-
}
65+
"op": "between",
66+
"args": [
67+
{"property": "properties.MHn_Intensity"},
68+
[0.59, 0.60]
69+
]
6770
}'
6871
6972
Or
@@ -73,11 +76,11 @@ Or
7376
curl --location --request POST 'http://localhost:5000/collections/recentearthquakes/items?f=json&limit=10&filter-lang=cql-json'
7477
--header 'Content-Type: application/query-cql-json'
7578
--data-raw '{
76-
"between":{
77-
"value":{"property": "ml"},
78-
"lower":4,
79-
"upper":4.5
80-
}
79+
"op": "between",
80+
"args": [
81+
{"property": "ml"},
82+
[4, 4.5]
83+
]
8184
}'
8285
8386
The same ``BETWEEN`` query using HTTP GET request formatted as CQL text and URL encoded as below:
@@ -93,7 +96,11 @@ An ``EQUALS`` example for a specific property:
9396
curl --location --request POST 'http://localhost:5000/collections/recentearthquakes/items?f=json&limit=10&filter-lang=cql-json'
9497
--header 'Content-Type: application/query-cql-json'
9598
--data-raw '{
96-
"eq":[{"property": "user_entered"},"APBE"]
99+
"op": "=",
100+
"args": [
101+
{"property": "user_entered"},
102+
"APBE"
103+
]
97104
}'
98105
99106
A ``CROSSES`` example via an HTTP GET request. The CQL text is passed via the ``filter`` parameter.
@@ -115,7 +122,6 @@ The same example, but this time providing a geometry in EWKT format:
115122
116123
curl "http://localhost:5000/collections/beni/items?filter=DWITHIN(geometry,SRID=3857;POINT(1392921%205145517),100,meters)"
117124
118-
119-
120-
121125
Note that the CQL text has been URL encoded. This is required in curl commands but when entering in a browser, plain text can be used e.g. ``CROSSES(foo_geom, LINESTRING(28 -2, 30 -4))``.
126+
127+
.. _`CQL2`: https://docs.ogc.org/is/21-065r2/21-065r2.html

docs/source/development.rst

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,44 +22,6 @@ Tests can be run locally as part of development workflow. They are also run on
2222
To run all tests, simply run ``pytest`` in the repository. To run a specific test file,
2323
run ``pytest tests/api/test_itemtypes.py``, for example.
2424

25-
26-
CQL extension lifecycle
27-
-----------------------
28-
29-
Limitations
30-
^^^^^^^^^^^
31-
32-
This workflow is valid only for the `CQL-JSON` format.
33-
34-
Schema
35-
^^^^^^
36-
37-
The Common Query Language (CQL) is the part 3 of the standard OGC API - Features. This extension has its specification available at
38-
`OGC API - Features - Part 3: Filtering and the Common Query Language (CQL) <https://portal.ogc.org/files/96288>`_ and the schema exists in development at
39-
`cql.json <https://portal.ogc.org/files/96288#cql-json-schema>`_.
40-
41-
Model generation
42-
^^^^^^^^^^^^^^^^
43-
44-
pygeoapi uses a class-based Python model interface to translate the schema into Python objects defined by `pydantic <https://docs.pydantic.dev/>`_ models.
45-
The model is generated with the pre-processing of the schema through the utility ``datamodel-codegen``, which is part
46-
of the `datamodel-code-generator <https://koxudaxi.github.io/datamodel-code-generator/>`_ package:
47-
48-
49-
.. code-block:: bash
50-
51-
# Generate from local downloaded json schema file
52-
datamodel-codegen --input ~/Download/cql-schema.json --input-file-type jsonschema --output ./pygeoapi/models/cql_update.py --class-name CQLModel
53-
54-
Note that datamodel-code-generator must be explicitly installed, as it is not a pygeoapi runtime dependency
55-
56-
How to merge
57-
^^^^^^^^^^^^
58-
59-
Once the new pydantic models have been generated then the content of the Python file ``cql_update.py`` can be used to replace the old classes within the ``cql.py`` file.
60-
Update everything above the function ``get_next_node`` and then verify if the tests for the CQL are still passing, for example ``test_post_cql_json_between_query``
61-
in ``tests/test_elasticsearch__provider.py``.
62-
6325
Working with Spatialite on OSX
6426
------------------------------
6527

0 commit comments

Comments
 (0)