Skip to content

Commit 2d740a5

Browse files
authored
Add operators and fix discrepancies (#76)
1 parent 2677539 commit 2d740a5

File tree

5 files changed

+76
-15
lines changed

5 files changed

+76
-15
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ coverage.xml
7575
.noseids
7676
Procfile
7777

78-
# PyCharm
78+
# editor
7979
.idea
80+
.vscode/
8081

8182
# Config
8283
config.toml

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ Returns OpenAPI/Swagger documentation specific to this resource.
210210

211211
### Query Operators
212212

213-
The data endpoint can be queried with the following operators as query string (replacing `column_name` with the name of an actual column), if the column type allows it (see the swagger for each column's allowed parameter):
213+
The data endpoint can be queried with the following operators as query string (replacing `column_name` with the name of an actual column), if the column type allows it (see the swagger for each column's allowed parameters):
214214

215215
#### Filtering Operators
216216
```
@@ -220,12 +220,18 @@ column_name__exact=value
220220
# differs
221221
column_name__differs=value
222222
223-
# contains (for strings only)
223+
# contains
224224
column_name__contains=value
225225
226+
# notcontains (value does not contain)
227+
column_name__notcontains=value
228+
226229
# in (value in list)
227230
column_name__in=value1,value2,value3
228231
232+
# notin (value not in list)
233+
column_name__notin=value1,value2,value3
234+
229235
# less
230236
column_name__less=value
231237
@@ -271,6 +277,8 @@ column_name__sum
271277

272278
> **Note**: Passing an aggregation operator (`count`, `avg`, `min`, `max`, `sum`) returns a column that is named `<column_name>__<operator>` (for instance: `?birth__groupby&score__sum` will return a list of dicts with the keys `birth` and `score__sum`).
273279
280+
> ⚠️ **WARNING**: columns that contain **JSON** objects (see the `profile` to know which ones do) **do not support filtering nor aggregation** for now.
281+
274282
#### Pagination
275283
```
276284
page=1 # Page number (default: 1)

api_tabular/utils.py

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,24 @@
88
from api_tabular import config
99

1010
TYPE_POSSIBILITIES = {
11-
"string": ["compare", "contains", "differs", "exact", "in", "sort", "groupby", "count"],
11+
"string": [
12+
"compare",
13+
"contains",
14+
"notcontains",
15+
"differs",
16+
"exact",
17+
"in",
18+
"notin",
19+
"sort",
20+
"groupby",
21+
"count",
22+
],
1223
"float": [
1324
"compare",
1425
"differs",
1526
"exact",
1627
"in",
28+
"notin",
1729
"sort",
1830
"groupby",
1931
"count",
@@ -27,6 +39,7 @@
2739
"differs",
2840
"exact",
2941
"in",
42+
"notin",
3043
"sort",
3144
"groupby",
3245
"count",
@@ -35,10 +48,33 @@
3548
"min",
3649
"sum",
3750
],
38-
"bool": ["differs", "exact", "in", "sort", "groupby", "count"],
39-
"date": ["compare", "contains", "differs", "exact", "in", "sort", "groupby", "count"],
40-
"datetime": ["compare", "contains", "differs", "exact", "in", "sort", "groupby", "count"],
41-
"json": ["contains", "differs", "exact", "in", "groupby", "count"],
51+
"bool": ["differs", "exact", "sort", "groupby", "count"],
52+
"date": [
53+
"compare",
54+
"contains",
55+
"notcontains",
56+
"differs",
57+
"exact",
58+
"in",
59+
"notin",
60+
"sort",
61+
"groupby",
62+
"count",
63+
],
64+
"datetime": [
65+
"compare",
66+
"contains",
67+
"notcontains",
68+
"differs",
69+
"exact",
70+
"in",
71+
"notin",
72+
"sort",
73+
"groupby",
74+
"count",
75+
],
76+
# TODO: JSON needs special treatment for operators to work
77+
"json": [],
4278
}
4379

4480
MAP_TYPES = {
@@ -61,10 +97,18 @@
6197
"name": "{}__contains",
6298
"description": "String contains in column: {} ({}__contains=value)",
6399
},
100+
"notcontains": {
101+
"name": "{}__notcontains",
102+
"description": "String does not contain in column: {} ({}__notcontains=value)",
103+
},
64104
"in": {
65105
"name": "{}__in",
66106
"description": "Value in list in column: {} ({}__in=value1,value2,...)",
67107
},
108+
"notin": {
109+
"name": "{}__notin",
110+
"description": "Value not in list in column: {} ({}__notin=value1,value2,...)",
111+
},
68112
"groupby": {
69113
"name": "{}__groupby",
70114
"description": "Performs `group by values` operation in column: {}",
@@ -114,7 +158,7 @@ def build_sql_query_string(
114158
request_arg: list,
115159
resource_id: str | None = None,
116160
indexes: set | None = None,
117-
page_size: int = None,
161+
page_size: int | None = None,
118162
offset: int = 0,
119163
) -> str:
120164
sql_query = []
@@ -190,8 +234,12 @@ def add_filter(argument: str, value: str, indexes: set | None) -> tuple[str | No
190234
return f"{column}=neq.{value}", False
191235
elif normalized_comparator == "contains":
192236
return f"{column}=ilike.*{value}*", False
237+
elif normalized_comparator == "notcontains":
238+
return f"{column}=not.ilike.*{value}*", False
193239
elif normalized_comparator == "in":
194240
return f"{column}=in.({value})", False
241+
elif normalized_comparator == "notin":
242+
return f"{column}=not.in.({value})", False
195243
elif normalized_comparator == "less":
196244
return f"{column}=lte.{value}", False
197245
elif normalized_comparator == "greater":

db/initdb/0-init.sql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ CREATE TABLE "csvapi".eb7a008177131590c2f1a2ca0 (
5959
decompte integer,
6060
is_true boolean,
6161
birth character varying,
62-
liste character varying
62+
liste JSON
6363
);
6464

6565

@@ -1214,7 +1214,7 @@ CREATE TABLE "csvapi".s34fff81a3a7292c64a77e5cz (
12141214
decompte integer,
12151215
is_true boolean,
12161216
birth character varying,
1217-
liste character varying
1217+
liste JSON
12181218
);
12191219

12201220

@@ -1299,7 +1299,7 @@ CREATE TABLE "csvapi".aa2zoa2zfb243p45azj33ap1o (
12991299
decompte integer,
13001300
is_true boolean,
13011301
birth character varying,
1302-
liste character varying
1302+
liste JSON
13031303
);
13041304

13051305

@@ -1384,7 +1384,7 @@ CREATE TABLE "csvapi".p34zej8pnq446k2ejfz2m3dqz (
13841384
decompte integer,
13851385
is_true boolean,
13861386
birth character varying,
1387-
liste character varying
1387+
liste JSON
13881388
);
13891389

13901390

tests/test_api.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,19 @@ async def test_api_exception_resource_no_indexes(client, base_url, tables_index_
308308
assert res.status == 200
309309

310310
# checking that the resource can be filtered on all columns
311-
for col in detection["columns"].keys():
311+
for col, results in detection["columns"].items():
312+
if results["python_type"] == "json":
313+
continue
312314
res = await client.get(
313315
f"{base_url}/api/resources/{_resource_id}/data/?{col}__exact=1&page=1&page_size=1"
314316
)
315317
assert res.status == 200
316318

317319
# if aggregation is allowed:
318320
# checking whether aggregation is allowed on all columns or none
319-
for col in detection["columns"].keys():
321+
for col, results in detection["columns"].items():
322+
if results["python_type"] == "json":
323+
continue
320324
res = await client.get(
321325
f"{base_url}/api/resources/{_resource_id}/data/?{col}__groupby&page=1&page_size=1"
322326
)

0 commit comments

Comments
 (0)