knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
CQL2 is an OGC standard that enables complex filter expressions on OAFeat3 or STAC web services. CQL2 standard states that expressions can be represented in JSON or TEXT formats. Our implementation intends to convert native R expressions into CQL2 valid expressions without needing cumbersome nested lists or dictionaries. Also, we can make CQL2 filter requisition in JSON or TEXT formats with the same filter representation.
To explain the difference between the TEXT and JSON CQL2 representation, let's start with a simple example. In the following code, we have a valid CQL2 expression (in TEXT format) that refers to two properties, vehicle_height
and bridge_clearance
.
vehicle_height > (bridge_clearance - 1))
This filter expression can be passed in the HTTP GET verb implemented by the service to retrieve only those features that satisfy the condition. The same expression can be represented in JSON format, which is more suitable for HTTP POST requests:
{ "op": ">", "args": [ {"property":"vehicle_height"}, { "op": "-", "args": [ {"property":"bridge_clearance"}, 1 ] } ] }
Note how properties vehicle_height
and bridge_clearance
are represented in this format. They are elements of an object containing a property
member. Also, they go as arguments of operators (in this case,>
and -
operators).
In the R language, the JSON above could be represented by nested lists, which would be somewhat cumbersome to write. To produce valid CQL2 filter expressions, we use the R abstract syntax tree (AST) from R expressions that can be converted to TEXT or JSON formats. Let us see the same previous example written in R CQL2:
library(rstac)
cql2_text(vehicle_height > (bridge_clearance - 1)) # TEXT format
cql2_json(vehicle_height > (bridge_clearance - 1)) # JSON format
In both cases, the same CQL2 object representation is built from the expression using AST of R expression evaluation. Then, the object is converted into TEXT or JSON format.
CQL2 filters in TEXT format are sometimes represented the same way as in the R expression. However, this should only sometimes be the case, as we can see in some examples provided below.
A literal value is any part of a CQL2 filter expression used the same as specified in the expression.
The scalar data types are: character string
, number
, boolean
, timestamp
, and date
.
character string
cql2_text("Via dell'Avvento") cql2_json("Via dell'Avvento")
number
cql2_text(3.1415) cql2_json(-100)
boolean
cql2_text(TRUE) cql2_json(FALSE)
timestamp
cql2_text(timestamp("1969-07-20T20:17:40Z")) cql2_json(timestamp("1969-07-20T20:17:40Z"))
date
cql2_text(date("1969-07-20")) cql2_json(date("1969-07-20"))
The property of an item can be evaluated in the CQL2 filter expression by its name.
cql2_text(windSpeed > 1) cql2_json(windSpeed > 1)
A comparison predicate evaluates if two scalar expressions satisfy the specified comparison operator.
The standard comparison operators are: =
, !=
, <
, >
, <=
, >=
, and IS NULL
.
cql2_text(city == "Crato") cql2_json(city == "JacareĆ")
cql2_text(avg(windSpeed) < 4) cql2_json(avg(windSpeed) < 4)
cql2_text(balance - 150.0 > 0) cql2_json(balance - 150.0 > 0)
cql2_text(updated >= date('1970-01-01')) cql2_json(updated >= date('1970-01-01'))
IS NULL
operator
cql2_text(!is_null(geometry)) cql2_json(!is_null(geometry))
A comparison predicate evaluates if two scalar expressions satisfy the specified comparison operator.
Advanced comparison operators are: LIKE
, BETWEEN
, and IN
.
LIKE
operator
cql2_text(name %like% "Smith%") cql2_json(name %like% "Smith%")
BETWEEN
operator
cql2_text(between(depth, 100.0, 150.0)) cql2_json(between(depth, 100.0, 150.0))
IN
operator
cql2_text(cityName %in% list('Toronto', 'Frankfurt', 'Tokyo', 'New York')) cql2_json(cityName %in% list('Toronto', 'Frankfurt', 'Tokyo', 'New York'))
cql2_text(!category %in% list(1, 2, 3, 4)) cql2_json(!category %in% list(1, 2, 3, 4))
A spatial predicate evaluates if two spatial expressions satisfy the specified spatial operator.
The supported spatial operators are: S_INTERSECTS
, S_EQUALS
, S_DISJOINT
, S_TOUCHES
, S_WITHIN
, S_OVERLAPS
, S_CROSSES
, and S_CONTAINS
.
```{R spatial, message=FALSE} poly <- list( type = "Polygon", coordinates = list( rbind( c(0,0), c(0,1), c(0,1) ) )) cql2_text(s_intersects(geometry, {{poly}})) cql2_json(s_intersects(geometry, {{poly}}))
> Note: We provide an escape to evaluate user variables using `{{` or `!!`. Both symbols are largely used in the R Data Science community. ## Temporal operators{-} A temporal predicate evaluates if two temporal expressions satisfy the specified temporal operator. The supported temporal operators are: `T_AFTER`, `T_BEFORE`, `T_CONTAINS`, `T_DISJOINT`, `T_DURING`, `T_EQUALS`, `T_FINISHEDBY`, `T_FINISHES`, `T_INTERSECTS`, `T_MEETS`, `T_METBY`, `T_OVERLAPPEDBY`, `T_OVERLAPS`, `T_STARTEDBY`, and `T_STARTS`. ```r cql2_text(t_intersects(event_date, interval("1969-07-16T05:32:00Z", "1969-07-24T16:50:35Z"))) cql2_json(t_intersects(event_date, interval("1969-07-16T05:32:00Z", "1969-07-24T16:50:35Z")))
Functions allow implementations to extend the language.
Example of a function that returns a geometry value.
cql2_text(s_within(road, Buffer(geometry, 10, "m"))) cql2_json(s_within(road, Buffer(geometry, 10, "m")))
In conclusion, this tutorial has demonstrated using the rstac
package to build CQL2 expressions, making it easier for R users to write syntactically correct filter criteria for STAC services. This functionality can be an alternative for users to construct CQL2 expressions easily and efficiently. For more about CQL2 in rstac
, type the command ?ext_filter
.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.