Implemented ?_search=XXX + UI if a FTS table is detected

Closes #131
pull/104/head
Simon Willison 2017-11-19 08:59:26 -08:00
rodzic f59c840e7d
commit eed6a0fe36
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: FBB38AFE227189DB
5 zmienionych plików z 75 dodań i 5 usunięć

Wyświetl plik

@ -19,6 +19,7 @@ from .utils import (
build_where_clauses,
compound_pks_from_path,
CustomJSONEncoder,
detect_fts_sql,
escape_css_string,
escape_sqlite_table_name,
get_all_foreign_keys,
@ -427,6 +428,22 @@ class TableView(BaseView):
where_clauses = []
params = {}
# _search support:
fts_table = None
fts_sql = detect_fts_sql(table)
fts_rows = list(await self.execute(name, fts_sql))
if fts_rows:
fts_table=fts_rows[0][0]
search = special_args.get('_search')
if search and fts_table:
where_clauses.append(
'rowid in (select rowid from {fts_table} where {fts_table} match :search)'.format(
fts_table=fts_table
)
)
params['search'] = search
next = special_args.get('_next')
offset = ''
if next:
@ -504,6 +521,8 @@ class TableView(BaseView):
async def extra_template():
return {
'database_hash': hash,
'supports_search': bool(fts_table),
'search': search or '',
'use_rowid': use_rowid,
'display_columns': display_columns,
'display_rows': await self.make_display_rows(name, hash, table, rows, display_columns, pks, is_view, use_rowid),

Wyświetl plik

@ -90,12 +90,13 @@ form.sql textarea {
font-family: monospace;
font-size: 1.3em;
}
form.sql label {
form label {
font-weight: bold;
display: inline-block;
width: 15%;
}
form.sql input[type=text] {
form input[type=text],
form input[type=search] {
border: 1px solid #ccc;
width: 60%;
padding: 4px;
@ -103,12 +104,15 @@ form.sql input[type=text] {
display: inline-block;
font-size: 1.1em;
}
form input[type=search] {
width: 40%;
}
@media only screen and (max-width: 576px) {
form.sql textarea {
width: 95%;
}
}
form.sql input[type=submit] {
form input[type=submit] {
color: #fff;
background-color: #007bff;
border-color: #007bff;
@ -118,7 +122,7 @@ form.sql input[type=submit] {
vertical-align: middle;
border: 1px solid blue;
padding: .275rem .75rem;
font-size: 1rem;
line-height: 1.5;
font-size: 0.9rem;
line-height: 1;
border-radius: .25rem;
}

Wyświetl plik

@ -21,6 +21,12 @@
<h2>{{ "{:,}".format(table_rows) }} total row{% if table_rows == 1 %}{% else %}s{% endif %} in this table</h2>
{% endif %}
{% if supports_search %}
<form action="/{{ database }}-{{ database_hash }}/{{ table|quote_plus }}" method="get">
<p><input type="search" name="_search" value="{{ search }}"> <input type="submit" value="Search"></p>
</form>
{% endif %}
{% if query.params %}
<pre>{{ query.sql }}</pre>
<pre>params = {{ query.params|tojson(4) }}</pre>

Wyświetl plik

@ -235,3 +235,20 @@ def get_all_foreign_keys(conn):
})
return table_to_foreign_keys
def detect_fts(conn, table, return_sql=False):
"Detect if table has a corresponding FTS virtual table and return it"
rows = conn.execute(detect_fts_sql(table)).fetchall()
if len(rows) == 0:
return None
else:
return rows[0][0]
def detect_fts_sql(table):
return r'''
select name from sqlite_master
where rootpage = 0
and sql like '%VIRTUAL TABLE%USING FTS%content="{}"%';
'''.format(table)

Wyświetl plik

@ -4,6 +4,7 @@ Tests for various datasette helper functions.
from datasette import utils
import pytest
import sqlite3
import json
@ -124,3 +125,26 @@ def test_validate_sql_select_bad(bad_sql):
])
def test_validate_sql_select_good(good_sql):
utils.validate_sql_select(good_sql)
def test_detect_fts():
sql = '''
CREATE TABLE "Dumb_Table" (
"TreeID" INTEGER,
"qSpecies" TEXT
);
CREATE TABLE "Street_Tree_List" (
"TreeID" INTEGER,
"qSpecies" TEXT,
"qAddress" TEXT,
"SiteOrder" INTEGER,
"qSiteInfo" TEXT,
"PlantType" TEXT,
"qCaretaker" TEXT
);
CREATE VIRTUAL TABLE "Street_Tree_List_fts" USING FTS4 ("qAddress", "qCaretaker", "qSpecies", content="Street_Tree_List");
'''
conn = sqlite3.connect(':memory:')
conn.executescript(sql)
assert None is utils.detect_fts(conn, 'Dumb_Table')
assert 'Street_Tree_List_fts' == utils.detect_fts(conn, 'Street_Tree_List')