Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CQL spatial capability #102

Merged
merged 14 commits into from
Mar 1, 2022
23 changes: 13 additions & 10 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## References

1. [OGC API for Features version 1.0](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html)
1. [OpenAPI Specifcation version 3.0.2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md)
* [OGC API for Features version 1.0](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html)
* [OGC API - Features - Part 3: Filtering and the Common Query Language (CQL)](https://portal.ogc.org/files/96288)
* [OpenAPI Specifcation version 3.0.2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md)

## Notes

Expand Down Expand Up @@ -69,25 +70,27 @@ Produces a dataset of items from the collection (as GeoJSON)
Path: `/collections/{cid}/items`

### Parameters
* `crs=SRID` - specifies the CRS for the output feature geometry
* `limit=N` - limits the number of features in the response.
* `offset=N` - starts the response at an offset.
* `sortby=[+|-]PROP` - sort the response items by a property (ascending (default) or descending).
* `bbox=mix,miny,maxx,maxy` - filter features in response to ones intersecting a bounding box (in lon/lat or specified CRS).
* `bbox-crs=SRID` - specify CRS for the `bbox` coordinates
* `<propname>=val` - filter features for a property having a value.
Multiple property filters are ANDed together.
* `filter=cql-expr` - filters features via a CQL expression
* `filter-crs=SRID` - specifies the CRS for geometry values in the CQL filter
* `transform=fun1[,args][|fun2,args...]` - transform the feature geometry by a geometry function pipeline.
* `groupby=PROP-NAME` - group results on a property.
Usually used with an aggregate `transform` function.
* `properties=PROP-LIST`- return only specific properties (comma-separated).
If PROP-LIST is empty, no properties are returned.
If not present, all properties are returned.
* `crs=SRID` - specifies the CRS for the output feature geometry
* `precision=N` - set precision of GeoJSON ordinates to use N decimal places
* `transform=fun1[,args][|fun2,args...]` - transform the feature geometry by a geometry function pipeline.
* `groupby=PROP-NAME` - group results on a property.
Usually used with an aggregate `transform` function.
* `sortby=[+|-]PROP` - sort the response items by a property (ascending (default) or descending).
* `limit=N` - limits the number of features in the response.
* `offset=N` - starts the response at an offset.

### Response

GeoJSON document containg the features produced by the request.
GeoJSON document containing the features resulting from the request query.

#### Links
* self - `/collections/{cid}/items.json` - This document as JSON
Expand Down
15 changes: 10 additions & 5 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ It includes [*OGC API - Features*](http://docs.opengeospatial.org/is/17-069r3/17
- `sortby=name`, `sortby=+name`, `sortby=-name`
- [x] filtering by property value ( `name=value`, as per [spec sec. 7.15.5](http://docs.opengeospatial.org/is/17-069r3/17-069r3.html#_parameters_for_filtering_on_feature_properties) )
- [x] `filter` with CQL expressions (see below)
- [ ] `filter-lang`
- [ ] `filter-crs`
- [ ] `filter-lang` (only CQL-Text is supported)
- [ ] `filter-crs=srid`

### Query parameters - Extension
- [x] `precision` to set output precision of GeoJSON coordinates
Expand All @@ -64,16 +64,21 @@ It includes [*OGC API - Features*](http://docs.opengeospatial.org/is/17-069r3/17
- [x] property names
- [x] character literals
- [x] numeric literals
- [ ] spatial literals
- [x] geometry literals
- `POINT`,`LINESTRING`,`POLYGON`,`MULTIPOINT`,`MULTILINESTRING`,`MULTIPOLYGON`,`GEOMETRYCOLLECTION`,`ENVELOPE`
- [ ] temporal literals
- [x] binary comparisons (`<`,`<=`,`>`,`>=`,`=`,`<>`)
- [x] binary comparisons
- `<`,`<=`,`>`,`>=`,`=`,`<>`
- [x] `property [NOT] BETWEEN a AND B`
- [x] `property [NOT] IN ( value-list )`
- [x] `property [NOT] (LIKE | ILIKE) pattern`
- `pattern` can include `%` wildcards
- [x] `property [NOT] IS NULL`
- [x] boolean combinations (`AND`,`OR`,`NOT`)
- [ ] spatial predicates
- [x] spatial predicates
- `INTERSECTS`,`DISJOINT`,`CONTAINS`,`WITHIN`,`EQUALS`,`CROSSES`,`OVERLAPS`,`TOUCHES`
- [x] distance predicate
- `DWITHIN`
- [ ] temporal predicates
- [ ] functions

Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Add configuration to set base path (#88)
* Add standard query parameters `crs` and `bbox-crs` (#98)
* Allow configuring published function schemas (#99)
* Add support for CQL filtering with `filter` and `filter-crs` query parameters (#101, #102)

### Performance Improvements

Expand Down
3 changes: 2 additions & 1 deletion hugo/content/examples/ex_query_functions_countries_name.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ weight: 210

This is the same spatial function example shown in the [Usage](/usage/functions/) section. Here we'll show a sample GeoJSON response and the web UI preview.

Note: this functionality can now be obtained more easily by using the `filter` query parameter with a `LIKE` CQl expression.
Note:
Another way to obtain this functionality is to use the `filter` query parameter with a `LIKE` CQl expression. See the [CQL section](/usage/cql/)

## Create a spatial function that returns a filtered set of countries

Expand Down
2 changes: 1 addition & 1 deletion hugo/content/usage/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Visible spatial tables and views are those which:
* declare a **geometry type**;
* declare an **SRID** (spatial reference ID);
* and the service database connection has `SELECT` privileges for
(see the and [Security](/usage/security/) section for more detail).
(see the [Security](/usage/security/) section for more detail).

If the table or view has a **primary key column** it will
be used as the id for features in the collection.
Expand Down
112 changes: 96 additions & 16 deletions hugo/content/usage/cql.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
---
title: "Filtering with CQL"
title: "CQL Filters"
date:
draft: false
weight: 175
---

The features returned by `items` queries can be filtered using
the `filter` query parameter with an expression written using
the Common Query Language (CQL).
the [Common Query Language](https://portal.ogc.org/files/96288) (CQL).
CQL expressions return a value of `true` or `false`.
Only features which evaluate to `true` are returned.
In `pg_featureserv` the filter expression is evaluated by the database,
so it can take advantage of indexes to make filter evaluation very efficient.

This section describes the CQL query language subset supported by `pg_featureserv`.

{{% note %}}
The filter expression is evaluated by the database,
which will take advantage of indexes (attribute and spatial)
to make filter evaluation very efficient.
{{% /note %}}

## Property and Literal Values

The basic elements of filter expressions are values obtained
from feature collection properties and literals.
Properties are referred to by name, and literals can be
numbers, boolean or text values.
from feature collection properties, and literals.

Properties are referred to by name.
Property names can be quoted, to support including special characters.

#### Example
```
propname
"quoted_name$"
```

Literals can be numbers, boolean or text values.

```
1.234
true
'a text value'
Expand All @@ -37,20 +47,20 @@ Values can be compared using conditional operators:
a = b a <> b a > b a >= b a < b a <= b
```

### Example
#### Examples
```
pop_est >= 1000000
name = 'Finland'
```

## BETWEEN predicate

The `BETWEEN` predicate tests if a value lies in a range defined by start and end values (inclusive):
The `BETWEEN` predicate tests if a value lies in a range defined by a start and end value (inclusive):
```
property [NOT] BETWEEN a AND b
```

### Example
#### Examples
```
pop_est BETWEEN 100000 AND 1000000
name NOT BETWEEN 'Chile' AND 'Denmark'
Expand All @@ -62,7 +72,7 @@ The `IN` predicate tests if a value lies in a list of constant values.
property [NOT] IN ( val1, val2, ... )
```

### Example
#### Examples
```
id IN (1,2,3)
name IN ('Chile', 'Kenya', 'Denmark')
Expand All @@ -78,7 +88,7 @@ The character `%` is a wildcard.
property [NOT] LIKE | ILIKE pattern
```

### Example
#### Examples
```
name LIKE 'Ch%'
continent ILIKE '%america'
Expand All @@ -90,7 +100,7 @@ The `IS NULL` predicate tests if a property value is (or is not) null.
property IS [NOT] NULL
```

### Example
#### Example
```
name IS NULL
```
Expand All @@ -102,7 +112,77 @@ Operators are evaluated in the order NOT, AND, OR.
Evaluation order can be controlled by enclosing
subexpressions in parentheses.

### Example
#### Example
```
(continent = 'Europe' OR continent = 'Africa') AND pop_est < 1000000
```

# Spatial filters

CQL supports spatial filtering by providing **geometry literals**
and **spatial predicates**.

## Geometry Literals

Geometry literals use [Well-Known Text](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry)
(WKT) to describe
values for points, lines, polygons (with holes), and collections.

#### Examples
```
POINT (1 2)
LINESTRING (0 0, 1 1)
POLYGON ((0 0, 0 9, 9 0, 0 0))
POLYGON ((0 0, 0 9, 9 0, 0 0),(1 1, 1 8, 8 1, 1 1))
MULTIPOINT ((0 0), (0 9))
MULTILINESTRING ((0 0, 1 1),(1 1, 2 2))
MULTIPOLYGON (((1 4, 4 1, 1 1, 1 4)), ((1 9, 4 9, 1 6, 1 9)))
GEOMETRYCOLLECTION(POLYGON ((1 4, 4 1, 1 1, 1 4)), LINESTRING (3 3, 5 5), POINT (1 5))
```

CQL also provides a syntax for concisely representing a rectangular polygon
by the X and Y ordinates at the lower-left and upper-right corners:
```
ENVELOPE (1, 2, 3, 4)
```

By default the coordinate system of geometry literal values is assumed to be geodetic (SRID = 4326).
The `filter-crs=SRID` query parameter can be used to specify that the geometry literals in a filter expression are in a different coordinate system.

## Spatial predicates

Spatial predicates allow filtering features via spatial conditions
on the feature geometry.
Spatial predicates are defined in the form of spatial functions.
Predicates for spatial relationships include:

* `INTERSECTS` - tests whether two geometries intersect
* `DISJOINT` - tests whether two geometries have no points in common
* `CONTAINS` - tests whether a geometry contains another
* `WITHIN` - tests whether a geometry is within another
* `EQUALS` - tests whether two geometries are topologically equal
* `CROSSES` - tests whether the geometries cross
* `OVERLAPS` - tests whether the geometries overlap
* `TOUCHES` - tests whether the geometries touch

For detailed definitions of the spatial predicates see the
[CQL standard](https://portal.ogc.org/files/96288#enhanced-spatial-operators)
and the [PostGIS function reference](https://postgis.net/docs/reference.html#Spatial_Relationships).

Typically a spatial predicate is used to test the relationship between the spatial column of the queried collection
and a geometry literal value.

#### Examples
```
INTERSECTS(geom, ENVELOPE(-100, 49, -90, 50) )

CONTAINS(geom, POINT(-100 49) )
```

The `DWITHIN` predicate allows testing whether a geometry lies within a given distance of another. The distance is in the units of the dataset's coordinate system
(degrees in the case of data stored in SRID=4326, or a length unit such as meters for non-geodetic data).

#### Example
```
(continent = 'Europe' OR continent = 'Afica') AND pop_est < 1000000
DWITHIN(geom, POINT(-100 49), 0.1)
```
30 changes: 22 additions & 8 deletions hugo/content/usage/query_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ http://localhost:9000/collections/ne.countries/items?bbox=10.4,43.3,26.4,47.7
http://localhost:9000/collections/ne.countries/items?bbox-crs=3005&bbox=1000000,400000,1001000,401000
```

### Filter by properties
### Filter by property values

The response feature set can be filtered to include
only features which have a given value for one or more properties.
Expand All @@ -72,10 +72,22 @@ See the [CQL section](/query_data/cql/) for more details.

#### Example
```
http://localhost:9000/collections/ne.countries/items?filter=continent='Europe' AND pop_est<2000000
http://localhost:9000/collections/ne.countries/items?filter=continent='Europe' AND pop_est < 2000000
```

### Specify response properties
### Filter geometry coordinate system

By default the coordinate system of geometry literals in the filter expressionis
is assumed to be 4326 (geodetic).
A different coordinate system
can be specified by using the query parameter `filter-crs=SRID`.

#### Example
```
http://localhost:9000/collections/ebc.voting_area/items.json?filter-crs=3005&filter=DWITHIN(geom,POINT(1209000+477000),1000)
```

### Response properties

The query parameter `properties=PROP1,PROP2,PROP3...`
specifies the feature properties returned in the response.
Expand All @@ -89,17 +101,19 @@ no feature properties are returned.
http://localhost:9000/collections/ne.countries/items?properties=name,abbrev,pop_est
```

### Specify response coordinate system
### Response coordinate system

The query parameter `crs=SRID`
specifies the coordinate system to be used for the
feature geometry in the response.
The SRID must be a coordinate system which is defined in the PostGIS instance.
By default data is returned in WGS84 (SRID=4326) geodetic coordinate system.

Note: GeoJSON technically does not support coordinate systems other than 4326,
{{% note %}}
GeoJSON technically does not support coordinate systems other than 4326,
but the OGC API standard allows non-geodetic data to be encoded in GeoJSON.
However, this data may not be compatible with other systems.
{{% /note %}}

#### Example
```
Expand Down Expand Up @@ -164,7 +178,7 @@ The response is a GeoJSON feature containing the result.
http://localhost:9000/collections/ne.countries/items/23
```

### Specify properties
### Specify response properties

The query parameter `properties=PROP1,PROP2,PROP3...`
specifies the feature properties which are returned
Expand All @@ -175,11 +189,11 @@ in the response.
http://localhost:9000/collections/ne.countries/items/23?properties=name,abbrev,pop_est
```

### Specify coordinate system
### Specify responses coordinate system

The query parameter `crs=SRID`
can be included to specify the coordinate system to be used for the
feature geometry.
feature geometry in the response.

#### Example
```
Expand Down
Loading