Filtering¶
pyramid_georest implements a really powerful filter system to provide even deep nested filter combination possibilities.
Some of these abilities should be shown here to show you how this works and how you can take the best effort out of it into your own application using this API.
Prerequisites¶
For all example given below we assume your API is configured to be available under the following url path:
<application host>/api/test_schema/test_table
This means you initialized your API with the name api without any route prefix on including. Your database table test_table is situated in the database schema test_schema.
Sorting and paging¶
The API offers a way to implement paging in your application using this API. This is possible by passing the offset and limit both as url parameters whether to the read all or the read with filter url endpoint:
<application host>/api/test_schema/test_table/read.json?offset=0&limit=10
Unsurprisingly this will deliver the first 10 matches of the bound resource.
If you want to used something like paging in your application you can “swipe” through the collection of your database records with manipulating the described parameters. Let’s assume you have a table in your application which should show only 10 records at a time for performance reason and offers a selector to switch between this 10-record-windows via paging. You only need to set parameter like this:
<application host>/api/test_schema/test_table/read.json?offset=0&limit=10 # page 1
<application host>/api/test_schema/test_table/read.json?offset=10&limit=20 # page 2
<application host>/api/test_schema/test_table/read.json?offset=20&limit=30 # page 3
...
Note
It is mandatory to provide both. The offset and the limit parameter. Anything else will throw an error.
In addition to the option of windowing/paging you have the ability to sort your data by one column in a selectable direction. This can be done by passing order_by and direction both as url parameters like this:
<application host>/api/test_schema/test_table/read.json?order_by=test_column&direction=asc # ascending
<application host>/api/test_schema/test_table/read.json?order_by=test_column&direction=desc # descending
Note
It is possible to pass these six types of direction directives:
- ASC
- asc
- ascending
- DESC
- desc
- descending
everything else will throw an error.
Note
Of course sorting and paging is can be combined.
This mechanism is applied to the normal read entry point and also to the filtered read entry point (see Used URL patterns for details).
General filter structure¶
Note
Filtering mechanism is done through the HTTP POST method. So API expects the filter parameters to be passed as JSON in the body of the request. The most important reason for this is to prevent limitations of URL length which will surely be scratched on complex filters with geometry content.
The filter system tries to keep the logic of SQL in some way and transport it to a web usable language. This is JSON. As you can see below the general filter system is a JSON structure which defines a filter by setting the mode to be used for combining the elements stored in the array of clauses. The mode is whether AND or OR.
{
'filter': {
'definition': {
'mode': 'AND',
'clauses': []
}
}
}
The clause array can contain a filter definition itself. That’s how you can implement fairly complex filters.
A clause is a JSON-Object constructed 3 attributes:
column_name is the desired column name of your database model.
operator is the logical operator which is a bit varying on the type of the column you try to filter. On generic types like string or number types it provides the following options (please scroll also right table is a little big):
operator meaning value notes == equals string or number types = equals string or number types <> not equals string or number types != not equals string or number types < less than string or number types be aware in case of string types the behaviour completely depends on the underling database and encoding <= less than or equals string or number types > greater than string or number types >= greater than or equals string or number types LIKE SQL LIKE string with possible wildcards % and _ for instance ‘Ab%’ or ‘a__%’ this will cast database value to string for comparison IN SQL IN comma separated string like ‘Bud,Terence’ or ‘1,2,3’ NULL SQL IS NULL null or anything it won’t be interpreted NOT NULL SQL IS NOT NULL null or anything it won’t be interpreted Geometric operators INTERSECTS eg. ST_Intersects in PostGIS any WKT compatible geometry Only PostGIS is supported in the moment!
I would be glad to support other DB’s too. Please contact me or file an issue.
TOUCHES eg. ST_Touches in PostGIS COVERED_BY eg. ST_CoveredBy in PostGIS WITHIN eg. ST_DFullyWithin in PostGIS value is the value which should be used to compare against database
Note
A word about the geometric filtering. In the moment this API should support every WKT compatible geometry type. Even geometry collections => they are extracted arbitrary deep and the filter is assigned to every single element of collection. If you encounter any problem don’t hesitate to file an issue.
Simple filters¶
Construction of filter is easy. Below you can see a simple match filter which should return all matches for id equals 1 assuming id is a number field.
{
'filter': {
'definition': {
'mode': 'AND',
'clauses': [{
'column_name': 'id',
'operator': '==',
'value': 1
}]
}
}
}
Note
Above the mode AND is used. Obviously this has no effect since we only define one clause. So in this case it doesn’t matter if we pass AND or OR. But mode is mandatory always. So omitting it will throw an error.
{
'filter': {
'definition': {
'mode': 'OR',
'clauses': [{
'column_name': 'id',
'operator': '==',
'value': 1
}]
}
}
}
Regarding to the note above this filter should produce the same result as the AND version.
Geometric filters¶
Creating a geometric filter is easy as the filters for string or number types. Keep in mind the geometric operators which are available in the moment. For details see table above.
The value has to be a string of valid WKT. Without any spatial reference system. This means the API is not transforming any input. Your input of geometry WKT has to be in the same projection like your database geometries are.
{
'filter': {
'definition': {
'mode': 'AND',
'clauses': [{
'column_name': 'geom',
'operator': 'INTERSECTS',
'value': 'POINT(2615051.0 1264822.5)'
}]
}
}
}
Of cause you can combine string/number filters with geometric filters in any way. In the example below both clauses are logically connected the AND.
{
'filter': {
'definition': {
'mode': 'AND',
'clauses': [{
'column_name': 'geom',
'operator': 'INTERSECTS',
'value': 'POINT(2615051.0 1264822.5)'
},{
'column_name': 'type',
'operator': '==',
'value': 'building'
}]
}
}
}
Complex nested filters¶
Sooner or later you will come to the point where simple one mode filters aren’t enough. Then you can start to nest filters to get even more tuned selection.
{
"filter": {
"definition": {
"mode": "AND",
"clauses": [
{
"mode": "OR",
"clauses": [
{
"column_name": "geom",
"operator": "INTERSECTS",
"value": "POINT(2615051.0 1264822.5)"
},
{
"column_name": "geom",
"operator": "INTERSECTS",
"value": "POINT(2618963.0 1263219.0)"
}
]
},
{
"column_name": "id",
"operator": ">",
"value": 2800
}
]
}
}
}
It is only necessary to put a object inside clauses which defines a mode again which is then assigned to the sub clauses. So here a simple AND connection is done between the clause id is greater than 2800 and the sub clauses. The sub clauses are connected as OR.