Started implementing ?name__contains=X filters

So far we support __contains=, __startswith=, __endswith= and __exact=

Refs #23
magic-columns
Simon Willison 2017-10-24 17:06:23 -07:00
rodzic 4c7379a898
commit 1ae8ea0f03
2 zmienionych plików z 59 dodań i 1 usunięć

41
app.py
Wyświetl plik

@ -183,7 +183,15 @@ class TableView(BaseView):
def data(self, request, name, hash, table):
conn = get_conn(name)
rows = conn.execute('select * from {} limit 20'.format(table))
if request.args:
where_clause, params = build_where_clause(request.args)
sql = 'select * from "{}" where {} limit 50'.format(
table, where_clause
)
else:
sql = 'select * from "{}" limit 50'.format(table)
params = []
rows = conn.execute(sql, params)
columns = [r[0] for r in rows.description]
pks = pks_for_table(conn, table)
rows = list(rows)
@ -294,6 +302,37 @@ def path_from_row_pks(row, pks):
return ','.join(bits)
def build_where_clause(args):
sql_bits = []
for key, values in args.items():
if '__' in key:
column, lookup = key.rsplit('__', 1)
else:
column = key
lookup = 'exact'
template = {
'exact': '"{}" = ?',
'contains': '"{}" like ?',
'endswith': '"{}" like ?',
'startswith': '"{}" like ?',
}[lookup]
value = values[0]
value_convert = {
'exact': lambda s: s,
'contains': lambda s: '%{}%'.format(s),
'endswith': lambda s: '%{}'.format(s),
'startswith': lambda s: '{}%'.format(s),
}[lookup]
converted = value_convert(value)
sql_bits.append(
(template.format(column), converted)
)
sql_bits.sort(key=lambda p: p[0])
where_clause = ' and '.join(p[0] for p in sql_bits)
params = [p[1] for p in sql_bits]
return where_clause, params
class CustomJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, sqlite3.Row):

Wyświetl plik

@ -64,3 +64,22 @@ def test_custom_json_encoder(obj, expected):
sort_keys=True
)
assert expected == actual
@pytest.mark.parametrize('args,expected_where,expected_params', [
({
'name_english__contains': ['foo'],
}, '"name_english" like ?', ['%foo%']),
({
'foo': ['bar'],
'bar__contains': ['baz'],
}, '"bar" like ? and "foo" = ?', ['%baz%', 'bar']),
({
'foo__startswith': ['bar'],
'bar__endswith': ['baz'],
}, '"bar" like ? and "foo" like ?', ['%baz', 'bar%']),
])
def test_build_where(args, expected_where, expected_params):
actual_where, actual_params = app.build_where_clause(args)
assert expected_where == actual_where
assert expected_params == actual_params