mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
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:
parent
28a52fcffb
commit
81df47e8d9
4 changed files with 105 additions and 90 deletions
|
|
@ -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},
|
||||
}, {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue