Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement canned queries against new query JSON work #2114

Closed
simonw opened this issue Jul 26, 2023 · 3 comments
Closed

Implement canned queries against new query JSON work #2114

simonw opened this issue Jul 26, 2023 · 3 comments

Comments

@simonw
Copy link
Owner

simonw commented Jul 26, 2023

@simonw
Copy link
Owner Author

simonw commented Jul 26, 2023

This is also where I'll bring back writable canned queries:

# Execute query - as write or as read
if write:
if request.method == "POST":
# If database is immutable, return an error
if not db.is_mutable:
raise Forbidden("Database is immutable")
body = await request.post_body()
body = body.decode("utf-8").strip()
if body.startswith("{") and body.endswith("}"):
params = json.loads(body)
# But we want key=value strings
for key, value in params.items():
params[key] = str(value)
else:
params = dict(parse_qsl(body, keep_blank_values=True))
# Should we return JSON?
should_return_json = (
request.headers.get("accept") == "application/json"
or request.args.get("_json")
or params.get("_json")
)
if canned_query:
params_for_query = MagicParameters(params, request, self.ds)
else:
params_for_query = params
ok = None
try:
cursor = await self.ds.databases[database].execute_write(
sql, params_for_query
)
message = metadata.get(
"on_success_message"
) or "Query executed, {} row{} affected".format(
cursor.rowcount, "" if cursor.rowcount == 1 else "s"
)
message_type = self.ds.INFO
redirect_url = metadata.get("on_success_redirect")
ok = True
except Exception as e:
message = metadata.get("on_error_message") or str(e)
message_type = self.ds.ERROR
redirect_url = metadata.get("on_error_redirect")
ok = False
if should_return_json:
return Response.json(
{
"ok": ok,
"message": message,
"redirect": redirect_url,
}
)
else:
self.ds.add_message(request, message, message_type)
return self.redirect(request, redirect_url or request.path)

@simonw
Copy link
Owner Author

simonw commented Aug 8, 2023

The tests for this are still passing:

pytest tests/test_canned_queries.py

Because I left in the old code:

async def table_view_traced(datasette, request):
from datasette.app import TableNotFound
try:
resolved = await datasette.resolve_table(request)
except TableNotFound as not_found:
# Was this actually a canned query?
canned_query = await datasette.get_canned_query(
not_found.database_name, not_found.table, request.actor
)
# If this is a canned query, not a table, then dispatch to QueryView instead
if canned_query:
if request.method == "POST":
return await CannedQueryView(datasette).post(request)
else:
return await CannedQueryView(datasette).get(request)

class CannedQueryView(DataView):
def __init__(self, datasette):
self.ds = datasette
async def post(self, request):
from datasette.app import TableNotFound
try:
await self.ds.resolve_table(request)
except TableNotFound as e:
# Was this actually a canned query?
canned_query = await self.ds.get_canned_query(
e.database_name, e.table, request.actor
)
if canned_query:
# Handle POST to a canned query
return await QueryView(self.ds).data(
request,
canned_query["sql"],
metadata=canned_query,
editable=False,
canned_query=e.table,
named_parameters=canned_query.get("params"),
write=bool(canned_query.get("write")),
)
return Response.text("Method not allowed", status=405)

@simonw
Copy link
Owner Author

simonw commented Aug 9, 2023

I decided to figure out where the _size= parameter here comes from:

class QueryView(DataView):
async def data(
self,
request,
sql,
editable=True,
canned_query=None,
metadata=None,
_size=None,
named_parameters=None,
write=False,
default_labels=None,
):

It took some spelunking, but it looks like I added that five years ago as part of CSV streaming in fc3660c

It's there purely to allow CSV streaming to set _size="max".

And since CSV streaming is still just a table thing, not a query thing, I can drop it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant