Fix float coercion for numeric filter parameters (#2876)

Closes #1681
This commit is contained in:
Rami Abdelrazzaq 2026-09-15 15:14:29 -05:00 committed by GitHub
commit 82ed8d47f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 2 deletions

View file

@ -1,4 +1,5 @@
import json
import math
from typing import ClassVar
from datasette import hookimpl
@ -202,6 +203,17 @@ class Filter:
raise NotImplementedError
def _coerce_numeric_filter_value(value):
try:
return int(value)
except ValueError:
try:
converted = float(value)
except ValueError:
return value
return converted if math.isfinite(converted) else value
class TemplatedFilter(Filter):
def __init__(
self,
@ -223,8 +235,8 @@ class TemplatedFilter(Filter):
def where_clause(self, table, column, value, param_counter):
converted = self.format.format(value)
if self.numeric and converted.isdigit():
converted = int(converted)
if self.numeric:
converted = _coerce_numeric_filter_value(converted)
if self.no_argument:
kwargs = {"c": _quote_sqlite_identifier(column)}
converted = None

View file

@ -0,0 +1,45 @@
import sqlite3
import pytest
from datasette.filters import Filters
@pytest.mark.parametrize(
"value,expected",
(
("3.5", 3.5),
("-2", -2),
("-2.5", -2.5),
("1e3", 1000.0),
("not-a-number", "not-a-number"),
("nan", "nan"),
("inf", "inf"),
("-inf", "-inf"),
),
)
def test_numeric_filter_parameters(value, expected):
filters = Filters((("score__gt", value),))
sql_bits, params = filters.build_where_clauses("items")
assert sql_bits == ['"score" > :p0']
assert params == {"p0": expected}
def test_numeric_filter_parameters_against_calculated_view():
conn = sqlite3.connect(":memory:")
conn.execute("create table searchable(pk integer)")
conn.executemany("insert into searchable(pk) values (?)", [(0,), (1,), (2,)])
conn.execute(
"create view calculated as "
"select pk + 1 as pk_plus_one, pk / 2.0 as score from searchable"
)
sql_bits, params = Filters((("score__gt", "0.1"),)).build_where_clauses(
"calculated"
)
rows = conn.execute(
"select score from calculated where {}".format(" and ".join(sql_bits)), params
).fetchall()
assert rows == [(0.5,), (1.0,)]