kopia lustrzana https://github.com/simonw/datasette
Fixed incorrect display of compound primary keys with foreign key references
Closes #319pull/322/head^2
rodzic
3683a6b626
commit
3b53eea382
|
@ -70,8 +70,10 @@ def path_from_row_pks(row, pks, use_rowid, quote=True):
|
|||
if use_rowid:
|
||||
bits = [row['rowid']]
|
||||
else:
|
||||
bits = [row[pk] for pk in pks]
|
||||
|
||||
bits = [
|
||||
row[pk]["value"] if isinstance(row[pk], dict) else row[pk]
|
||||
for pk in pks
|
||||
]
|
||||
if quote:
|
||||
bits = [urllib.parse.quote_plus(str(bit)) for bit in bits]
|
||||
else:
|
||||
|
@ -817,8 +819,10 @@ def path_with_format(request, format, extra_qs=None):
|
|||
class CustomRow(OrderedDict):
|
||||
# Loose imitation of sqlite3.Row which offers
|
||||
# both index-based AND key-based lookups
|
||||
def __init__(self, columns):
|
||||
def __init__(self, columns, values=None):
|
||||
self.columns = columns
|
||||
if values:
|
||||
self.update(values)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, int):
|
||||
|
|
|
@ -303,6 +303,10 @@ INSERT INTO units VALUES (1, 1, 100);
|
|||
INSERT INTO units VALUES (2, 5000, 2500);
|
||||
INSERT INTO units VALUES (3, 100000, 75000);
|
||||
|
||||
CREATE TABLE tags (
|
||||
tag TEXT PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE searchable (
|
||||
pk integer primary key,
|
||||
text1 text,
|
||||
|
@ -310,9 +314,25 @@ CREATE TABLE searchable (
|
|||
[name with . and spaces] text
|
||||
);
|
||||
|
||||
CREATE TABLE searchable_tags (
|
||||
searchable_id integer,
|
||||
tag text,
|
||||
PRIMARY KEY (searchable_id, tag),
|
||||
FOREIGN KEY (searchable_id) REFERENCES searchable(pk),
|
||||
FOREIGN KEY (tag) REFERENCES tags(tag)
|
||||
);
|
||||
|
||||
INSERT INTO searchable VALUES (1, 'barry cat', 'terry dog', 'panther');
|
||||
INSERT INTO searchable VALUES (2, 'terry dog', 'sara weasel', 'puma');
|
||||
|
||||
INSERT INTO tags VALUES ("canine");
|
||||
INSERT INTO tags VALUES ("feline");
|
||||
|
||||
INSERT INTO searchable_tags (searchable_id, tag) VALUES
|
||||
(1, "feline"),
|
||||
(2, "canine")
|
||||
;
|
||||
|
||||
CREATE VIRTUAL TABLE "searchable_fts"
|
||||
USING FTS3 (text1, text2, [name with . and spaces], content="searchable");
|
||||
INSERT INTO "searchable_fts" (rowid, text1, text2, [name with . and spaces])
|
||||
|
|
|
@ -17,7 +17,7 @@ def test_homepage(app_client):
|
|||
assert response.json.keys() == {'fixtures': 0}.keys()
|
||||
d = response.json['fixtures']
|
||||
assert d['name'] == 'fixtures'
|
||||
assert d['tables_count'] == 17
|
||||
assert d['tables_count'] == 19
|
||||
|
||||
|
||||
def test_database_page(app_client):
|
||||
|
@ -188,11 +188,38 @@ def test_database_page(app_client):
|
|||
'columns': ['pk', 'text1', 'text2', 'name with . and spaces'],
|
||||
'name': 'searchable',
|
||||
'count': 2,
|
||||
'foreign_keys': {'incoming': [], 'outgoing': []},
|
||||
'foreign_keys': {'incoming': [{
|
||||
"other_table": "searchable_tags",
|
||||
"column": "pk",
|
||||
"other_column": "searchable_id"
|
||||
}], 'outgoing': []},
|
||||
'fts_table': 'searchable_fts',
|
||||
'hidden': False,
|
||||
'label_column': None,
|
||||
'primary_keys': ['pk'],
|
||||
}, {
|
||||
"name": "searchable_tags",
|
||||
"columns": ["searchable_id", "tag"],
|
||||
"primary_keys": ["searchable_id", "tag"],
|
||||
"count": 2,
|
||||
"label_column": None,
|
||||
"hidden": False,
|
||||
"fts_table": None,
|
||||
"foreign_keys": {
|
||||
"incoming": [],
|
||||
"outgoing": [
|
||||
{
|
||||
"other_table": "tags",
|
||||
"column": "tag",
|
||||
"other_column": "tag",
|
||||
},
|
||||
{
|
||||
"other_table": "searchable",
|
||||
"column": "searchable_id",
|
||||
"other_column": "pk",
|
||||
},
|
||||
],
|
||||
},
|
||||
}, {
|
||||
'columns': ['group', 'having', 'and'],
|
||||
'name': 'select',
|
||||
|
@ -251,6 +278,24 @@ def test_database_page(app_client):
|
|||
'label_column': None,
|
||||
'fts_table': None,
|
||||
'primary_keys': ['pk'],
|
||||
}, {
|
||||
"name": "tags",
|
||||
"columns": ["tag"],
|
||||
"primary_keys": ["tag"],
|
||||
"count": 2,
|
||||
"label_column": None,
|
||||
"hidden": False,
|
||||
"fts_table": None,
|
||||
"foreign_keys": {
|
||||
"incoming": [
|
||||
{
|
||||
"other_table": "searchable_tags",
|
||||
"column": "tag",
|
||||
"other_column": "tag",
|
||||
}
|
||||
],
|
||||
"outgoing": [],
|
||||
},
|
||||
}, {
|
||||
'columns': ['pk', 'distance', 'frequency'],
|
||||
'name': 'units',
|
||||
|
|
|
@ -550,6 +550,26 @@ def test_row_html_compound_primary_key(app_client):
|
|||
assert expected == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')]
|
||||
|
||||
|
||||
def test_compound_primary_key_with_foreign_key_references(app_client):
|
||||
# e.g. a many-to-many table with a compound primary key on the two columns
|
||||
response = app_client.get('/fixtures/searchable_tags')
|
||||
assert response.status == 200
|
||||
table = Soup(response.body, 'html.parser').find('table')
|
||||
expected = [
|
||||
[
|
||||
'<td class="col-Link"><a href="/fixtures/searchable_tags/1,feline">1,feline</a></td>',
|
||||
'<td class="col-searchable_id"><a href="/fixtures/searchable/1">1</a>\xa0<em>1</em></td>',
|
||||
'<td class="col-tag"><a href="/fixtures/tags/feline">feline</a></td>',
|
||||
],
|
||||
[
|
||||
'<td class="col-Link"><a href="/fixtures/searchable_tags/2,canine">2,canine</a></td>',
|
||||
'<td class="col-searchable_id"><a href="/fixtures/searchable/2">2</a>\xa0<em>2</em></td>',
|
||||
'<td class="col-tag"><a href="/fixtures/tags/canine">canine</a></td>',
|
||||
],
|
||||
]
|
||||
assert expected == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')]
|
||||
|
||||
|
||||
def test_view_html(app_client):
|
||||
response = app_client.get('/fixtures/simple_view')
|
||||
assert response.status == 200
|
||||
|
|
|
@ -75,11 +75,34 @@ def test_path_with_replaced_args(path, args, expected):
|
|||
assert expected == actual
|
||||
|
||||
|
||||
@pytest.mark.parametrize('row,pks,expected_path', [
|
||||
({'A': 'foo', 'B': 'bar'}, ['A', 'B'], 'foo,bar'),
|
||||
({'A': 'f,o', 'B': 'bar'}, ['A', 'B'], 'f%2Co,bar'),
|
||||
({'A': 123}, ['A'], '123'),
|
||||
])
|
||||
@pytest.mark.parametrize(
|
||||
"row,pks,expected_path",
|
||||
[
|
||||
({"A": "foo", "B": "bar"}, ["A", "B"], "foo,bar"),
|
||||
({"A": "f,o", "B": "bar"}, ["A", "B"], "f%2Co,bar"),
|
||||
({"A": 123}, ["A"], "123"),
|
||||
(
|
||||
utils.CustomRow(
|
||||
["searchable_id", "tag"],
|
||||
[
|
||||
(
|
||||
"searchable_id",
|
||||
{"value": 1, "label": "1"},
|
||||
),
|
||||
(
|
||||
"tag",
|
||||
{
|
||||
"value": "feline",
|
||||
"label": "feline",
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
["searchable_id", "tag"],
|
||||
"1,feline",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_path_from_row_pks(row, pks, expected_path):
|
||||
actual_path = utils.path_from_row_pks(row, pks, False)
|
||||
assert expected_path == actual_path
|
||||
|
|
Ładowanie…
Reference in New Issue