mirror of
https://github.com/simonw/datasette.git
synced 2026-09-16 05:24:21 +02:00
parent
f40d838429
commit
82ed8d47f9
2 changed files with 59 additions and 2 deletions
|
|
@ -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
|
||||
|
|
|
|||
45
tests/test_numeric_filter_values.py
Normal file
45
tests/test_numeric_filter_values.py
Normal 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,)]
|
||||
Loading…
Add table
Add a link
Reference in a new issue