Moved .execute() method from BaseView to Datasette class

Also introduced new Results() class with results.truncated, results.description, results.rows
This commit is contained in:
Simon Willison 2018-05-24 17:15:37 -07:00
commit 81df47e8d9
No known key found for this signature in database
GPG key ID: 17E2DEA2588B7F52
4 changed files with 105 additions and 90 deletions

View file

@ -2,7 +2,6 @@ import asyncio
import json
import re
import sqlite3
import threading
import time
import pint
@ -18,11 +17,9 @@ from datasette.utils import (
path_from_row_pks,
path_with_added_args,
path_with_ext,
sqlite_timelimit,
to_css_class
)
connections = threading.local()
ureg = pint.UnitRegistry()
HASH_LENGTH = 7
@ -128,68 +125,6 @@ class BaseView(RenderMixin):
return name, expected, None
async def execute(
self,
db_name,
sql,
params=None,
truncate=False,
custom_time_limit=None,
page_size=None,
):
"""Executes sql against db_name in a thread"""
page_size = page_size or self.page_size
def sql_operation_in_thread():
conn = getattr(connections, db_name, None)
if not conn:
info = self.ds.inspect()[db_name]
conn = sqlite3.connect(
"file:{}?immutable=1".format(info["file"]),
uri=True,
check_same_thread=False,
)
self.ds.prepare_connection(conn)
setattr(connections, db_name, conn)
time_limit_ms = self.ds.sql_time_limit_ms
if custom_time_limit and custom_time_limit < self.ds.sql_time_limit_ms:
time_limit_ms = custom_time_limit
with sqlite_timelimit(conn, time_limit_ms):
try:
cursor = conn.cursor()
cursor.execute(sql, params or {})
max_returned_rows = self.max_returned_rows
if max_returned_rows == page_size:
max_returned_rows += 1
if max_returned_rows and truncate:
rows = cursor.fetchmany(max_returned_rows + 1)
truncated = len(rows) > max_returned_rows
rows = rows[:max_returned_rows]
else:
rows = cursor.fetchall()
truncated = False
except sqlite3.OperationalError as e:
if e.args == ('interrupted',):
raise InterruptedError(e)
print(
"ERROR: conn={}, sql = {}, params = {}: {}".format(
conn, repr(sql), params, e
)
)
raise
if truncate:
return rows, truncated, cursor.description
else:
return rows
return await asyncio.get_event_loop().run_in_executor(
self.executor, sql_operation_in_thread
)
def get_templates(self, database, table=None):
assert NotImplemented
@ -348,10 +283,10 @@ class BaseView(RenderMixin):
extra_args = {}
if params.get("_timelimit"):
extra_args["custom_time_limit"] = int(params["_timelimit"])
rows, truncated, description = await self.execute(
results = await self.ds.execute(
name, sql, params, truncate=True, **extra_args
)
columns = [r[0] for r in description]
columns = [r[0] for r in results.description]
templates = ["query-{}.html".format(to_css_class(name)), "query.html"]
if canned_query:
@ -364,8 +299,8 @@ class BaseView(RenderMixin):
return {
"database": name,
"rows": rows,
"truncated": truncated,
"rows": results.rows,
"truncated": results.truncated,
"columns": columns,
"query": {"sql": sql, "params": params},
}, {