Skip to content

Commit

Permalink
Upgrade to Datasette 0.44+ - closes #8
Browse files Browse the repository at this point in the history
- Removes Starlette and asgi-csrf dependencies
- Now uses register_routes() plugin hook
  • Loading branch information
simonw committed Jul 6, 2020
1 parent 50e1957 commit 9729957
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 210 deletions.
142 changes: 129 additions & 13 deletions datasette_edit_tables/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,133 @@
from datasette import hookimpl
from .app import edit_tables_app
from datasette.utils.asgi import Response, NotFound
from urllib.parse import quote_plus
import sqlite_utils


@hookimpl
def asgi_wrapper(datasette):
def wrap_with_configure_fts(app):
async def wrapped_app(scope, receive, send):
path = scope["path"]
if path == "/-/edit-tables" or path.startswith("/-/edit-tables/"):
await (edit_tables_app(datasette))(scope, receive, send)
else:
await app(scope, receive, send)

return wrapped_app

return wrap_with_configure_fts
def register_routes():
return [
(r"^/-/edit-tables$", edit_tables_index),
(r"^/-/edit-tables/(?P<database>[^/]+)$", edit_tables_database),
(r"^/-/edit-tables/(?P<database>[^/]+)/(?P<table>[^/]+)$", edit_tables_table),
]


def get_databases(datasette):
return [db for db in datasette.databases.values() if db.is_mutable]


async def edit_tables_index(datasette, request):
databases = get_databases(datasette)
if 1 == len(databases):
return Response.redirect(
"/-/edit-tables/{}".format(quote_plus(databases[0].name))
)
return Response.html(
await datasette.render_template(
"edit_tables_index.html", {"databases": databases}, request=request
)
)


async def edit_tables_database(request, datasette):
databases = get_databases(datasette)
database_name = request.url_vars["database"]
just_these_tables = set(request.args.getlist("table"))
try:
database = [db for db in databases if db.name == database_name][0]
except IndexError:
raise NotFound("Database not found")
tables = []
hidden_tables = set(await database.hidden_table_names())
for table_name in await database.table_names():
if just_these_tables and table_name not in just_these_tables:
continue
if table_name in hidden_tables:
continue

def get_columns(conn):
return [
{"name": column, "type": dtype}
for column, dtype in sqlite_utils.Database(conn)[
table_name
].columns_dict.items()
]

columns = await database.execute_write_fn(get_columns, block=True)
tables.append(
{"name": table_name, "columns": columns,}
)
return Response.html(
await datasette.render_template(
"edit_tables_database.html",
{"database": database, "tables": tables,},
request=request,
)
)


async def edit_tables_table(request, datasette):
table = request.url_vars["table"]
databases = get_databases(datasette)
database_name = request.url_vars["database"]
try:
database = [db for db in databases if db.name == database_name][0]
except IndexError:
raise NotFound("Database not found")
if not await database.table_exists(table):
raise NotFound("Table not found")

if request.method == "POST":
formdata = await request.post_vars()
if "delete_table" in formdata:
return await delete_table(datasette, database, table)
elif "add_column" in formdata:
return await add_column(datasette, database, table, formdata)
else:
return Response.html("Unknown operation", status=400)

def get_columns(conn):
return [
{"name": column, "type": dtype}
for column, dtype in sqlite_utils.Database(conn)[table].columns_dict.items()
]

columns = await database.execute_fn(get_columns)

return Response.html(
await datasette.render_template(
"edit_tables_table.html",
{"database": database, "table": table, "columns": columns,},
request=request,
)
)


async def delete_table(datasette, database, table):
def do_delete_table(conn):
db = sqlite_utils.Database(conn)
db[table].disable_fts()
db[table].drop()
db.vacuum()

await datasette.databases[database.name].execute_write_fn(
do_delete_table, block=True
)

return Response.redirect("/{}".format(quote_plus(database.name)))


async def add_column(datasette, database, table, formdata):
name = formdata["name"]
type = formdata["type"]

def do_add_column(conn):
db = sqlite_utils.Database(conn)
db[table].add_column(name, type)

await datasette.databases[database.name].execute_write_fn(do_add_column, block=True)

return Response.redirect(
"/{}/{}".format(quote_plus(database.name), quote_plus(table))
)
179 changes: 0 additions & 179 deletions datasette_edit_tables/app.py

This file was deleted.

19 changes: 14 additions & 5 deletions datasette_edit_tables/templates/edit_tables_table.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
{% block title %}Edit table {{ table }} in {{ database.name }}{% endblock %}

{% block extra_head %}

<style>
select {
border: 1px solid #ccc;
border-radius: 3px;
padding: 9px 4px;
display: inline-block;
font-size: 1em;
font-family: Helvetica, sans-serif;
}
</style>
{% endblock %}

{% block nav %}
Expand All @@ -19,17 +28,17 @@ <h1>Edit table {{ table }} in {{ database.name }}</h1>
<h2>Columns</h2>
<ul>
{% for column in columns %}
<li>{{ column.name }} - {{ column.type.__name__ }}</li>
<li>{{ column.name }} - {{ column.type.__name__ }}</li>
{% endfor %}
</ul>

<h2>Add a column</h2>

<form action="/-/edit-tables/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken }}">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="hidden" name="add_column" value="1">
<p><label>Name <input type="text" name="name"></label>
<label>Type <select name="type">
<label>Column type <select name="type">
<option value="text">text</option>
<option value="integer">integer number</option>
<option value="float">floating point number</option>
Expand All @@ -41,7 +50,7 @@ <h2>Add a column</h2>
<h2>Delete table</h2>

<form action="/-/edit-tables/{{ database.name|quote_plus }}/{{ table|quote_plus }}" method="post">
<input type="hidden" name="csrftoken" value="{{ csrftoken }}">
<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">
<input type="hidden" name="delete_table" value="1">
<input type="submit" value="Delete this table">
</form>
Expand Down
8 changes: 1 addition & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,7 @@ def get_long_description():
version=VERSION,
packages=["datasette_edit_tables"],
entry_points={"datasette": ["edit_tables = datasette_edit_tables"]},
install_requires=[
"datasette",
"sqlite-utils~=2.4.2",
"starlette",
"python-multipart",
"asgi-csrf~=0.2.2a0",
],
install_requires=["datasette>=0.44", "sqlite-utils>=2.4.2",],
extras_require={"test": ["pytest", "pytest-asyncio", "httpx"]},
tests_require=["datasette-edit-tables[test]"],
package_data={"datasette_edit_tables": ["templates/*.html"]},
Expand Down
Loading

0 comments on commit 9729957

Please sign in to comment.