home / github

Menu
  • Search all tables
  • GraphQL API

issue_comments

Table actions
  • GraphQL API for issue_comments

4 rows where issue = 789336592 sorted by updated_at descending

✖
✖

✎ View and edit SQL

This data as json, CSV (advanced)

Suggested facets: created_at (date), updated_at (date)

user 1

  • simonw 4

issue 1

  • view_name = "query" for the query page · 4 ✖

author_association 1

  • OWNER 4
id html_url issue_url node_id user created_at updated_at ▲ author_association body reactions issue performed_via_github_app
766535046 https://github.com/simonw/datasette/issues/1195#issuecomment-766535046 https://api.github.com/repos/simonw/datasette/issues/1195 MDEyOklzc3VlQ29tbWVudDc2NjUzNTA0Ng== simonw 9599 2021-01-25T04:40:08Z 2021-01-25T04:40:08Z OWNER

Also: should the view name really be the same for both of these pages?

  • https://latest.datasette.io/fixtures?sql=select+*+from+facetable
  • https://latest.datasette.io/fixtures/neighborhood_search

Where one of them is a canned query and the other is an arbitrary query?

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
view_name = "query" for the query page 789336592  
766534748 https://github.com/simonw/datasette/issues/1195#issuecomment-766534748 https://api.github.com/repos/simonw/datasette/issues/1195 MDEyOklzc3VlQ29tbWVudDc2NjUzNDc0OA== simonw 9599 2021-01-25T04:38:56Z 2021-01-25T04:38:56Z OWNER

Here's a diff showing how far I got before I abandoned this particular effort:

```diff diff --git a/datasette/views/base.py b/datasette/views/base.py index a21b929..04e4aa9 100644 --- a/datasette/views/base.py +++ b/datasette/views/base.py @@ -120,7 +120,7 @@ class BaseView: handler = getattr(self, request.method.lower(), None) return await handler(request, args, *kwargs)

  • async def render(self, templates, request, context=None):
  • async def render(self, templates, request, context=None, view_name=None): context = context or {} template = self.ds.jinja_env.select_template(templates) template_context = { @@ -135,7 +135,7 @@ class BaseView: } return Response.html( await self.ds.render_template(
  • template, template_context, request=request, view_name=self.name
  • template, template_context, request=request, view_name=view_name ) )

@@ -155,7 +155,7 @@ class BaseView:

class DataView(BaseView): - name = "" + view_name = "no-view-name" re_named_parameter = re.compile(":([a-zA-Z0-9_]+)")

 async def options(self, request, *args, **kwargs):

@@ -414,6 +414,10 @@ class DataView(BaseView): args["table"] = urllib.parse.unquote_plus(args["table"]) return _format, args

  • async def get_view_name(self, request, database, hash, **kwargs):
  • Defaults to self.view_name, but can be over-ridden by subclasses

  • return self.view_name + async def view_get(self, request, database, hash, correct_hash_provided, **kwargs): _format, kwargs = await self.get_format(request, database, kwargs)

@@ -424,6 +428,8 @@ class DataView(BaseView): # HTML views default to expanding all foreign key labels kwargs["default_labels"] = True

  • view_name = await self.get_view_name(request, database, hash, **kwargs) + extra_template_data = {} start = time.perf_counter() status_code = 200 @@ -489,7 +495,7 @@ class DataView(BaseView): database=database, table=data.get("table"), request=request,
  • view_name=self.name,
  • view_name=view_name, # These will be deprecated in Datasette 1.0: args=request.args, data=data, @@ -533,7 +539,7 @@ class DataView(BaseView): database=database, table=data.get("table"), request=request,
  • view_name=self.name,
  • view_name=view_name, ) it_can_render = await await_me_maybe(it_can_render) if it_can_render: @@ -565,7 +571,7 @@ class DataView(BaseView): } if "metadata" not in context: context["metadata"] = self.ds.metadata
  • r = await self.render(templates, request=request, context=context)
  • r = await self.render(templates, request=request, context=context, view_name=view_name) r.status = status_code
     ttl = request.args.get("_ttl", None)
    

    diff --git a/datasette/views/database.py b/datasette/views/database.py index f6fd579..e425213 100644 --- a/datasette/views/database.py +++ b/datasette/views/database.py @@ -23,7 +23,11 @@ from .base import DatasetteError, DataView

class DatabaseView(DataView): - name = "database" + async def get_view_name(self, request, db_name, table_and_format): + if request.args.get("sql"): + return "query" + else: + return "database"

 async def data(self, request, database, hash, default_labels=False, _size=None):
     await self.check_permissions(

@@ -145,7 +149,7 @@ class DatabaseView(DataView):

class DatabaseDownload(DataView): - name = "database_download" + view_name = "database_download"

 async def view_get(self, request, database, hash, correct_hash_present, **kwargs):
     await self.check_permissions(

diff --git a/datasette/views/index.py b/datasette/views/index.py index b6b8cbe..d750e3d 100644 --- a/datasette/views/index.py +++ b/datasette/views/index.py @@ -16,7 +16,7 @@ COUNT_DB_SIZE_LIMIT = 100 * 1024 * 1024

class IndexView(BaseView): - name = "index" + view_name = "index"

 async def get(self, request, as_format):
     await self.check_permission(request, "view-instance")

diff --git a/datasette/views/special.py b/datasette/views/special.py index 9750dd0..dbd1e00 100644 --- a/datasette/views/special.py +++ b/datasette/views/special.py @@ -6,7 +6,7 @@ import secrets

class JsonDataView(BaseView): - name = "json_data" + view_name = "json_data"

 def __init__(self, datasette, filename, data_callback, needs_request=False):
     self.ds = datasette

@@ -42,7 +42,7 @@ class JsonDataView(BaseView):

class PatternPortfolioView(BaseView): - name = "patterns" + view_name = "patterns"

 async def get(self, request):
     await self.check_permission(request, "view-instance")

@@ -50,7 +50,7 @@ class PatternPortfolioView(BaseView):

class AuthTokenView(BaseView): - name = "auth_token" + view_name = "auth_token"

 async def get(self, request):
     token = request.args.get("token") or ""

@@ -68,7 +68,7 @@ class AuthTokenView(BaseView):

class LogoutView(BaseView): - name = "logout" + view_name = "logout"

 async def get(self, request):
     if not request.actor:

@@ -87,7 +87,7 @@ class LogoutView(BaseView):

class PermissionsDebugView(BaseView): - name = "permissions_debug" + view_name = "permissions_debug"

 async def get(self, request):
     await self.check_permission(request, "view-instance")

@@ -102,7 +102,7 @@ class PermissionsDebugView(BaseView):

class AllowDebugView(BaseView): - name = "allow_debug" + view_name = "allow_debug"

 async def get(self, request):
     errors = []

@@ -136,7 +136,7 @@ class AllowDebugView(BaseView):

class MessagesDebugView(BaseView): - name = "messages_debug" + view_name = "messages_debug"

 async def get(self, request):
     await self.check_permission(request, "view-instance")

diff --git a/datasette/views/table.py b/datasette/views/table.py index 0a3504b..45d298a 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -257,7 +257,16 @@ class RowTableShared(DataView):

class TableView(RowTableShared): - name = "table" + view_name = "table" + + async def get_view_name(self, request, db_name, table_and_format): + canned_query = await self.ds.get_canned_query( + db_name, table_and_format, request.actor + ) + if canned_query: + return "query" + else: + return "table"

 async def post(self, request, db_name, table_and_format):
     # Handle POST to a canned query

@@ -923,7 +932,7 @@ async def _sql_params_pks(db, table, pk_values):

class RowView(RowTableShared): - name = "row" + view_name = "row"

 async def data(self, request, database, hash, table, pk_path, default_labels=False):
     await self.check_permissions(

diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 715c7c1..7ce2b1b 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -252,7 +252,7 @@ def test_plugin_config_file(app_client): }, ), ( - "/fixtures/", + "/fixtures", { "template": "database.html", "database": "fixtures", @@ -285,6 +285,38 @@ def test_plugin_config_file(app_client): ], }, ), + ( + "/fixtures?sql=select+1+as+one", + { + "template": "query.html", + "database": "fixtures", + "table": None, + "config": {"depth": "database"}, + "view_name": "query", + "request_path": "/fixtures", + "added": 15, + "columns": [ + "one", + ], + }, + ), + ( + "/fixtures/neighborhood_search", + { + "template": "query.html", + "database": "fixtures", + "table": None, + "config": {"depth": "database"}, + "view_name": "query", + "request_path": "/fixtures/neighborhood_search", + "added": 15, + "columns": [ + "neighborhood", + "name", + "state", + ], + }, + ), ], ) def test_hook_extra_body_script(app_client, path, expected_extra_body_script): ```

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
view_name = "query" for the query page 789336592  
766534634 https://github.com/simonw/datasette/issues/1195#issuecomment-766534634 https://api.github.com/repos/simonw/datasette/issues/1195 MDEyOklzc3VlQ29tbWVudDc2NjUzNDYzNA== simonw 9599 2021-01-25T04:38:30Z 2021-01-25T04:38:30Z OWNER

