Skip to content

Add CQL2 to Elasticsearch DSL conversion#184

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/add-cql2-to-elastic-dsl-conversion
Draft

Add CQL2 to Elasticsearch DSL conversion#184
Copilot wants to merge 3 commits intomainfrom
copilot/add-cql2-to-elastic-dsl-conversion

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 8, 2026

Summary

Adds the ability to convert a CQL2 search expression into Elasticsearch Query DSL JSON, addressing the feature request to "add the ability to convert a CQL2 search into Elasticsearch DSL".

Changes

New: ToElasticsearch trait (src/elasticsearch.rs)

A new ToElasticsearch trait with a to_elasticsearch() -> Result<serde_json::Value, Error> method, implemented for Expr. It covers:

Category Operators
Boolean AND, OR, NOT
Comparison =, <>, >, >=, <, <=
Null check IS NULL
Pattern match LIKE (converts %*, _?; supports casei wrapper via case_insensitive: true)
Membership INterms query
Range BETWEENrange query
Spatial S_INTERSECTS, S_WITHIN, S_CONTAINS, S_DISJOINT, S_EQUALS (bidirectional within+contains), S_TOUCHES/S_OVERLAPS/S_CROSSES (approximated as intersects)
Temporal T_BEFORE, T_AFTER, T_MEETS, T_METBY, T_DURING, T_CONTAINS, T_STARTS, T_STARTEDBY, T_FINISHES, T_FINISHEDBY, T_OVERLAPS, T_OVERLAPPEDBY, T_EQUALS, T_DISJOINT, T_INTERSECTS, ANYINTERACTS

The property field may be on either side of binary predicates. Both Expr::BBox and the Expr::Operation { op: "bbox" } (from CQL2 text) forms are supported for spatial queries, converted to Elasticsearch envelope shapes.

Updated: src/lib.rs

  • Exports ToElasticsearch from the crate root.

Updated: cli/src/lib.rs

  • Adds --output-format elasticsearch and --output-format elasticsearch-pretty CLI options.

Examples

echo "eo:cloud_cover < 0.5" | cql2 -o elasticsearch
# {"range":{"eo:cloud_cover":{"lt":0.5}}}

echo "platform = 'landsat-8' AND s_intersects(footprint, {...})" | cql2 -o elasticsearch-pretty
# {
#   "bool": {
#     "must": [
#       {"term": {"platform": "landsat-8"}},
#       {"geo_shape": {"footprint": {"shape": {...}, "relation": "intersects"}}}
#     ]
#   }
# }
use cql2::{Expr, ToElasticsearch};

let expr: Expr = "landsat:scene_id = 'LC82030282019133LGN00'".parse().unwrap();
let dsl = expr.to_elasticsearch().unwrap();
// {"term": {"landsat:scene_id": "LC82030282019133LGN00"}}

Testing

  • 45 unit tests in src/elasticsearch.rs covering all supported operators.
  • Integration test in tests/elasticsearch_tests.rs following the project's fixture-based pattern (same structure as reduce_tests.rs), with 18 fixture pairs in tests/elasticsearch_expected.txt covering comparisons, boolean operators, LIKE, IN, BETWEEN, IS NULL, and temporal operators.
  • All existing 458 tests continue to pass.

Copilot AI and others added 2 commits April 8, 2026 15:14
Copy link
Copy Markdown
Contributor

@bitner bitner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure there are tests

Copy link
Copy Markdown
Author

Copilot AI commented Apr 8, 2026

Make sure there are tests

There are 45 unit tests in src/elasticsearch.rs (covering all operators: boolean, comparison, LIKE, IN, BETWEEN, IS NULL, spatial, and temporal) plus a new integration test added in 85ef597:

  • tests/elasticsearch_tests.rs — fixture-based integration test following the same pattern as reduce_tests.rs
  • tests/elasticsearch_expected.txt — 18 fixture pairs (CQL2 input → expected Elasticsearch DSL) covering the most common query types

Copilot AI requested a review from bitner April 8, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants