ogc-cql2 0.3.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.

This library aims to fulfill all the requirements listed under 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.
  • Evaluate CQL2 Expressions against records provided by Data Sources through two traits: Iterable and Streamable. So far implementations for CSV and GeoPackage data-sources are also included.

Changes are tracked in ChangeLog.

Parsing Expression Grammar (PEG) + Typify

The text-encoded parser used in this project was generated by 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 folder.

The JSON-encoded one started life from code generated by the 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) as well as a patch file (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...

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/data contain 3 CSV files created/converted from the same named Layers in the GeoPackage referenced in the Standard, as well as the GeoPackage DB/file itself.

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

The GeoPackage DB/file is used for testing the GeoPackage Data Source and the Streamable Data Source trait with and without translating the filter expression to SQL.

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

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 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 7 if/when undefined. For WGS 84 coordinates this translates to approx. 1.11 cm. accuracy when projecting them to Web Mercator.

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

RUST_LOG

See https://docs.rs/env_logger/latest/env_logger/#enabling-logging for details.

Required external software

GEOS

This library relies on GEOS by virtue of its dependence on the geos crate. In my case the native installed version shows the following at the time this page was last updated...

Name            : geos
Epoch           : 0
Version         : 3.14.1
Release         : 1.fc43
Architecture    : x86_64
Installed size  : 4.1 MiB
Source          : geos-3.14.1-1.fc43.src.rpm
From repository : updates
Summary         : GEOS is a C++ port of the Java Topology Suite
URL             : http://trac.osgeo.org/geos/
License         : LGPL-2.1-only
Description     : GEOS (Geometry Engine - Open Source) is a C++ port of the Java Topology
                : Suite (JTS). As such, it aims to contain the complete functionality of
                : JTS in C++. This includes all the OpenGIS "Simple Features for SQL" spatial
                : predicate functions and spatial operators, as well as specific JTS topology
                : functions such as IsValid()
Vendor          : Fedora Project

SQLite + Spatialite extension

This library now supports GeoPackage database files. This requires an installed version of sqlite and libspatial binaries. The latter will provide the mod_spatialite.so extension usually to be found under /usr/lib64/. Here is the info about my test installation at the time of this page's last update...

Name            : sqlite
Epoch           : 0
Version         : 3.50.2
Release         : 2.fc43
Architecture    : x86_64
Installed size  : 1.8 MiB
Source          : sqlite-3.50.2-2.fc43.src.rpm
From repository : fedora
Summary         : Library that implements an embeddable SQL database engine
URL             : http://www.sqlite.org/
License         : blessing
Description     : SQLite is a C library that implements an SQL database engine. A large
                : subset of SQL92 is supported. A complete database is stored in a
                : single disk file. The API is designed for convenience and ease of use.
                : ...
Vendor          : Fedora Project
...
Name            : libspatialite
Epoch           : 0
Version         : 5.1.0
Release         : 11.fc43
Architecture    : x86_64
Installed size  : 15.3 MiB
Source          : libspatialite-5.1.0-11.fc43.src.rpm
From repository : fedora
Summary         : Enables SQLite to support spatial data
URL             : https://www.gaia-gis.it/fossil/libspatialite
License         : MPL-1.1 OR GPL-2.0-or-later OR LGPL-2.0-or-later
Description     : SpatiaLite is a a library extending the basic SQLite core in order to
                : get a full fledged Spatial DBMS, really simple and lightweight, but
                : mostly OGC-SFS compliant.
Vendor          : Fedora Project

TODO

In no particular order...

  • Implement more Data Sources such as Shapefiles and PostGIS tables.
  • Add an option to the repl command line tool to output valid expressions as SQL WHERE clauses.
  • Investigate implementing basic spatial operators for 2D geometries in pure Rust; i.e. removing ependenceon the geos crate.
  • 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.
  • The WKT parsing machinery entry-point is private. Make it public. Done 2025-08-31.
  • 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. Turns out Proj is not Send and hence cannot be cached in an LRU cache safely w/o introducing unsafe code.

License

This product is licensed under the Apache License Version 2.0 —see included copy or online