From 3840070dddcaedd49595275cd12cbd5f27550e7f Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Tue, 5 Nov 2019 21:10:48 -0800 Subject: [PATCH 1/3] WIP col nocol - refs #615 --- datasette/views/table.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/datasette/views/table.py b/datasette/views/table.py index 139ff80b..941e4bb4 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -63,6 +63,26 @@ class Row: class RowTableShared(DataView): + async def columns_to_select(self, db, table, request): + table_columns = await db.table_columns(table) + if "_col" in request.args and "_nocol" in request.args: + raise DatasetteError("Cannot use _col and _nocol at the same time") + if "_col" in request.args: + new_columns = [] + for column in request.args["_col"]: + if column not in table_columns: + raise DatasetteError("_col={} is an invalid column".format(column)) + new_columns.append(column) + return new_columns + elif "_nocol" in request.args: + # Return all columns EXCEPT these + bad_columns = [column for column in request.args["_nocol"] if column not in table_columns] + if bad_columns: + raise DatasetteError("_nocol={} - invalid columns".format(", ".join(bad_columns))) + return [column for column in table_columns if column not in request.args["_nocol"]] + else: + return table_columns + async def sortable_columns_for_table(self, database, table, use_rowid): db = self.ds.databases[database] table_metadata = self.ds.table_metadata(database, table) @@ -235,17 +255,18 @@ class TableView(RowTableShared): raise NotFound("Table not found: {}".format(table)) pks = await db.primary_keys(table) - table_columns = await db.table_columns(table) - select_columns = ", ".join(escape_sqlite(t) for t in table_columns) + # Take _col= and _nocol= into account + table_columns = await self.columns_to_select(db, table, request) + select_clause = ", ".join(escape_sqlite(t) for t in table_columns) use_rowid = not pks and not is_view if use_rowid: - select = "rowid, {}".format(select_columns) + select = "rowid, {}".format(select_clause) order_by = "rowid" order_by_pks = "rowid" else: - select = select_columns + select = select_clause order_by_pks = ", ".join([escape_sqlite(pk) for pk in pks]) order_by = order_by_pks @@ -598,7 +619,7 @@ class TableView(RowTableShared): facets_timed_out.extend(instance_facets_timed_out) # Figure out columns and rows for the query - columns = [r[0] for r in results.description] + columns = table_columns rows = list(results.rows) filter_columns = columns[:] @@ -626,6 +647,8 @@ class TableView(RowTableShared): column = fk["column"] if column not in columns_to_expand: continue + if column not in columns: + continue expanded_columns.append(column) # Gather the values column_index = columns.index(column) From aa5988cb6302cdec16b3f4b9c598cef29d078afc Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Tue, 5 Nov 2019 21:12:55 -0800 Subject: [PATCH 2/3] Removed _group_count=col feature, closes #504 --- datasette/views/table.py | 12 ------------ docs/json_api.rst | 9 --------- 2 files changed, 21 deletions(-) diff --git a/datasette/views/table.py b/datasette/views/table.py index 941e4bb4..933f73c4 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -520,18 +520,6 @@ class TableView(RowTableShared): if order_by: order_by = "order by {} ".format(order_by) - # _group_count=col1&_group_count=col2 - group_count = special_args_lists.get("_group_count") or [] - if group_count: - sql = 'select {group_cols}, count(*) as "count" from {table_name} {where} group by {group_cols} order by "count" desc limit 100'.format( - group_cols=", ".join( - '"{}"'.format(group_count_col) for group_count_col in group_count - ), - table_name=escape_sqlite(table), - where=where_clause, - ) - return await self.custom_sql(request, database, hash, sql, editable=True) - extra_args = {} # Handle ?_size=500 page_size = _size or request.raw_args.get("_size") diff --git a/docs/json_api.rst b/docs/json_api.rst index de70362c..e369bee7 100644 --- a/docs/json_api.rst +++ b/docs/json_api.rst @@ -321,15 +321,6 @@ Special table arguments Here's `an example `__. - -``?_group_count=COLUMN`` - Executes a SQL query that returns a count of the number of rows matching - each unique value in that column, with the most common ordered first. - -``?_group_count=COLUMN1&_group_count=column2`` - You can pass multiple ``_group_count`` columns to return counts against - unique combinations of those columns. - ``?_next=TOKEN`` Pagination by continuation token - pass the token that was returned in the ``"next"`` property by the previous page. From bce6aee48512dd05b15c47ed923a006ea5f57c38 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 6 Nov 2019 16:55:44 -0800 Subject: [PATCH 3/3] Removed unused special_args_lists variable --- datasette/views/table.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/datasette/views/table.py b/datasette/views/table.py index 933f73c4..8c24bf53 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -282,12 +282,10 @@ class TableView(RowTableShared): # That's so if there is a column that starts with _ # it can still be queried using ?_col__exact=blah special_args = {} - special_args_lists = {} other_args = [] for key, value in args.items(): if key.startswith("_") and "__" not in key: special_args[key] = value[0] - special_args_lists[key] = value else: for v in value: other_args.append((key, v))