diff --git a/src/db.py b/src/db.py index f9ffd39..a0e1978 100644 --- a/src/db.py +++ b/src/db.py @@ -155,12 +155,16 @@ def query_marches( sql += f" LIMIT {int(limit)}" if offset is not None: sql += f" OFFSET {int(offset)}" + + logger.debug("query_marches: " + sql.replace("?", "{}").format(*params)) + return get_cursor().execute(sql, list(params)).pl() def count_marches(where_sql: str = "TRUE", params: tuple | list = ()) -> int: """Retourne le nombre de lignes correspondant à where_sql.""" sql = f"SELECT COUNT(*) FROM decp WHERE {where_sql}" + logger.debug("count_marches: " + sql.replace("?", "{}").format(*params)) result = get_cursor().execute(sql, list(params)).fetchone() return int(result[0]) if result else 0 @@ -168,5 +172,6 @@ def count_marches(where_sql: str = "TRUE", params: tuple | list = ()) -> int: def count_unique_marches(where_sql: str = "TRUE", params: tuple | list = ()) -> int: """Retourne le nombre de uid distincts correspondant à where_sql.""" sql = f"SELECT COUNT(DISTINCT uid) FROM decp WHERE {where_sql}" + logger.debug("count_unique_marches: " + sql.replace("?", "{}").format(*params)) result = get_cursor().execute(sql, list(params)).fetchone() return int(result[0]) if result else 0 diff --git a/src/utils/filtering.py b/src/utils/filtering.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/table_sql.py b/src/utils/table_sql.py index f670f80..516d6dd 100644 --- a/src/utils/table_sql.py +++ b/src/utils/table_sql.py @@ -57,17 +57,11 @@ def filter_query_to_sql(filter_query: str, schema: pl.Schema) -> tuple[str, list value = raw_value.strip('"') if operator == "contains": - if value.endswith("*") and not value.startswith("*"): - like = value[:-1] + "%" - elif value.startswith("*") and not value.endswith("*"): - like = "%" + value[1:] - else: - like = "%" + value + "%" - target = f"CAST({quoted_col} AS VARCHAR)" if col_is_date else quoted_col - clauses.append( - f"{quoted_col} IS NOT NULL AND {target} <> '' AND {target} ILIKE ?" - ) - params.append(like) + where_clause, param_list = tokenize_text_filter(col_name, value) + clauses.append(where_clause) + params.extend(param_list) + logger.debug(params) + elif operator in (">", "<"): target = f"CAST({quoted_col} AS VARCHAR)" if col_is_date else quoted_col clauses.append(f"{quoted_col} IS NOT NULL AND {target} {operator} ?") @@ -163,8 +157,9 @@ def dashboard_filters_to_sql( params.append(dashboard_marche_type) if dashboard_marche_objet: - clauses.append('"objet" ILIKE ?') - params.append(f"%{dashboard_marche_objet}%") + where_clause, param_list = tokenize_text_filter("objet", dashboard_marche_objet) + clauses.append(where_clause) + params.extend(param_list) if dashboard_marche_code_cpv: clauses.append('"codeCPV" LIKE ?') @@ -206,3 +201,23 @@ def dashboard_filters_to_sql( params.append(dashboard_montant_max) return " AND ".join(clauses), params + + +def tokenize_text_filter(column: str, text: str) -> tuple[str, list]: + terms = text.split() + + conditions = [] + params = [] + + for term in terms: + conditions.append(f'"{column}" ILIKE ?') + + if term.startswith("*") or term.endswith("*"): + params.append(term.replace("*", "%")) + if "+" in term: + params.append(f"%{term.replace('+', ' ')}%") + else: + params.append(f"%{term}%") + + where_clause = " AND ".join(conditions) + return where_clause, params