kopia lustrzana https://github.com/simonw/datasette
rodzic
b07312c2b3
commit
07e208cc6d
|
@ -461,104 +461,3 @@ class DataView(BaseView):
|
||||||
if self.ds.cors:
|
if self.ds.cors:
|
||||||
response.headers["Access-Control-Allow-Origin"] = "*"
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
async def custom_sql(
|
|
||||||
self,
|
|
||||||
request,
|
|
||||||
database,
|
|
||||||
hash,
|
|
||||||
sql,
|
|
||||||
editable=True,
|
|
||||||
canned_query=None,
|
|
||||||
metadata=None,
|
|
||||||
_size=None,
|
|
||||||
):
|
|
||||||
params = request.raw_args
|
|
||||||
if "sql" in params:
|
|
||||||
params.pop("sql")
|
|
||||||
if "_shape" in params:
|
|
||||||
params.pop("_shape")
|
|
||||||
# Extract any :named parameters
|
|
||||||
named_parameters = self.re_named_parameter.findall(sql)
|
|
||||||
named_parameter_values = {
|
|
||||||
named_parameter: params.get(named_parameter) or ""
|
|
||||||
for named_parameter in named_parameters
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set to blank string if missing from params
|
|
||||||
for named_parameter in named_parameters:
|
|
||||||
if named_parameter not in params:
|
|
||||||
params[named_parameter] = ""
|
|
||||||
|
|
||||||
extra_args = {}
|
|
||||||
if params.get("_timelimit"):
|
|
||||||
extra_args["custom_time_limit"] = int(params["_timelimit"])
|
|
||||||
if _size:
|
|
||||||
extra_args["page_size"] = _size
|
|
||||||
results = await self.ds.execute(
|
|
||||||
database, sql, params, truncate=True, **extra_args
|
|
||||||
)
|
|
||||||
columns = [r[0] for r in results.description]
|
|
||||||
|
|
||||||
templates = ["query-{}.html".format(to_css_class(database)), "query.html"]
|
|
||||||
if canned_query:
|
|
||||||
templates.insert(
|
|
||||||
0,
|
|
||||||
"query-{}-{}.html".format(
|
|
||||||
to_css_class(database), to_css_class(canned_query)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
async def extra_template():
|
|
||||||
display_rows = []
|
|
||||||
for row in results.rows:
|
|
||||||
display_row = []
|
|
||||||
for column, value in zip(results.columns, row):
|
|
||||||
display_value = value
|
|
||||||
# Let the plugins have a go
|
|
||||||
# pylint: disable=no-member
|
|
||||||
plugin_value = pm.hook.render_cell(
|
|
||||||
value=value,
|
|
||||||
column=column,
|
|
||||||
table=None,
|
|
||||||
database=database,
|
|
||||||
datasette=self.ds,
|
|
||||||
)
|
|
||||||
if plugin_value is not None:
|
|
||||||
display_value = plugin_value
|
|
||||||
else:
|
|
||||||
if value in ("", None):
|
|
||||||
display_value = jinja2.Markup(" ")
|
|
||||||
elif is_url(str(display_value).strip()):
|
|
||||||
display_value = jinja2.Markup(
|
|
||||||
'<a href="{url}">{url}</a>'.format(
|
|
||||||
url=jinja2.escape(value.strip())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
display_row.append(display_value)
|
|
||||||
display_rows.append(display_row)
|
|
||||||
return {
|
|
||||||
"display_rows": display_rows,
|
|
||||||
"custom_sql": True,
|
|
||||||
"named_parameter_values": named_parameter_values,
|
|
||||||
"editable": editable,
|
|
||||||
"canned_query": canned_query,
|
|
||||||
"metadata": metadata,
|
|
||||||
"config": self.ds.config_dict(),
|
|
||||||
"request": request,
|
|
||||||
"path_with_added_args": path_with_added_args,
|
|
||||||
"path_with_removed_args": path_with_removed_args,
|
|
||||||
"hide_sql": "_hide_sql" in params,
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
{
|
|
||||||
"database": database,
|
|
||||||
"rows": results.rows,
|
|
||||||
"truncated": results.truncated,
|
|
||||||
"columns": columns,
|
|
||||||
"query": {"sql": sql, "params": params},
|
|
||||||
},
|
|
||||||
extra_template,
|
|
||||||
templates,
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import os
|
import os
|
||||||
|
import jinja2
|
||||||
|
|
||||||
from datasette.utils import to_css_class, validate_sql_select
|
from datasette.utils import (
|
||||||
|
to_css_class,
|
||||||
|
validate_sql_select,
|
||||||
|
is_url,
|
||||||
|
path_with_added_args,
|
||||||
|
path_with_removed_args,
|
||||||
|
)
|
||||||
from datasette.utils.asgi import AsgiFileDownload
|
from datasette.utils.asgi import AsgiFileDownload
|
||||||
|
from datasette.plugins import pm
|
||||||
|
|
||||||
from .base import DatasetteError, DataView
|
from .base import DatasetteError, DataView
|
||||||
|
|
||||||
|
@ -18,7 +26,7 @@ class DatabaseView(DataView):
|
||||||
raise DatasetteError("sql= is not allowed", status=400)
|
raise DatasetteError("sql= is not allowed", status=400)
|
||||||
sql = request.raw_args.pop("sql")
|
sql = request.raw_args.pop("sql")
|
||||||
validate_sql_select(sql)
|
validate_sql_select(sql)
|
||||||
return await self.custom_sql(
|
return await QueryView(self.ds).data(
|
||||||
request, database, hash, sql, _size=_size, metadata=metadata
|
request, database, hash, sql, _size=_size, metadata=metadata
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -85,3 +93,108 @@ class DatabaseDownload(DataView):
|
||||||
filename=os.path.basename(filepath),
|
filename=os.path.basename(filepath),
|
||||||
content_type="application/octet-stream",
|
content_type="application/octet-stream",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class QueryView(DataView):
|
||||||
|
name = "query"
|
||||||
|
|
||||||
|
async def data(
|
||||||
|
self,
|
||||||
|
request,
|
||||||
|
database,
|
||||||
|
hash,
|
||||||
|
sql,
|
||||||
|
editable=True,
|
||||||
|
canned_query=None,
|
||||||
|
metadata=None,
|
||||||
|
_size=None,
|
||||||
|
):
|
||||||
|
params = request.raw_args
|
||||||
|
if "sql" in params:
|
||||||
|
params.pop("sql")
|
||||||
|
if "_shape" in params:
|
||||||
|
params.pop("_shape")
|
||||||
|
# Extract any :named parameters
|
||||||
|
named_parameters = self.re_named_parameter.findall(sql)
|
||||||
|
named_parameter_values = {
|
||||||
|
named_parameter: params.get(named_parameter) or ""
|
||||||
|
for named_parameter in named_parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set to blank string if missing from params
|
||||||
|
for named_parameter in named_parameters:
|
||||||
|
if named_parameter not in params:
|
||||||
|
params[named_parameter] = ""
|
||||||
|
|
||||||
|
extra_args = {}
|
||||||
|
if params.get("_timelimit"):
|
||||||
|
extra_args["custom_time_limit"] = int(params["_timelimit"])
|
||||||
|
if _size:
|
||||||
|
extra_args["page_size"] = _size
|
||||||
|
results = await self.ds.execute(
|
||||||
|
database, sql, params, truncate=True, **extra_args
|
||||||
|
)
|
||||||
|
columns = [r[0] for r in results.description]
|
||||||
|
|
||||||
|
templates = ["query-{}.html".format(to_css_class(database)), "query.html"]
|
||||||
|
if canned_query:
|
||||||
|
templates.insert(
|
||||||
|
0,
|
||||||
|
"query-{}-{}.html".format(
|
||||||
|
to_css_class(database), to_css_class(canned_query)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def extra_template():
|
||||||
|
display_rows = []
|
||||||
|
for row in results.rows:
|
||||||
|
display_row = []
|
||||||
|
for column, value in zip(results.columns, row):
|
||||||
|
display_value = value
|
||||||
|
# Let the plugins have a go
|
||||||
|
# pylint: disable=no-member
|
||||||
|
plugin_value = pm.hook.render_cell(
|
||||||
|
value=value,
|
||||||
|
column=column,
|
||||||
|
table=None,
|
||||||
|
database=database,
|
||||||
|
datasette=self.ds,
|
||||||
|
)
|
||||||
|
if plugin_value is not None:
|
||||||
|
display_value = plugin_value
|
||||||
|
else:
|
||||||
|
if value in ("", None):
|
||||||
|
display_value = jinja2.Markup(" ")
|
||||||
|
elif is_url(str(display_value).strip()):
|
||||||
|
display_value = jinja2.Markup(
|
||||||
|
'<a href="{url}">{url}</a>'.format(
|
||||||
|
url=jinja2.escape(value.strip())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
display_row.append(display_value)
|
||||||
|
display_rows.append(display_row)
|
||||||
|
return {
|
||||||
|
"display_rows": display_rows,
|
||||||
|
"custom_sql": True,
|
||||||
|
"named_parameter_values": named_parameter_values,
|
||||||
|
"editable": editable,
|
||||||
|
"canned_query": canned_query,
|
||||||
|
"metadata": metadata,
|
||||||
|
"config": self.ds.config_dict(),
|
||||||
|
"request": request,
|
||||||
|
"path_with_added_args": path_with_added_args,
|
||||||
|
"path_with_removed_args": path_with_removed_args,
|
||||||
|
"hide_sql": "_hide_sql" in params,
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
{
|
||||||
|
"database": database,
|
||||||
|
"rows": results.rows,
|
||||||
|
"truncated": results.truncated,
|
||||||
|
"columns": columns,
|
||||||
|
"query": {"sql": sql, "params": params},
|
||||||
|
},
|
||||||
|
extra_template,
|
||||||
|
templates,
|
||||||
|
)
|
||||||
|
|
|
@ -26,6 +26,7 @@ from datasette.utils import (
|
||||||
from datasette.utils.asgi import NotFound
|
from datasette.utils.asgi import NotFound
|
||||||
from datasette.filters import Filters
|
from datasette.filters import Filters
|
||||||
from .base import DataView, DatasetteError, ureg
|
from .base import DataView, DatasetteError, ureg
|
||||||
|
from .database import QueryView
|
||||||
|
|
||||||
LINK_WITH_LABEL = (
|
LINK_WITH_LABEL = (
|
||||||
'<a href="{base_url}{database}/{table}/{link_id}">{label}</a> <em>{id}</em>'
|
'<a href="{base_url}{database}/{table}/{link_id}">{label}</a> <em>{id}</em>'
|
||||||
|
@ -221,8 +222,8 @@ class TableView(RowTableShared):
|
||||||
_size=None,
|
_size=None,
|
||||||
):
|
):
|
||||||
canned_query = self.ds.get_canned_query(database, table)
|
canned_query = self.ds.get_canned_query(database, table)
|
||||||
if canned_query is not None:
|
if canned_query:
|
||||||
return await self.custom_sql(
|
return await QueryView(self.ds).data(
|
||||||
request,
|
request,
|
||||||
database,
|
database,
|
||||||
hash,
|
hash,
|
||||||
|
@ -231,6 +232,7 @@ class TableView(RowTableShared):
|
||||||
editable=False,
|
editable=False,
|
||||||
canned_query=table,
|
canned_query=table,
|
||||||
)
|
)
|
||||||
|
|
||||||
db = self.ds.databases[database]
|
db = self.ds.databases[database]
|
||||||
is_view = bool(await db.get_view_definition(table))
|
is_view = bool(await db.get_view_definition(table))
|
||||||
table_exists = bool(await db.table_exists(table))
|
table_exists = bool(await db.table_exists(table))
|
||||||
|
|
Ładowanie…
Reference in New Issue