arraynotcontains filter, closes #1132

This commit is contained in:
Simon Willison 2020-12-07 14:41:03 -08:00
commit 4c25b035b2
3 changed files with 39 additions and 4 deletions

View file

@ -154,7 +154,16 @@ class Filters:
where j.value = :{p} where j.value = :{p}
)""", )""",
'{c} contains "{v}"', '{c} contains "{v}"',
) ),
TemplatedFilter(
"arraynotcontains",
"array does not contain",
"""rowid not in (
select {t}.rowid from {t}, json_each({t}.{c}) j
where j.value = :{p}
)""",
'{c} does not contain "{v}"',
),
] ]
if detect_json1() if detect_json1()
else [] else []

View file

@ -267,7 +267,12 @@ You can filter the data returned by the table based on column values using a que
Rows where column does not match any of the provided values. The inverse of ``__in=``. Also supports JSON arrays. Rows where column does not match any of the provided values. The inverse of ``__in=``. Also supports JSON arrays.
``?column__arraycontains=value`` ``?column__arraycontains=value``
Works against columns that contain JSON arrays - matches if any of the values in that array match. Works against columns that contain JSON arrays - matches if any of the values in that array match the provided value.
This is only available if the ``json1`` SQLite extension is enabled.
``?column__arraynotcontains=value``
Works against columns that contain JSON arrays - matches if none of the values in that array match the provided value.
This is only available if the ``json1`` SQLite extension is enabled. This is only available if the ``json1`` SQLite extension is enabled.

View file

@ -1121,7 +1121,7 @@ def test_table_filter_queries_multiple_of_same_type(app_client):
@pytest.mark.skipif(not detect_json1(), reason="Requires the SQLite json1 module") @pytest.mark.skipif(not detect_json1(), reason="Requires the SQLite json1 module")
def test_table_filter_json_arraycontains(app_client): def test_table_filter_json_arraycontains(app_client):
response = app_client.get("/fixtures/facetable.json?tags__arraycontains=tag1") response = app_client.get("/fixtures/facetable.json?tags__arraycontains=tag1")
assert [ assert response.json["rows"] == [
[ [
1, 1,
"2019-01-14 08:00:00", "2019-01-14 08:00:00",
@ -1146,7 +1146,28 @@ def test_table_filter_json_arraycontains(app_client):
"[]", "[]",
"two", "two",
], ],
] == response.json["rows"] ]
@pytest.mark.skipif(not detect_json1(), reason="Requires the SQLite json1 module")
def test_table_filter_json_arraynotcontains(app_client):
response = app_client.get(
"/fixtures/facetable.json?tags__arraynotcontains=tag3&tags__not=[]"
)
assert response.json["rows"] == [
[
1,
"2019-01-14 08:00:00",
1,
1,
"CA",
1,
"Mission",
'["tag1", "tag2"]',
'[{"foo": "bar"}]',
"one",
]
]
def test_table_filter_extra_where(app_client): def test_table_filter_extra_where(app_client):