From 2a8e82ccd692a0d06ca1df261f93770b423be4ff Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Mon, 22 Jun 2026 13:55:18 +0200 Subject: [PATCH] =?UTF-8?q?feat(api):=20ajoute=20l'op=C3=A9rateur=20de=20f?= =?UTF-8?q?iltre=20differs=20(IS=20DISTINCT=20FROM)=20(#78)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implémente l'opérateur de filtre `differs` qui génère un fragment SQL `IS DISTINCT FROM` pour exclure des valeurs en tenant compte des NULL. Co-Authored-By: Claude Sonnet 4.6 --- src/api/filters.py | 4 ++++ tests/api/test_endpoints_data.py | 10 ++++++++++ tests/api/test_filters.py | 12 ++++++++++++ 3 files changed, 26 insertions(+) diff --git a/src/api/filters.py b/src/api/filters.py index 9ca30d1..2106fdc 100644 --- a/src/api/filters.py +++ b/src/api/filters.py @@ -6,6 +6,7 @@ OPERATORS = { "exact", "contains", "notcontains", + "differs", "less", "greater", "strictly_less", @@ -132,6 +133,9 @@ def build_where( elif op == "notcontains": where_parts.append(f'"{col}" NOT LIKE ?') params.append(f"%{v}%") + elif op == "differs": + where_parts.append(f'"{col}" IS DISTINCT FROM ?') + params.append(v) where_sql = " AND ".join(where_parts) if where_parts else "TRUE" order_sql = ", ".join(order_parts) if order_parts else None diff --git a/tests/api/test_endpoints_data.py b/tests/api/test_endpoints_data.py index 991c1c3..010f20a 100644 --- a/tests/api/test_endpoints_data.py +++ b/tests/api/test_endpoints_data.py @@ -102,3 +102,13 @@ def test_data_sort_desc(api_client, valid_token_header): row["dateNotification"] for row in body["data"] if row.get("dateNotification") ] assert dates == sorted(dates, reverse=True) + + +def test_data_differs_excludes_value(api_client, valid_token_header): + client, _ = api_client + base = client.get("/api/v1/data?page_size=1", headers=valid_token_header).get_json() + uid = base["data"][0]["uid"] + resp = client.get(f"/api/v1/data?uid__differs={uid}", headers=valid_token_header) + assert resp.status_code == 200 + body = resp.get_json() + assert all(row["uid"] != uid for row in body["data"]) diff --git a/tests/api/test_filters.py b/tests/api/test_filters.py index 8d3ecd5..239a317 100644 --- a/tests/api/test_filters.py +++ b/tests/api/test_filters.py @@ -139,3 +139,15 @@ def test_sort_invalid_direction_raises(): def test_param_without_operator_raises(): with pytest.raises(FilterError): build_where([("uidexact", "x")], SCHEMA) + + +def test_differs_filter(): + where, params, _ = build_where([("uid__differs", "abc")], SCHEMA) + assert where == '"uid" IS DISTINCT FROM ?' + assert params == ["abc"] + + +def test_differs_filter_on_int(): + where, params, _ = build_where([("annee__differs", "2020")], SCHEMA) + assert where == '"annee" IS DISTINCT FROM ?' + assert params == [2020]