From f4b57dbe5cc78d4122eb3ed8852ae77a779ad68b Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Tue, 5 May 2026 14:08:50 +0200 Subject: [PATCH] Gestion des filtres de dates comme du texte #76 --- src/utils/table_sql.py | 21 +++++++++++++++++---- tests/test_main.py | 26 +++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/utils/table_sql.py b/src/utils/table_sql.py index 756bde8..2c3dcdd 100644 --- a/src/utils/table_sql.py +++ b/src/utils/table_sql.py @@ -57,12 +57,18 @@ def filter_query_to_sql(filter_query: str, schema: pl.Schema) -> tuple[str, list value = raw_value.strip('"') if operator == "contains": + if col_is_date: + target = f"CAST({quoted_col} AS VARCHAR)" + if col_name in ("acheteur_id", "titulaire_id"): value = value.replace(" ", "") - where_clause, param_list = tokenize_text_filter(col_name, value) + where_clause, param_list = tokenize_text_filter( + col_name, value, col_is_date + ) clauses.append(where_clause) params.extend(param_list) logger.debug(params) + continue elif operator in (">", "<"): target = f"CAST({quoted_col} AS VARCHAR)" if col_is_date else quoted_col @@ -207,15 +213,22 @@ def dashboard_filters_to_sql( return " AND ".join(clauses), params -def tokenize_text_filter(column: str, text: str) -> tuple[str, list]: +def tokenize_text_filter( + column: str, text: str, col_is_date: bool = False +) -> tuple[str, list]: terms = text.split() + # si col_is_date alors le deuxième doit être casté en VARCHAR + if col_is_date: + quoted_col = f'CAST("{column}" AS VARCHAR)' + else: + quoted_col = '"column"' - conditions = [f'"{column}" IS NOT NULL', f"\"{column}\" <> ''"] + conditions = [f'"{column}" IS NOT NULL', f"{quoted_col} <> ''"] params = [] for term in terms: - conditions.append(f'"{column}" ILIKE ?') + conditions.append(f"{quoted_col} ILIKE ?") if term.startswith("*") or term.endswith("*"): params.append(term.replace("*", "%")) diff --git a/tests/test_main.py b/tests/test_main.py index ae9b36c..5a606cf 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -292,7 +292,7 @@ def test_011_observatoire_multi_param_url(dash_duo: DashComposite): ) -def test_get_distance_histogram_returns_graph(): +def test_012_get_distance_histogram_returns_graph(): import polars as pl from dash import dcc @@ -303,7 +303,7 @@ def test_get_distance_histogram_returns_graph(): assert isinstance(result, dcc.Graph) -def test_get_distance_histogram_handles_nulls(): +def test_013_get_distance_histogram_handles_nulls(): import polars as pl from dash import dcc @@ -314,7 +314,7 @@ def test_get_distance_histogram_handles_nulls(): assert isinstance(result, dcc.Graph) -def test_get_distance_histogram_all_nulls(): +def test_014_get_distance_histogram_all_nulls(): import polars as pl from dash import dcc @@ -322,4 +322,24 @@ def test_get_distance_histogram_all_nulls(): lff = pl.LazyFrame({"titulaire_distance": pl.Series([], dtype=pl.Int64)}) result = get_distance_histogram(lff) + assert isinstance(result, dcc.Graph) + + +def test_015_tableau_filter_date(dash_duo: DashComposite): + from src.app import app + + dash_duo.start_server(app) + dash_duo.wait_for_text_to_equal(".logo > h1", "decp.info", timeout=4) + + for page in ["tableau", "acheteurs/123", "titulaires/345"]: + dash_duo.wait_for_page(f"{dash_duo.server_url}/{page}") + filter_input = '.marches_table th[data-dash-column="dateNotification"] input' + filter_cell_result = '.marches_table td[data-dash-column="dateNotification"] p' + dash_duo.wait_for_element(filter_input, timeout=2) + _filter_input: WebElement = dash_duo.find_element(filter_input) + _filter_input.send_keys("2024") # a dateNotification that doesn't exist + _filter_input.send_keys(Keys.ENTER) + _filter_result: list[WebElement] = dash_duo.find_elements(filter_cell_result) + + assert len(_filter_result) == 0