This has proved surprisingly difficult to implement, due to the weird way the QueryView is actually called. The class itself isn't used like other view classes - instead, the .data() methods of both DatabaseView and TableView dispatch out to QueryView.data() when they need to:

https://github.com/simonw/datasette/blob/07e163561592c743e4117f72102fcd350a600909/datasette/views/table.py#L259-L270

https://github.com/simonw/datasette/blob/07e163561592c743e4117f72102fcd350a600909/datasette/views/table.py#L290-L294

https://github.com/simonw/datasette/blob/07e163561592c743e4117f72102fcd350a600909/datasette/views/database.py#L39-L44

It turns out this is a bad pattern because it makes changes like this one WAY harder than they should be.

I think I should clean this up as part of #878.

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
view_name = "query" for the query page 789336592  
763108730 https://github.com/simonw/datasette/issues/1195#issuecomment-763108730 https://api.github.com/repos/simonw/datasette/issues/1195 MDEyOklzc3VlQ29tbWVudDc2MzEwODczMA== simonw 9599 2021-01-19T20:22:37Z 2021-01-19T20:22:37Z OWNER

I can use this test: https://github.com/simonw/datasette/blob/c38c42948cbfddd587729413fd6082ba352eaece/tests/test_plugins.py#L238-L294

{
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
view_name = "query" for the query page 789336592  

Advanced export

JSON shape: default, array, newline-delimited, object

CSV options:

CREATE TABLE [issue_comments] (
   [html_url] TEXT,
   [issue_url] TEXT,
   [id] INTEGER PRIMARY KEY,
   [node_id] TEXT,
   [user] INTEGER REFERENCES [users]([id]),
   [created_at] TEXT,
   [updated_at] TEXT,
   [author_association] TEXT,
   [body] TEXT,
   [reactions] TEXT,
   [issue] INTEGER REFERENCES [issues]([id])
, [performed_via_github_app] TEXT);
CREATE INDEX [idx_issue_comments_issue]
                ON [issue_comments] ([issue]);
CREATE INDEX [idx_issue_comments_user]
                ON [issue_comments] ([user]);
Powered by Datasette · Queries took 17.392ms · About: github-to-sqlite
  • Sort ascending
  • Sort descending
  • Facet by this
  • Hide this column
  • Show all columns
  • Show not-blank rows