mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Compare commits
1 commit
main
...
custom-rou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
018af454f2 |
2 changed files with 143 additions and 0 deletions
78
datasette/routes.py
Normal file
78
datasette/routes.py
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
from collections import namedtuple
|
||||||
|
from datasette.views.database import DatabaseView
|
||||||
|
from datasette.views.special import JsonDataView
|
||||||
|
from datasette.views.table import TableView
|
||||||
|
|
||||||
|
RouteResult = namedtuple('RouteResult', ('view', 'kwargs', 'redirect'))
|
||||||
|
|
||||||
|
|
||||||
|
def redirect(path):
|
||||||
|
return RouteResult(None, None, path)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve(path, database_exists, table_exists, database_hash):
|
||||||
|
bits = path.split('/')
|
||||||
|
# Kill the leading /:
|
||||||
|
del bits[0]
|
||||||
|
# /-/...
|
||||||
|
if bits[0] == '-':
|
||||||
|
return resolve_special(bits[1:])
|
||||||
|
# /databasename
|
||||||
|
bit = bits[0]
|
||||||
|
rest = ''
|
||||||
|
if bits[1:]:
|
||||||
|
rest = '/'.join([''] + bits[1:])
|
||||||
|
# Might be database-databasehash
|
||||||
|
if '-' in bit:
|
||||||
|
database, databasehash = bit.rsplit('-', 1)
|
||||||
|
if database_exists(database):
|
||||||
|
# Is the hash correct?
|
||||||
|
expected_hash = database_hash(database)
|
||||||
|
if expected_hash == databasehash:
|
||||||
|
if not rest:
|
||||||
|
return RouteResult(
|
||||||
|
DatabaseView, {'database': database}, None
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Pass on to table logic
|
||||||
|
return resolve_table(rest, database, table_exists)
|
||||||
|
else:
|
||||||
|
# Bad hash, redirect
|
||||||
|
return redirect('/{}-{}{}'.format(
|
||||||
|
database, expected_hash, rest)
|
||||||
|
)
|
||||||
|
# If we get here, maybe the full string is a DB name?
|
||||||
|
if database_exists(bit):
|
||||||
|
database = bit
|
||||||
|
databasehash = database_hash(bit)
|
||||||
|
return redirect('/{}-{}{}'.format(database, databasehash, rest))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_table(rest, database, table_exists):
|
||||||
|
# TODO: Rows, views, canned queries
|
||||||
|
table = rest.lstrip('/')
|
||||||
|
if not table_exists(database, table):
|
||||||
|
return None
|
||||||
|
return RouteResult(TableView, {'database': database, 'table': table}, None)
|
||||||
|
|
||||||
|
|
||||||
|
specials = {'inspect', 'metadata', 'versions', 'plugins', 'config'}
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_special(path_bits):
|
||||||
|
if len(path_bits) != 1:
|
||||||
|
return None
|
||||||
|
filename = path_bits[0]
|
||||||
|
as_json = False
|
||||||
|
if filename.endswith('.json'):
|
||||||
|
as_json = True
|
||||||
|
filename = filename.replace('.json', '')
|
||||||
|
if filename not in specials:
|
||||||
|
return None
|
||||||
|
kwargs = {
|
||||||
|
'filename': filename,
|
||||||
|
}
|
||||||
|
if as_json:
|
||||||
|
kwargs['format'] = 'json'
|
||||||
|
return RouteResult(JsonDataView, kwargs, None)
|
||||||
65
tests/test_routes.py
Normal file
65
tests/test_routes.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
from datasette import routes
|
||||||
|
from datasette.views.database import DatabaseView
|
||||||
|
from datasette.views.special import JsonDataView
|
||||||
|
from datasette.views.table import TableView
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
MOCK_DATABASES = {
|
||||||
|
# database: set-of-tables
|
||||||
|
'foo': {'bar'},
|
||||||
|
'foo-bar': {'baz'}
|
||||||
|
}
|
||||||
|
MOCK_DATABASE_HASHES = {
|
||||||
|
'foo': 'foohash',
|
||||||
|
'foo-bar': 'foobarhash',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def database_exists(database):
|
||||||
|
return database in MOCK_DATABASES
|
||||||
|
|
||||||
|
|
||||||
|
def table_exists(database, table):
|
||||||
|
print('table_exists: ', database, table)
|
||||||
|
return table in MOCK_DATABASES.get(database, set())
|
||||||
|
|
||||||
|
|
||||||
|
def database_hash(database):
|
||||||
|
return MOCK_DATABASE_HASHES[database]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('path,expected', [
|
||||||
|
('/does-not-exist', None),
|
||||||
|
# This should redirect
|
||||||
|
('/foo', routes.RouteResult(
|
||||||
|
None, None, '/foo-foohash'
|
||||||
|
)),
|
||||||
|
('/foo-bar-badhash', routes.RouteResult(
|
||||||
|
None, None, '/foo-bar-foobarhash'
|
||||||
|
)),
|
||||||
|
('/foo-foohash', routes.RouteResult(
|
||||||
|
DatabaseView, {'database': 'foo'}, None
|
||||||
|
)),
|
||||||
|
# Table views
|
||||||
|
('/foo/bar', routes.RouteResult(
|
||||||
|
None, None, '/foo-foohash/bar'
|
||||||
|
)),
|
||||||
|
('/foo/bad', routes.RouteResult(
|
||||||
|
None, None, '/foo-foohash/bad'
|
||||||
|
)),
|
||||||
|
('/foo-foohash/bad', None),
|
||||||
|
('/foo-foohash/bar', routes.RouteResult(
|
||||||
|
TableView, {'database': 'foo', 'table': 'bar'}, None
|
||||||
|
)),
|
||||||
|
] + [
|
||||||
|
('/-/{}'.format(filename), routes.RouteResult(
|
||||||
|
JsonDataView, {'filename': filename}, None
|
||||||
|
)) for filename in ('inspect', 'metadata', 'versions', 'plugins', 'config')
|
||||||
|
] + [
|
||||||
|
('/-/{}.json'.format(filename), routes.RouteResult(
|
||||||
|
JsonDataView, {'filename': filename, 'format': 'json'}, None
|
||||||
|
)) for filename in ('inspect', 'metadata', 'versions', 'plugins', 'config')
|
||||||
|
])
|
||||||
|
def test_routes(path, expected):
|
||||||
|
actual = routes.resolve(path, database_exists, table_exists, database_hash)
|
||||||
|
assert actual == expected
|
||||||
Loading…
Add table
Add a link
Reference in a new issue