mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Basic writable canned queries
Refs #698. First working version of this feature. * request.post_vars() no longer discards empty values
This commit is contained in:
parent
0934844c0b
commit
aa82d03704
6 changed files with 256 additions and 19 deletions
|
|
@ -14,7 +14,7 @@ import string
|
|||
import tempfile
|
||||
import textwrap
|
||||
import time
|
||||
from urllib.parse import unquote, quote
|
||||
from urllib.parse import unquote, quote, urlencode
|
||||
|
||||
|
||||
# This temp file is used by one of the plugin config tests
|
||||
|
|
@ -54,10 +54,26 @@ class TestClient:
|
|||
async def get(
|
||||
self, path, allow_redirects=True, redirect_count=0, method="GET", cookies=None
|
||||
):
|
||||
return await self._get(path, allow_redirects, redirect_count, method, cookies)
|
||||
return await self._request(
|
||||
path, allow_redirects, redirect_count, method, cookies
|
||||
)
|
||||
|
||||
async def _get(
|
||||
self, path, allow_redirects=True, redirect_count=0, method="GET", cookies=None
|
||||
@async_to_sync
|
||||
async def post(
|
||||
self, path, post_data=None, allow_redirects=True, redirect_count=0, cookies=None
|
||||
):
|
||||
return await self._request(
|
||||
path, allow_redirects, redirect_count, "POST", cookies, post_data
|
||||
)
|
||||
|
||||
async def _request(
|
||||
self,
|
||||
path,
|
||||
allow_redirects=True,
|
||||
redirect_count=0,
|
||||
method="GET",
|
||||
cookies=None,
|
||||
post_data=None,
|
||||
):
|
||||
query_string = b""
|
||||
if "?" in path:
|
||||
|
|
@ -83,7 +99,13 @@ class TestClient:
|
|||
"headers": headers,
|
||||
}
|
||||
instance = ApplicationCommunicator(self.asgi_app, scope)
|
||||
await instance.send_input({"type": "http.request"})
|
||||
|
||||
if post_data:
|
||||
body = urlencode(post_data, doseq=True).encode("utf-8")
|
||||
await instance.send_input({"type": "http.request", "body": body})
|
||||
else:
|
||||
await instance.send_input({"type": "http.request"})
|
||||
|
||||
# First message back should be response.start with headers and status
|
||||
messages = []
|
||||
start = await instance.receive_output(2)
|
||||
|
|
@ -110,7 +132,7 @@ class TestClient:
|
|||
redirect_count, self.max_redirects
|
||||
)
|
||||
location = response.headers["Location"]
|
||||
return await self._get(
|
||||
return await self._request(
|
||||
location, allow_redirects=True, redirect_count=redirect_count + 1
|
||||
)
|
||||
return response
|
||||
|
|
@ -128,6 +150,7 @@ def make_app_client(
|
|||
inspect_data=None,
|
||||
static_mounts=None,
|
||||
template_dir=None,
|
||||
metadata=None,
|
||||
):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
filepath = os.path.join(tmpdir, filename)
|
||||
|
|
@ -161,7 +184,7 @@ def make_app_client(
|
|||
immutables=immutables,
|
||||
memory=memory,
|
||||
cors=cors,
|
||||
metadata=METADATA,
|
||||
metadata=metadata or METADATA,
|
||||
plugins_dir=PLUGINS_DIR,
|
||||
config=config,
|
||||
inspect_data=inspect_data,
|
||||
|
|
|
|||
88
tests/test_canned_write.py
Normal file
88
tests/test_canned_write.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import pytest
|
||||
from .fixtures import make_app_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def canned_write_client():
|
||||
for client in make_app_client(
|
||||
extra_databases={"data.db": "create table names (name text)"},
|
||||
metadata={
|
||||
"databases": {
|
||||
"data": {
|
||||
"queries": {
|
||||
"add_name": {
|
||||
"sql": "insert into names (name) values (:name)",
|
||||
"write": True,
|
||||
"on_success_redirect": "/data/add_name?success",
|
||||
},
|
||||
"add_name_specify_id": {
|
||||
"sql": "insert into names (rowid, name) values (:rowid, :name)",
|
||||
"write": True,
|
||||
"on_error_redirect": "/data/add_name_specify_id?error",
|
||||
},
|
||||
"delete_name": {
|
||||
"sql": "delete from names where rowid = :rowid",
|
||||
"write": True,
|
||||
"on_success_message": "Name deleted",
|
||||
},
|
||||
"update_name": {
|
||||
"sql": "update names set name = :name where rowid = :rowid",
|
||||
"params": ["rowid", "name"],
|
||||
"write": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
):
|
||||
yield client
|
||||
|
||||
|
||||
def test_insert(canned_write_client):
|
||||
response = canned_write_client.post(
|
||||
"/data/add_name", {"name": "Hello"}, allow_redirects=False
|
||||
)
|
||||
assert 302 == response.status
|
||||
assert "/data/add_name?success" == response.headers["Location"]
|
||||
messages = canned_write_client.ds.unsign(
|
||||
response.cookies["ds_messages"], "messages"
|
||||
)
|
||||
assert [["Query executed, 1 row affected", 1]] == messages
|
||||
|
||||
|
||||
def test_custom_success_message(canned_write_client):
|
||||
response = canned_write_client.post(
|
||||
"/data/delete_name", {"rowid": 1}, allow_redirects=False
|
||||
)
|
||||
assert 302 == response.status
|
||||
messages = canned_write_client.ds.unsign(
|
||||
response.cookies["ds_messages"], "messages"
|
||||
)
|
||||
assert [["Name deleted", 1]] == messages
|
||||
|
||||
|
||||
def test_insert_error(canned_write_client):
|
||||
canned_write_client.post("/data/add_name", {"name": "Hello"})
|
||||
response = canned_write_client.post(
|
||||
"/data/add_name_specify_id",
|
||||
{"rowid": 1, "name": "Should fail"},
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert 302 == response.status
|
||||
assert "/data/add_name_specify_id?error" == response.headers["Location"]
|
||||
messages = canned_write_client.ds.unsign(
|
||||
response.cookies["ds_messages"], "messages"
|
||||
)
|
||||
assert [["UNIQUE constraint failed: names.rowid", 3]] == messages
|
||||
# How about with a custom error message?
|
||||
canned_write_client.ds._metadata["databases"]["data"]["queries"][
|
||||
"add_name_specify_id"
|
||||
]["on_error_message"] = "ERROR"
|
||||
response = canned_write_client.post(
|
||||
"/data/add_name_specify_id",
|
||||
{"rowid": 1, "name": "Should fail"},
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert [["ERROR", 3]] == canned_write_client.ds.unsign(
|
||||
response.cookies["ds_messages"], "messages"
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue