ogc-cql2 0.2.0

OGC CQL2 Text + JSON Encoding parser and interpreter in Rust
Documentation
# ogc-cql2

Rust implementation of the Open Geospatial Consortium (OGC) Common Query Language (CQL2) described [here](https://docs.ogc.org/is/21-065r2/21-065r2.html).

This library aims to fulfill **all** the requirements listed under [Conformance](https://docs.ogc.org/is/21-065r2/21-065r2.html#_conformance) section of the specs.

So far, users of this library will be able to:

* Parse CQL2 _Expressions_ in either Text- or JSON-encoded forms,
* Implement _Evaluators_ to process collections of _Resources_ (a.k.a features) against valid expressions.
* Make use of a comprehensive set of builtin _Functions_ to use in writing their expressions.
* Implement their own versions of _Functions_ and register them w/ _Evaluators_.

Changes are tracked in [ChangeLog](CHANGELOG.md).


## Parsing Expression Grammar (PEG) + Typify

The text-encoded parser used in this project was generated by [`rust-peg`](https://github.com/kevinmehall/rust-peg) by manually translating the source into input recognizable by that crate's `peg::parser!` macro. The reference BNF document is included in the [`doc`](doc/cql2.bnf) folder.

The JSON-encoded one started life from code generated by the [`cargo-typify`](https://crates.io/crates/cargo-typify) tool from the JSON Schema given in the Standard. However some limitations w/ that tool meant that manual intervention was required.

The modified JSON Schema input file is included w/ the source of this crate ([`cql2.json`](doc/cql2.json)) as well as a patch file ([`cql2.json.patch`](doc/cql2.json.patch)) showing the changes from the original copy.


## Change to the BNF Grammar

The BNF grammar specified in the specs limit the WKT representation of multi-point geometries to always enclose point coordinates w/in parenthesis as implied from the following rules...

```bnf
multipointTaggedText = "MULTIPOINT" ["Z"] multiPointText;
multiPointText = "(" pointText {"," pointText} ")";
pointText = "(" point ")";
point = xCoord yCoord [zCoord];
```

That meant that text like `MULTIPOINT(1 2, 3 4)` causes a syntax error forcing the user to write it instead as `MULTIPOINT((1 2), (3 4))`.

This implementation allows for both forms.


## Deviation from the Stadard

The CQL2 specs state that _Dates_ should be considered as local with regard to time zones. This implementation however always assign them the UTC TZ.


## Conformance tests

The `tests` folder contains tests that implement most of the `Annex A: Abstract Test Suite (Normative)` conformance tests, grouped in folders mirroring the level-1 sections of the specs.

### Test data

The folder `tests/samples/csv` contain 3 CSV files created/converted from the same named _Layers_ in the [GeoPackage][1] referenced in the Standard.

Those CSV files were first created by exporting each _Layer_ to a CSV file using [DB Browser for SQLite Version 3.13.1][2], then converting the geometries to their WKT form and renaming their column `geom`.

The other 2 folders next to `csv` in the same parent folder mirror the same data found [here][3]. 

### Tests not implemented yet

Some tests, which test filter expressions with AND, OR, and NOT including sub-expressions of 4 predicates are not implemented yet. Those are:

* A.6.6. Conformance Test 24: `/conf/accent-insensitive-comparison/logical`,
* A.7.3. Conformance Test 27: `/conf/basic-spatial-functions/logical`,
* A.9.10. Conformance Test 39: `/conf/spatial-functions/logical`,
* A.10.4. Conformance Test 43: `/conf/temporal-functions/logical`,
* A.11.2. Conformance Test 45: `/conf/array-functions/logical`,
* A.12.5. Conformance Test 50: `/conf/property-property/logical`,
* A.14.3. Conformance Test 54: `/conf/arithmetic/logical`,

### Test result pending request for clarification

The [issue here](https://github.com/opengeospatial/ogcapi-features/issues/1011) is at the time of this writing still unresolved.

For now, the relevant test (`a6/test_23.rs`) expected results have been amended according to the findings reported in the issue in question.

### How to configure this library

1. Make a copy of the file `.env.template` and rename it `.env`.
2. Make sure `.env` is included in `.gitignore`.
3. Edit the contents of `.env` to suit your requirements and environment.

For now these are the environment variables that can be configured:

#### `DEFAULT_CRS`

_Coordinate Reference System_ (CRS) code to use when validating geometry coordinates. Defaults to `EPSG:4326` if/when undefined.

#### `DEFAULT_PRECISION`
_Precision_ (number of digits after the decimal point) to keep/use when processing coordinates. Defaults to `6` if/when undefined. For _WGS 84_ coordinates this translates to approx. `11.1` cm. accuracy when projecting them to _Web Mercator_.

For now only positive integers in the range `0..7` inclusive are allowed.


#### `RUST_LOG`
See <https://docs.rs/env_logger/latest/env_logger/#enabling-logging> for details.


## TODO

In no particular order...

- [ ] Implement missing conformance tests preferably after finding an external set of Test Vectors.
- [ ] Add more _Functions_.
- [ ] Implement pooling of _Evaluators_ à la DB connections pools.
- [ ] Refine the _Evaluator_ trait as the external interface to this library.
- [ ] Investigate ways of translating _Expressions_ to PostGIS clauses + views.
- [ ] Improve the way we handle user defined closures.
- [ ] Reduce allocation.
- [ ] Improve performance.
- [ ] Reduce code repetition by using more macros.
- [ ] Investigate alternative means for external clients to inject functions logic + metadata.
- [x] ~~The WKT parsing machinery entry-point is private. Make it public.~~ Done 2025-08-31.
- [x] ~~Properly manage + handle global configurable options such as default CRS bearing in mind how it may affect conformance tests.~~ Done 2025-09-02.
- [ ] Add an LRU to store commonly used CRSes.


## License

This product is licensed under the Apache License Version 2.0 &mdash;see [included copy](LICENSE) or [online](https://www.apache.org/licenses/LICENSE-2.0)

[1]: https://github.com/opengeospatial/ogcapi-features/blob/master/cql2/standard/data/ne110m4cql2.gpkg
[2]: https://github.com/sqlitebrowser/sqlitebrowser
[3]: https://github.com/opengeospatial/ogcapi-features/tree/master/cql2/standard/schema/examples
[4]: https://docs.geoserver.org/2.27.x/en/user/filter/function_reference.html