{"id": 309047460, "node_id": "MDU6SXNzdWUzMDkwNDc0NjA=", "number": 188, "title": "Ability to bundle metadata and templates inside the SQLite file", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-03-27T16:42:07Z", "updated_at": "2020-12-04T17:18:34Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "One of the nicest qualities of SQLite as a data format is that you get a single file which you can then backup or share with other people. \r\n\r\nDatasette breaks this a little once you start including custom metadata.json or template files and CSS.\r\n\r\nIt would be cool if there was an optional mechanism for baking that extra configuration into the SQLite file itself. That way entire datasette mini-applications (including canned queries and custom HTML and CSS) could be constructed as single .db files.\r\n\r\nSince datasette configuration is all file-based, one way to achieve that would be to support a \"datasette_files\" table which, if present is used to search for file contents by path.\r\n\r\nThis is inline with the philosophy described by https://www.sqlite.org/appfileformat.html\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/188/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 309471814, "node_id": "MDU6SXNzdWUzMDk0NzE4MTQ=", "number": 189, "title": "Ability to sort (and paginate) by column", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": {"value": 9599, "label": "simonw"}, "milestone": null, "comments": 31, "created_at": "2018-03-28T18:04:51Z", "updated_at": "2018-04-15T18:54:22Z", "closed_at": "2018-04-09T05:16:02Z", "author_association": "OWNER", "pull_request": null, "body": "As requested in https://github.com/simonw/datasette/issues/185#issuecomment-376614973\r\n\r\nI've previously avoided this for performance reasons: sort-by-column on a column without an index is likely to perform badly for hundreds of thousands of rows.\r\n\r\nThat's not a good enough reason to avoid the feature entirely though. A few options:\r\n\r\n* Allow sort-by-column by default, give users the option to disable it for specific tables/columns\r\n* Disallow sort-by-column by default, give users option (probably in `metadata.json`) to enable it for specific tables/columns\r\n* Automatically detect if a column either has an index on it OR a table has less than X rows in it\r\n\r\nWe already have the mechanism in place to cut off SQL queries that take more than X seconds, so if someone DOES try to sort by a column that's too expensive it won't actually hurt anything - but it would be nice to not show people a \"sort\" option which is guaranteed to throw a timeout error.\r\n\r\nThe vast majority of datasette usage that I've seen so far is on smaller datasets where the performance penalties of sort-by-column are extremely unlikely to show up.\r\n\r\n----\r\n\r\nStill left to do:\r\n\r\n- [x] UI that shows which sort order is currently being applied (in HTML and in JSON)\r\n- [x] UI for applying a sort order (with rel=nofollow to avoid Google crawling it)\r\n- [x] Sort column names should be escaped correctly in generated SQL\r\n- [x] Validation that the selected sort order is a valid column\r\n- [x] Throw error if user attempts to apply _sort AND _sort_desc at the same time\r\n- [x] Ability to disable sorting (or sort only for specific columns) in metadata.json\r\n- [x] Fix \"201 rows where sorted by sortable_with_nulls \" bug\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/189/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 309558826, "node_id": "MDU6SXNzdWUzMDk1NTg4MjY=", "number": 190, "title": "Keyset pagination doesn't work correctly for compound primary keys", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 7, "created_at": "2018-03-28T22:45:06Z", "updated_at": "2018-03-30T06:31:15Z", "closed_at": "2018-03-30T06:26:28Z", "author_association": "OWNER", "pull_request": null, "body": "Consider https://datasette-issue-190-compound-pks.now.sh/compound-pks-9aafe8f/compound_primary_key\r\n\r\n![2018-03-28 at 3 47 pm](https://user-images.githubusercontent.com/9599/38060388-56da86dc-329f-11e8-9f20-5576153ad55c.png)\r\n\r\nThe next= link is to `d,v`:\r\n\r\nhttps://datasette-issue-190-compound-pks.now.sh/compound-pks-9aafe8f/compound_primary_key?_next=d%2Cv\r\n\r\nBut that page starts with:\r\n\r\n![2018-03-28 at 3 48 pm](https://user-images.githubusercontent.com/9599/38060402-6b0f5984-329f-11e8-85b8-44a666c4ee71.png)\r\n\r\nThe next key in the sequence should be `d,w`. Also we should return the full a-z of the ones that start with the letter e - in this example we only return `e-w`, `e-x`, `e-y` and `e-z`", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/190/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 310533258, "node_id": "MDU6SXNzdWUzMTA1MzMyNTg=", "number": 191, "title": "Figure out how to bundle a more up-to-date SQLite", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-04-02T16:33:25Z", "updated_at": "2018-07-10T17:46:13Z", "closed_at": "2018-07-10T17:46:13Z", "author_association": "OWNER", "pull_request": null, "body": "The version of SQLite that ships with Python 3 is a bit limited - it doesn't support row values for example https://www.sqlite.org/rowvalue.html\r\n\r\nFigure out how to bundle a more recent SQLite engine with datasette. We need to figure out two cases:\r\n\r\n* Bundling a recent version in a Dockerfile build. I expect this to be quite easy.\r\n* Making a more recent version available to people hacking around in Mac OS X. I have no idea how to start on this.\r\n\r\nI want it working on Mac OS X too because I don't want to force Docker as a dependency for anyone who just want to hack around with Datasette a little and run the test suite.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/191/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 310850458, "node_id": "MDExOlB1bGxSZXF1ZXN0MTc5MTA4OTYx", "number": 192, "title": "New ?_shape=objects/object/lists param for JSON API", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-03T14:02:58Z", "updated_at": "2018-04-03T14:53:00Z", "closed_at": "2018-04-03T14:52:55Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/192", "body": "Refs #122", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/192/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 310882100, "node_id": "MDU6SXNzdWUzMTA4ODIxMDA=", "number": 193, "title": "Cleaner mechanism for handling custom errors", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-03T15:19:13Z", "updated_at": "2018-04-13T18:18:59Z", "closed_at": "2018-04-13T18:18:59Z", "author_association": "OWNER", "pull_request": null, "body": "This code is pretty messy:\r\n\r\nhttps://github.com/simonw/datasette/blob/0abd3abacb309a2bd5913a7a2df4e9256585b1bb/datasette/app.py#L245-L265\r\n\r\nInstead, it would be nice if I could raise an exception that would be converted into the appropriate JSON or HTML error message, with a corresponding HTTP code.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/193/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 312312125, "node_id": "MDU6SXNzdWUzMTIzMTIxMjU=", "number": 194, "title": "Rename table_rows and filtered_table_rows to have _count suffix", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-08T14:53:37Z", "updated_at": "2018-04-09T05:25:22Z", "closed_at": "2018-04-09T05:25:22Z", "author_association": "OWNER", "pull_request": null, "body": "These fields represent counts of items:\r\n\r\n \"table_rows\": 131,\r\n \"filtered_table_rows\": 8,\r\n\r\nBut the names make it sound like they might be arrays full of rows. Adding a `_count` suffix would make this more clear:\r\n\r\n \"table_rows_count\": 131,\r\n \"filtered_table_rows_count\": 8,\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/194/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 312313496, "node_id": "MDU6SXNzdWUzMTIzMTM0OTY=", "number": 195, "title": "Run pks_for_table in inspect, executing once at build time rather than constantly", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-08T15:12:40Z", "updated_at": "2018-04-10T00:54:43Z", "closed_at": "2018-04-10T00:54:43Z", "author_association": "OWNER", "pull_request": null, "body": "Right now several Datasette views call the `await self.pks_for_table(...)` method to figure out what primary keys are set for a specific table. This executes a `PRAGMA table_info` SQL query.\r\n\r\nIt would be faster and more efficient to execute this query for each table as part of the `inspect()` method.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/195/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 312355154, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgwMTg4Mzk3", "number": 196, "title": "_sort= and _sort_desc= parameters to table view", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-09T00:07:21Z", "updated_at": "2018-04-09T05:10:29Z", "closed_at": "2018-04-09T05:10:23Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/196", "body": "See #189 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/196/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 312395790, "node_id": "MDU6SXNzdWUzMTIzOTU3OTA=", "number": 197, "title": "Ability to sort by more than one column", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-09T05:13:30Z", "updated_at": "2018-07-10T17:45:37Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Split off from #189.\r\n\r\nI'd like to support \"sort by X descending, then by Y ascending if there are dupes for X\" as well. Suggested syntax for that:\r\n\r\n ?_sort_desc=X&_sort=Y\r\n\r\nwe currently only allow one argument to be sent. We should allow as many arguments as there are columns, for example:\r\n\r\n ?_sort=department&_sort_desc=precinct&_sort=age&_sort_desc=size", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/197/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 312396095, "node_id": "MDU6SXNzdWUzMTIzOTYwOTU=", "number": 198, "title": "Ability to sort with nulls last", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-09T05:15:40Z", "updated_at": "2018-07-10T17:45:37Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Split off from #189\r\n\r\nHere's how to do that in SQL: https://fivethirtyeight.datasettes.com/fivethirtyeight-2628db9?sql=select+rowid%2C+*+from+%5Bnfl-wide-receivers%2Fadvanced-historical%5D%0D%0Aorder+by+case+when+career_ranypa+is+null+then+1+else+0+end%2C+career_ranypa%2C+rowid\r\n\r\n order by case when career_ranypa is null then 1 else 0 end, career_ranypa", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/198/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 312620566, "node_id": "MDU6SXNzdWUzMTI2MjA1NjY=", "number": 199, "title": "Ability to apply sort on mobile in portrait mode", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-04-09T17:35:04Z", "updated_at": "2018-04-10T00:37:53Z", "closed_at": "2018-04-10T00:34:38Z", "author_association": "OWNER", "pull_request": null, "body": "Missed this in #189... on mobile in portrait mode we hide the column headers, which means you can't click them to sort! You can sort in landscape mode at least.\r\n\r\nNeed to come up with an alternative sort UI for portrait on mobile.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/199/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 313494458, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxMDMzMDI0", "number": 200, "title": "Hide Spatialite system tables", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-11T21:26:58Z", "updated_at": "2018-04-12T21:34:48Z", "closed_at": "2018-04-12T21:34:48Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/200", "body": "They were getting on my nerves.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/200/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 313512748, "node_id": "MDU6SXNzdWUzMTM1MTI3NDg=", "number": 201, "title": "Support explain select / explain query plan select", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-11T22:41:26Z", "updated_at": "2018-04-13T21:17:14Z", "closed_at": "2018-04-12T21:32:52Z", "author_association": "OWNER", "pull_request": null, "body": "See https://www.sqlite.org/eqp.html and https://www.sqlite.org/lang_explain.html", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/201/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 313785206, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxMjQ3NTY4", "number": 202, "title": "Raise 404 on nonexistent table URLs", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-12T15:47:06Z", "updated_at": "2018-04-13T19:22:56Z", "closed_at": "2018-04-13T18:19:15Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/202", "body": "Currently they just 500. Also cleaned the logic up a bit, I hope I didn't miss anything.\r\n\r\nThis is issue #184.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/202/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 313837303, "node_id": "MDU6SXNzdWUzMTM4MzczMDM=", "number": 203, "title": "Support for units", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 10, "created_at": "2018-04-12T18:24:28Z", "updated_at": "2018-04-16T21:59:17Z", "closed_at": "2018-04-16T21:59:17Z", "author_association": "CONTRIBUTOR", "pull_request": null, "body": "It would be nice to be able to attach a unit to a column in the metadata, and have it rendered with that unit (and SI prefix) when it's displayed.\r\n\r\nIt would also be nice to support entering the prefixes in variables when querying.\r\n\r\nWith my radio licensing app I've put all frequencies in Hz. It's easy enough to special-case the row rendering to add the SI prefixes, but it's pretty unusable when querying by that field.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/203/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314256802, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNjAwOTI2", "number": 204, "title": "Initial units support", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-13T21:32:49Z", "updated_at": "2018-04-14T09:44:33Z", "closed_at": "2018-04-14T03:32:54Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/204", "body": "Add support for specifying units for a column in metadata.json and rendering them on display using [pint](https://pint.readthedocs.io/en/latest/).\r\n\r\nExample table metadata:\r\n```json\r\n \"license_frequency\": {\r\n \"units\": {\r\n \"frequency\": \"Hz\",\r\n \"channel_width\": \"Hz\",\r\n \"height\": \"m\",\r\n \"antenna_height\": \"m\",\r\n \"azimuth\": \"degrees\"\r\n }\r\n }\r\n```\r\n\r\n[Example result](https://wtr-api.herokuapp.com/wtr-663ea99/license_frequency/1)\r\n\r\nThis works surprisingly well! I'd like to add support for using units when querying but this is PR is pretty usable as-is.\r\n\r\n(Pint doesn't seem to support decibels though - it thinks they're decibytes - which is an annoying omission.)\r\n\r\n(ref ticket #203)", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/204/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314319372, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNjQyMTE0", "number": 205, "title": "Support filtering with units and more", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-14T10:47:51Z", "updated_at": "2018-04-14T15:24:04Z", "closed_at": "2018-04-14T15:24:04Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/205", "body": "The first commit:\r\n* Adds units to exported JSON\r\n* Adds units key to metadata skeleton\r\n* Adds some docs for units\r\n\r\nThe second commit adds filtering by units by the first method I mentioned in #203:\r\n![image](https://user-images.githubusercontent.com/45057/38767463-7193be16-3fd9-11e8-8a5f-ac4159415c6d.png)\r\n\r\n[Try it here](https://wtr-api.herokuapp.com/wtr-663ea99/license_frequency?frequency__gt=50GHz&height__lt=50ft). I think it integrates pretty neatly.\r\n\r\nThe third commit adds support for registering custom units with Pint from metadata.json. Probably pretty niche, but I need decibels!", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/205/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314323977, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNjQ0ODA1", "number": 206, "title": "Fix sqlite error when loading rows with no incoming FKs", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-14T12:08:17Z", "updated_at": "2018-04-14T14:32:42Z", "closed_at": "2018-04-14T14:24:25Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/206", "body": "This fixes `ERROR: conn=, sql\r\n= 'select ', params = {'id': '1'}` caused by an invalid query loading incoming FKs when none exist.\r\n\r\nThe error was ignored due to async but it still got printed to the console.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/206/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314329002, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNjQ3NzE3", "number": 207, "title": "Link foreign keys which don't have labels", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-14T13:27:14Z", "updated_at": "2018-04-14T15:00:00Z", "closed_at": "2018-04-14T15:00:00Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/207", "body": "This renders unlabeled FKs as simple links. I can't see why this would cause any major problems.\r\n\r\n![image](https://user-images.githubusercontent.com/45057/38768722-ea15a000-3fef-11e8-8664-ffd7aa4894ea.png)\r\n\r\nAlso includes bonus fixes for two minor issues:\r\n\r\n* In foreign key link hrefs the primary key was escaped using HTML escaping rather than URL escaping. This broke some non-integer PKs.\r\n* Print tracebacks to console when handling 500 errors.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/207/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314340944, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNjU0ODM5", "number": 208, "title": "Return HTTP 405 on InvalidUsage rather than 500", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-14T16:12:50Z", "updated_at": "2018-04-14T18:00:39Z", "closed_at": "2018-04-14T18:00:39Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/208", "body": "This also stops it filling up the logs. This happens for HEAD requests at the moment - which perhaps should be handled better, but that's a different issue.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/208/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314455877, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNzIzMzAz", "number": 209, "title": " Don't duplicate simple primary keys in the link column", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-04-15T21:56:15Z", "updated_at": "2018-04-18T08:40:37Z", "closed_at": "2018-04-18T01:13:04Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/209", "body": "When there's a simple (single-column) primary key, it looks weird to duplicate it in the link column.\r\n\r\nThis change removes the second PK column and treats the link column as if it were the PK column from a header/sorting perspective. \r\n\r\nThis might make it a bit more difficult to tell what the link for the row is, I'm not sure yet. I feel like the alternative is to change the link column to just have the text \"view\" or something, instead of repeating the PK. (I doubt it makes much more sense with compound PKs.)\r\n\r\nBonus change in this PR: fix urlencoding of links in the displayed HTML.\r\n\r\nBefore:\r\n![image](https://user-images.githubusercontent.com/45057/38783830-e2ababb4-40ff-11e8-97fb-25e286a8c920.png)\r\n\r\nAfter:\r\n![image](https://user-images.githubusercontent.com/45057/38783835-ebf6b48e-40ff-11e8-8c47-6a864cf21ccc.png)", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/209/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314469126, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNzMxOTU2", "number": 210, "title": "Start of the plugin system, based on pluggy", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T00:51:30Z", "updated_at": "2018-04-16T00:56:16Z", "closed_at": "2018-04-16T00:56:16Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/210", "body": "Refs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/210/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314471743, "node_id": "MDU6SXNzdWUzMTQ0NzE3NDM=", "number": 211, "title": "Load plugins from a `--plugins-dir=plugins/` directory", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-04-16T01:17:43Z", "updated_at": "2018-04-16T05:22:02Z", "closed_at": "2018-04-16T05:22:02Z", "author_association": "OWNER", "pull_request": null, "body": "In #14 and 33c7c53ff87c2 I've added working support for setuptools entry_points plugins. These can be installed from PyPI using `pip install ...`.\r\n\r\nI imagine some projects will benefit from being able to add plugins without first publishing them to PyPI. Datasette already supports [loading custom templates](http://datasette.readthedocs.io/en/latest/custom_templates.html#custom-templates) like so:\r\n\r\n datasette serve --template-dir=mytemplates/ mydb.db\r\n\r\nI propose an additional option, `--plugins-dir=` which specifies a directory full of `blah.py` files which will be loaded into Datasette when the application server starts.\r\n\r\n datasette serve --plugins-dir=myplugins/ mydb.db\r\n\r\nThis will also need to be supported by `datasette publish` as those Python files should be copied up as part of the deployment.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/211/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314504812, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNzU1MjIw", "number": 212, "title": "New --plugins-dir=plugins/ option", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T05:19:28Z", "updated_at": "2018-04-16T05:22:18Z", "closed_at": "2018-04-16T05:22:01Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/212", "body": "Refs #211", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/212/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314506033, "node_id": "MDU6SXNzdWUzMTQ1MDYwMzM=", "number": 213, "title": "Documentation for plugins system", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T05:27:07Z", "updated_at": "2018-04-16T15:12:48Z", "closed_at": "2018-04-16T15:12:48Z", "author_association": "OWNER", "pull_request": null, "body": "Documentation for #14 - how to write plugins, how to ship plugins to PyPI and how to use the `--plugins-dir` option added in #211 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/213/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314506446, "node_id": "MDU6SXNzdWUzMTQ1MDY0NDY=", "number": 214, "title": "Ability for plugins to define extra JavaScript and CSS", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-04-16T05:29:34Z", "updated_at": "2020-09-30T20:36:11Z", "closed_at": "2018-04-18T03:13:03Z", "author_association": "OWNER", "pull_request": null, "body": "This can hook in to the existing `extra_css_urls` and `extra_js_urls` mechanism:\r\n\r\nhttps://github.com/simonw/datasette/blob/b2955d9065ea019500c7d072bcd9d49d1967f051/datasette/app.py#L304-L305\r\n\r\nThe plugins should be able to bundle their own assets though, so it will also have to integrate with the `/static/` static mounts mechanism somehow:\r\n\r\nhttps://github.com/simonw/datasette/blob/b2955d9065ea019500c7d072bcd9d49d1967f051/datasette/app.py#L1255-L1257\r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/214/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314665147, "node_id": "MDU6SXNzdWUzMTQ2NjUxNDc=", "number": 216, "title": "Bug: Sort by column with NULL in next_page URL", "user": {"value": 222245, "label": "carlmjohnson"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 15, "created_at": "2018-04-16T14:03:18Z", "updated_at": "2018-04-17T01:45:24Z", "closed_at": "2018-04-17T01:45:24Z", "author_association": "NONE", "pull_request": null, "body": "Copy-pasting from https://github.com/simonw/datasette/issues/189#issuecomment-381429213, since that issue is closed:\r\n\r\nI think I found a bug. I tried to sort by middle initial in my salaries set, and many middle initials are null. The `next_url` gets set by Datasette to:\r\n\r\nhttp://localhost:8001/salaries-d3a5631/2017+Maryland+state+salaries?_next=None%2C391&_sort=middle_initial\r\n\r\nBut then None is interpreted literally and it tries to find a name with the middle initial \"None\" and ends up skipping ahead to O on page 2.\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/216/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314725342, "node_id": "MDU6SXNzdWUzMTQ3MjUzNDI=", "number": 217, "title": "Plugin support for datasette publish", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-16T16:17:14Z", "updated_at": "2018-07-26T05:33:39Z", "closed_at": "2018-07-26T05:16:00Z", "author_association": "OWNER", "pull_request": null, "body": "It should be possible to support additional deployment options by writing a plugin (see #59).\r\n\r\nAs part of this, rewrite the Heroku and Now publishers to be implemented as plugins (they will still ship with datasette by default).\r\n\r\nMaybe `datasette package` should be changed to being part of publish instead, `datasette publish docker` perhaps? \r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/217/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314771615, "node_id": "MDU6SXNzdWUzMTQ3NzE2MTU=", "number": 218, "title": "Support custom unit display in order to handle \"$10,000\"", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T18:39:31Z", "updated_at": "2018-07-10T17:45:38Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I tried to get Datasette to display `$10,000` using the new units support but we currently only display units as a suffix:\r\n\r\nhttps://github.com/simonw/datasette/blob/10a34f995c70daa37a8a2aa02c3135a4b023a24c/datasette/app.py#L563-L572\r\n\r\nIt would be neat if there was a mechanism for specifying a custom unit display - maybe something like this:\r\n\r\n```\r\n{\r\n \"custom_units\": {\r\n \"us_dollar\": {\r\n \"unit\": \"us_dollar = [] = $\",\r\n \"format\": \"${:,}\"\r\n }\r\n }\r\n}\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/218/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 314834783, "node_id": "MDU6SXNzdWUzMTQ4MzQ3ODM=", "number": 219, "title": "Expose units in the JSON API?", "user": {"value": 45057, "label": "russss"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T22:04:25Z", "updated_at": "2018-04-16T22:04:25Z", "closed_at": null, "author_association": "CONTRIBUTOR", "pull_request": null, "body": "From #203: it would be nice for the JSON API to (optionally) return columns rendered with units in them - if, for example, you're consuming the JSON to render the rows on a map.\r\n\r\nI'm not entirely sure how useful this will be though - at the moment my map queries are custom SQL queries (a few have joins in, the rest might be fetching large amounts of data so it makes sense to limit columns fetched). Perhaps the SQL function is a better approach in general.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/219/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 314847571, "node_id": "MDU6SXNzdWUzMTQ4NDc1NzE=", "number": 220, "title": "Investigate syntactic sugar for plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-16T23:01:39Z", "updated_at": "2020-06-11T21:50:06Z", "closed_at": "2020-06-11T21:49:55Z", "author_association": "OWNER", "pull_request": null, "body": "Suggested by @andrewhayward on Twitter: https://twitter.com/arhayward/status/986015118965268480?s=21\r\n\r\n> Have you considered a basic abstraction on top of that, for standard hook features?\r\n\r\n```\r\n@sql_function\r\nrandom_integer(a,b):\r\n return random.randint(a,b)\r\n\r\n@template_filter\r\nuppercase(str):\r\n return str.upper()\r\n```\r\n\r\nMaybe `from datasette.plugins import template_filter`?\r\n\r\nWould have to work out how to get this to play well with pluggy", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/220/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 315142414, "node_id": "MDU6SXNzdWUzMTUxNDI0MTQ=", "number": 221, "title": "Allow plugins to add new cli sub commands ", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-17T16:40:13Z", "updated_at": "2021-01-04T20:12:14Z", "closed_at": "2021-01-04T20:12:14Z", "author_association": "OWNER", "pull_request": null, "body": "I could then test this out by having https://github.com/simonw/csvs-to-sqlite register itself as a plugin", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/221/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 315316214, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgyMzU3NjEz", "number": 222, "title": "Fix for plugins in Python 3.5", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-18T03:21:01Z", "updated_at": "2018-04-18T04:26:50Z", "closed_at": "2018-04-18T03:24:21Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/222", "body": "", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/222/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 315327860, "node_id": "MDU6SXNzdWUzMTUzMjc4NjA=", "number": 223, "title": "datasette publish --install=name-of-plugin", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-18T04:33:59Z", "updated_at": "2018-04-18T14:56:17Z", "closed_at": "2018-04-18T14:56:17Z", "author_association": "OWNER", "pull_request": null, "body": "Mechanism for causing datasette publish and datasette package to install one or more additional plugins using `pip install` - refs #14 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/223/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 315517578, "node_id": "MDU6SXNzdWUzMTU1MTc1Nzg=", "number": 224, "title": "Ability for plugins to bundle templates", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-18T14:57:53Z", "updated_at": "2018-04-19T05:50:36Z", "closed_at": "2018-04-19T05:50:36Z", "author_association": "OWNER", "pull_request": null, "body": "Plugins should be able to bundle templates.\r\n\r\nThe Datasette template loader should then consult those plugins first when loading a template.\r\n\r\nJinja2 has a `PackageLoader` class that can help with this: http://jinja.pocoo.org/docs/2.10/api/#jinja2.PackageLoader\r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/224/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 315548495, "node_id": "MDU6SXNzdWUzMTU1NDg0OTU=", "number": 225, "title": "/-/(inspect|metadata|plugins)(.json)? introspection", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-18T16:14:58Z", "updated_at": "2018-04-19T05:25:33Z", "closed_at": "2018-04-19T05:25:33Z", "author_association": "OWNER", "pull_request": null, "body": "3 pages (and accompanying .json endpoints) for viewing:\r\n\r\n* the metadata.json that datasette was loaded with\r\n* the output of ds.inspect()\r\n* a list of installed plugins, detected by pluggy", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/225/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 315738696, "node_id": "MDU6SXNzdWUzMTU3Mzg2OTY=", "number": 226, "title": "Unit tests for installable plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-19T06:05:32Z", "updated_at": "2020-11-24T19:52:51Z", "closed_at": "2020-11-24T19:52:46Z", "author_association": "OWNER", "pull_request": null, "body": "I'd like more thorough unit test coverage of the plugins mechanism - in particular for installable plugins.\r\n\r\nI think I can do this while still having the code live in the same repo, by creating a subdirectory in tests/example_plugin with its own setup.py and then running `python setup.py install` as part of the test runner.\r\n\r\nI imagine I will need to bump the version number every time I change the plugin in case someone runs the test again in the same virtual environment.\r\n\r\nIf that doesn't work I can instead ship a datasette-plugins-tests two to PyPI and add that as a tests_require dependency.\r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/226/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 315960272, "node_id": "MDU6SXNzdWUzMTU5NjAyNzI=", "number": 227, "title": "prepare_context() plugin hook", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 8, "created_at": "2018-04-19T16:55:26Z", "updated_at": "2020-03-24T22:19:54Z", "closed_at": "2020-03-24T22:19:54Z", "author_association": "OWNER", "pull_request": null, "body": "This would be called with the context dictionary before each template is rendered. It would have the opportunity to modify that context.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/227/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316031566, "node_id": "MDU6SXNzdWUzMTYwMzE1NjY=", "number": 228, "title": "If spatialite detected, mark idx_XXX_Geometry tables as hidden", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-19T20:37:24Z", "updated_at": "2018-04-26T03:25:39Z", "closed_at": "2018-04-26T03:25:39Z", "author_association": "OWNER", "pull_request": null, "body": "https://timezones-api.now.sh/timezones-faf26d0\r\n\r\n![2018-04-19 at 1 36 pm](https://user-images.githubusercontent.com/9599/39016906-a5acbb3e-43d6-11e8-9a31-814ff1d0022e.png)\r\n\r\nNeed to update this logic:\r\n\r\nhttps://github.com/simonw/datasette/blob/e2750c7cc0585adaa8c866be611089e62961ee35/datasette/app.py#L1276-L1288", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/228/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316123256, "node_id": "MDU6SXNzdWUzMTYxMjMyNTY=", "number": 229, "title": "Table view should support ?_size=400 parameter", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-20T04:23:18Z", "updated_at": "2018-04-26T04:49:46Z", "closed_at": "2018-04-26T04:48:32Z", "author_association": "OWNER", "pull_request": null, "body": "Allows callers to request more rows at once. The limit will still be `max_returned_rows` (defaults to 1000).", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/229/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316128955, "node_id": "MDU6SXNzdWUzMTYxMjg5NTU=", "number": 230, "title": "Setting page size AND max returned rows to 1000 doesn't seem to work", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-20T05:05:11Z", "updated_at": "2018-04-26T04:04:25Z", "closed_at": "2018-04-26T04:04:25Z", "author_association": "OWNER", "pull_request": null, "body": "It appears that if the two settings are the same Datasette fails to return any results, probably because of the trick where we try to fetch 1001 rows so we know if there's a next page.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/230/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316323336, "node_id": "MDU6SXNzdWUzMTYzMjMzMzY=", "number": 231, "title": "metadata.json support for plugin configuration options", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-04-20T15:58:47Z", "updated_at": "2019-05-13T18:56:21Z", "closed_at": "2019-05-13T18:56:21Z", "author_association": "OWNER", "pull_request": null, "body": "My [datasette-cluster-map](https://github.com/simonw/datasette-cluster-map) plugin currently works by detecting `latitude` and `longitude` columns. I'd like to be able to configure it to look for different column names.\r\n\r\nOne way to do this could be to support optional plugin configuration as part of `metadata.json`. Something like this:\r\n\r\n {\r\n \"title\": \"Polar Bear Ear Tags, 2009-2011\",\r\n \"source\": \"USGS Alaska Science Center, Polar Bear Research Program\",\r\n \"source_url\": \"https://alaska.usgs.gov/products/data.php?dataid=130\",\r\n \"plugins\": {\r\n \"datasette_cluster_map\": {\r\n \"latitude_columns\": [\r\n \"latitude\",\r\n \"Capture Latitude\"\r\n ],\r\n \"longitude_columns\": [\r\n \"longitude\",\r\n \"Capture Longitude\"\r\n ]\r\n }\r\n }\r\n }\r\n\r\nThese settings should be supported at the root level or at the individual database or table level.\r\n\r\nThey could also be exposed in the https://datasette-cluster-map-demo.now.sh/-/plugins debug tool.\r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/231/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316365426, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgzMTM1NjA0", "number": 232, "title": "Fix a typo", "user": {"value": 45281, "label": "lsb"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-20T18:20:04Z", "updated_at": "2018-04-21T00:19:08Z", "closed_at": "2018-04-21T00:19:08Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/232", "body": "It looks like this was the only instance of it: https://github.com/simonw/datasette/search?utf8=%E2%9C%93&q=SOLite&type=", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/232/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 316444720, "node_id": "MDU6SXNzdWUzMTY0NDQ3MjA=", "number": 233, "title": "Option to expose expanded foreign keys in JSON/CSV", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 11, "created_at": "2018-04-21T00:18:25Z", "updated_at": "2018-06-16T22:26:21Z", "closed_at": "2018-06-16T22:20:14Z", "author_association": "OWNER", "pull_request": null, "body": "https://datasette-cluster-map-demo.datasettes.com/sf-trees-02c8ef1/Street_Tree_List?qCareAssistant=1\r\n\r\n![f36b87c0-478e-4d55-9a5f-ad37df0b47cb](https://user-images.githubusercontent.com/9599/39078411-bb3e4f88-44be-11e8-9d0c-d22324793c77.png)\r\n\r\nIt would be nice if the info bubbles there could expose more than just the IDs, and if the title showed the expanded name of the selected qCareAssistant.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/233/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316526433, "node_id": "MDU6SXNzdWUzMTY1MjY0MzM=", "number": 234, "title": "label_column option in metadata.json", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-21T21:19:08Z", "updated_at": "2018-04-22T20:47:12Z", "closed_at": "2018-04-22T20:47:12Z", "author_association": "OWNER", "pull_request": null, "body": "Currently the column used for displaying a foreign key relationship is automatically detected by `inspect()` by looking for tables that have a primary key column and one other column.\r\n\r\nThis doesn't work for tables with more than two columns.\r\n\r\nLet's allow the table section in `metadata.json` to optionally define a `label_column` which, if present, will be used for those displays.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/234/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 316621102, "node_id": "MDU6SXNzdWUzMTY2MjExMDI=", "number": 235, "title": "Add limit on the size in KB of data returned from a single query", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-22T23:01:15Z", "updated_at": "2018-04-24T00:30:02Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Datasette limits the number of rows returned to 1,000 and limits the time spent executing a SQL query to 1000ms - and both of these limits can be customized.\r\n\r\nIt does not have a limit on the size of the response returned. It's possible to compose maliciously large SQL responses in a small number of rows using mechanisms like the `group_concat()` aggregate function. It would be good to avoid malicious SQL creating 100MB+ responses and potentially crashing the server.\r\n\r\nI think the easiest place to implement that is here:\r\n\r\nhttps://github.com/simonw/datasette/blob/f3f42957128c1e7ece584d45d9167f2ac003a3b8/datasette/app.py#L175-L190\r\n\r\nCurrently we use `cursor.fetchmany()` to fetch up to 1,001 rows at once. Instead, we could switch to iterating through `cursor.fetchone()` (or just using `for row in cursor`) and keeping a running tally of the size of the response as we go - maybe just using `rough_response_size += len(str(row))`. If that goes above a certain threshold we can terminate the response with an error, like we do with timelimits.\r\n\r\nThe bigger challenge here is understanding how well this approach works and what impact it will have on overall Datasette performance. I think I need #33 for this.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/235/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 317001500, "node_id": "MDU6SXNzdWUzMTcwMDE1MDA=", "number": 236, "title": "datasette publish lambda plugin", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 11, "created_at": "2018-04-23T22:10:30Z", "updated_at": "2023-03-12T14:04:15Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Refs #217 - create a publish plugin that can deploy to AWS Lambda.\r\n\r\nhttps://docs.aws.amazon.com/lambda/latest/dg/limits.html says lambda packages can be up to 50 MB, so this would only work with smaller databases (the command can check the filesize before attempting to package and deploy it).\r\n\r\nLambdas do get a 512 MB `/tmp` directory too, so for larger databases the function could start and then download up to 512MB from an S3 bucket - so the plugin could take an optional S3 bucket to write to and know how to upload the `.db` file there and then have the lambda download it on startup.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/236/reactions\", \"total_count\": 2, \"+1\": 2, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 317475156, "node_id": "MDU6SXNzdWUzMTc0NzUxNTY=", "number": 237, "title": "Support for ?_search_colname=blah searches", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-25T04:29:53Z", "updated_at": "2018-05-05T22:56:42Z", "closed_at": "2018-05-05T22:33:23Z", "author_association": "OWNER", "pull_request": null, "body": "Right now the `_search=` argument searches across all fields in a full-text index, for example:\r\n\r\nhttps://san-francisco.datasettes.com/sf-film-locations-84594a7/Film_Locations_in_San_Francisco?_search=justin\r\n\r\nSQLite FTS also supports searches within a specified field, for example:\r\n\r\nhttps://san-francisco.datasettes.com/sf-film-locations-84594a7?sql=select+rowid%2C+*+from+Film_Locations_in_San_Francisco+where+rowid+in+%28select+rowid+from+%5BFilm_Locations_in_San_Francisco_fts%5D+where+%5BLocations%5D+match+%3Asearch%29+order+by+rowid+limit+101&search=justin\r\n\r\n```\r\nselect rowid, * from Film_Locations_in_San_Francisco\r\nwhere rowid in (\r\n select rowid from [Film_Locations_in_San_Francisco_fts]\r\n where [Locations] match :search\r\n) order by rowid limit 101\r\n```\r\n\r\nThe `_search=` parameter could be extended to support this using `_search_colname=`.\r\n\r\nThis should also be able to support columns with spaces and special characters in their names, something like this:\r\n\r\n`_search_Column%20With%20Spaces=foo`\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/237/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 317714268, "node_id": "MDU6SXNzdWUzMTc3MTQyNjg=", "number": 238, "title": "External metadata.json", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-04-25T17:02:30Z", "updated_at": "2019-06-24T06:52:55Z", "closed_at": "2019-06-24T06:52:45Z", "author_association": "OWNER", "pull_request": null, "body": "A frustration I'm having with https://register-of-members-interests.datasettes.com/ is that I keep coming up with new canned queries but I don't want to redeploy the whole thing just to add them to `metadata.json`\r\n\r\nMaybe Datasette could optionally take a `--metadata-url` option which causes it to load from a URL instead and occasionally check for updates.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/238/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 317760361, "node_id": "MDU6SXNzdWUzMTc3NjAzNjE=", "number": 239, "title": "Support for hidden tables in metadata.json", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-25T19:21:17Z", "updated_at": "2018-04-26T03:45:12Z", "closed_at": "2018-04-26T03:43:10Z", "author_association": "OWNER", "pull_request": null, "body": "Since we already have a hidden feature, let's expose it more to our users ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/239/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 317900587, "node_id": "MDU6SXNzdWUzMTc5MDA1ODc=", "number": 240, "title": "FTS table detection should be part of .inspect()", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-26T06:58:10Z", "updated_at": "2018-04-29T00:04:44Z", "closed_at": "2018-04-29T00:04:44Z", "author_association": "OWNER", "pull_request": null, "body": "The code that detects if specific tables have a corresponding FTS column is currently called from TableView - it should instead be handled as part of `.inspect()`. This will make it easier to build other features that need to behave differently depending on whether a table can be searched, e.g. an autocomplete widget for selecting filters from foreign key tables.\r\n\r\nCurrent code:\r\n\r\nhttps://github.com/simonw/datasette/blob/f188ceaa2a3a5b2eab83425ad0f00cb0d364e24a/datasette/app.py#L728-L733", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/240/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 318490133, "node_id": "MDU6SXNzdWUzMTg0OTAxMzM=", "number": 241, "title": "Default datasette logging format should be JSON", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-27T17:32:48Z", "updated_at": "2018-07-10T17:45:40Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Structured logs are better. Datasette should default to outputting it's HTTP access log lines as newline delimited JSON instead of the Sanic default format it uses at the moment.\r\n\r\nFor improved greppability these logs should have keys ordered in a consistent way. Python's JSON module can do this with ordered dictionaries.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/241/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 318692953, "node_id": "MDU6SXNzdWUzMTg2OTI5NTM=", "number": 242, "title": "Rename ?_sql_time_limit_ms= to ?_timelimit=", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-29T06:11:35Z", "updated_at": "2018-05-02T00:20:42Z", "closed_at": "2018-05-02T00:20:42Z", "author_association": "OWNER", "pull_request": null, "body": "It's a bit of a mouthful at the moment.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/242/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 318737808, "node_id": "MDU6SXNzdWUzMTg3Mzc4MDg=", "number": 243, "title": "--spatialite option for datasette publish commands", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-29T18:19:32Z", "updated_at": "2018-05-31T14:17:53Z", "closed_at": "2018-05-31T14:17:53Z", "author_association": "OWNER", "pull_request": null, "body": "Performs the necessary incantations to install Spatialite on Zeit Now or Heroku and sets the corresponding environment variable to ensure the module is correctly loaded by datasette serve.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/243/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 318738000, "node_id": "MDU6SXNzdWUzMTg3MzgwMDA=", "number": 244, "title": "/-/versions page", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-29T18:22:15Z", "updated_at": "2018-05-03T14:13:49Z", "closed_at": "2018-05-03T14:09:53Z", "author_association": "OWNER", "pull_request": null, "body": "Displays the current version of:\r\n\r\n* datasette\r\n* Python\r\n* SQLite\r\n* Spatialite (if available)\r\n\r\nInstalled plugin versions should be shown on /-/plugins", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/244/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 319358200, "node_id": "MDU6SXNzdWUzMTkzNTgyMDA=", "number": 245, "title": "?_shape=array option", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-01T23:11:07Z", "updated_at": "2018-05-03T14:14:33Z", "closed_at": "2018-05-02T00:12:20Z", "author_association": "OWNER", "pull_request": null, "body": "Some tools (`pandas.DataFrame(...)` for example) are happiest when you give them a raw array of JSON objects.\r\n\r\n`?_shape=array` should do just that\r\n\r\nWhile I'm at it, rename the default `?_shape=lists` to instead be called `?shape=arrays`\r\n\r\nAnd validate that `_shape` is a valid option\r\n\r\nAnd have `?_shape=object` return the object at the root level rather than nested in `.rows` to better match the behavior of `?_shape=array`", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/245/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 319371036, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg1MzA3NDA3", "number": 246, "title": "?_shape=array and _timelimit=", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-05-02T00:18:54Z", "updated_at": "2018-05-02T00:20:41Z", "closed_at": "2018-05-02T00:20:40Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/246", "body": "", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/246/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 319449852, "node_id": "MDU6SXNzdWUzMTk0NDk4NTI=", "number": 247, "title": "SQLite code decoupled from Datasette", "user": {"value": 11912854, "label": "jsancho-gpl"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-02T08:03:28Z", "updated_at": "2018-05-21T15:29:31Z", "closed_at": null, "author_association": "NONE", "pull_request": null, "body": "I'm working on the possibility of use Datasette with other file formats that aren't SQLite, like files with [PyTables](https://github.com/PyTables/PyTables) format.\r\n\r\nIn order to accomplish that, I've started [a fork for decoupling the code related with SQLite](https://github.com/jsancho-gpl/datasette/tree/feature/db-type-plugin) and putting it in an external connector to allow future connectors for a lot of file formats.\r\n\r\nIt'd be nice if you could look at it and suggest improvements for a possible PR.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/247/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 319954545, "node_id": "MDU6SXNzdWUzMTk5NTQ1NDU=", "number": 248, "title": "/-/plugins should show version of each installed plugin", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-05-03T14:50:45Z", "updated_at": "2018-05-04T18:25:40Z", "closed_at": "2018-05-04T18:05:04Z", "author_association": "OWNER", "pull_request": null, "body": "Refs #244 \r\n\r\nhttps://stackoverflow.com/questions/20180543/how-to-check-version-of-python-modules\r\n\r\n```\r\n>>> import pkg_resources\r\n>>> pkg_resources.get_distribution('datasette_cluster_map').version\r\n'0.4'\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/248/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 320090329, "node_id": "MDU6SXNzdWUzMjAwOTAzMjk=", "number": 249, "title": "?_size=max argument ", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-03T21:42:04Z", "updated_at": "2018-05-04T18:26:30Z", "closed_at": "2018-05-04T18:05:04Z", "author_association": "OWNER", "pull_request": null, "body": "For plugins that want to load the most data allowable, having `?_size=max` would be useful.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/249/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 320132682, "node_id": "MDU6SXNzdWUzMjAxMzI2ODI=", "number": 250, "title": "Setup some issue templates", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-05-04T01:49:07Z", "updated_at": "2018-05-04T01:49:07Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://twitter.com/left_pad/status/99216385740464537\r\n\r\nI like the idea of using these to help people understand some of the ways I want to use issues.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/250/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 320592643, "node_id": "MDU6SXNzdWUzMjA1OTI2NDM=", "number": 251, "title": "Explore \"distinct values for column\" in inspect()", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-05-06T13:27:24Z", "updated_at": "2018-05-14T22:47:55Z", "closed_at": "2018-05-14T22:47:55Z", "author_association": "OWNER", "pull_request": null, "body": "A lot of datasets have columns which have a small number of possible values in them - this one for example: https://fivethirtyeight.datasettes.com/fivethirtyeight-2628db9?sql=select+distinct+category+from+%5Binconvenient-sequel%2Fratings%5D%3B\r\n\r\nDetecting these could be interesting as part of `.inspect()`, since it would allow for various UI enhancements like autocomplete / select box filters for those columns.\r\n\r\nThe problem is detecting them efficiently. `.inspect()` shouldn't spend 5 minutes churning through columns on giant tables trying to determine if they have a small collection of unique values.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/251/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 321624016, "node_id": "MDU6SXNzdWUzMjE2MjQwMTY=", "number": 252, "title": "/-/versions should report the FTS version supported by SQLite", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-05-09T15:43:47Z", "updated_at": "2018-05-11T13:19:52Z", "closed_at": "2018-05-11T13:19:52Z", "author_association": "OWNER", "pull_request": null, "body": "I can copy this function from `csvs-to-sqlite`: https://github.com/simonw/csvs-to-sqlite/blob/dccbf65b37bc9eed50e9edb80a42f257e93edb1f/csvs_to_sqlite/utils.py#L283-L293", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/252/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 321631020, "node_id": "MDU6SXNzdWUzMjE2MzEwMjA=", "number": 253, "title": "Documentation explaining how to use SQLite FTS with Datasette", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-09T16:02:08Z", "updated_at": "2018-05-12T12:09:02Z", "closed_at": "2018-05-12T12:06:51Z", "author_association": "OWNER", "pull_request": null, "body": "In particular how to work with https://www.sqlite.org/fts3.html#_external_content_fts4_tables_ - which Datasette can automatically detect and use to add a search UI to your page.\r\n\r\nExamples of basic search setup like this:\r\n\r\n```\r\nCREATE VIRTUAL TABLE \"interests_fts\"\r\n USING FTS4 (name, content=\"interests\");\r\nINSERT INTO \"interests_fts\" (rowid, name)\r\n SELECT rowid, name FROM interests;\r\n```\r\n\r\nAnd complex join-based search setup like this:\r\n\r\n```\r\nCREATE VIRTUAL TABLE \"interests_fts\"\r\n USING FTS4 (name, category, member, content=\"interests\");\r\nINSERT INTO \"interests_fts\" (rowid, name, category, member)\r\n SELECT interests.rowid, interests.name, interest_categories.name, members.name\r\n FROM interests\r\n JOIN interest_categories ON interests.category_id = interest_categories.id\r\n JOIN members ON interests.member_id = members.id;\r\n```\r\n\r\nAlso mention how `csvs-to-sqlite` can be used to do this easily.\r\n\r\nThis will benefit from #252 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/253/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 322283067, "node_id": "MDU6SXNzdWUzMjIyODMwNjc=", "number": 254, "title": "Escaping named parameters in canned queries", "user": {"value": 247131, "label": "philroche"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-05-11T12:43:30Z", "updated_at": "2020-05-10T14:54:14Z", "closed_at": "2020-05-10T14:54:13Z", "author_association": "NONE", "pull_request": null, "body": "Thank you very much for this project.\r\n\r\nI have created some canned queries but some of the filters include a colon eg. \"com.ubuntu.cloud:server:18.04:amd64\". When saved these colons are parsed as named parameters. \r\n\r\nIs there a way to escape colons in a canned query?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/254/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 322477187, "node_id": "MDU6SXNzdWUzMjI0NzcxODc=", "number": 255, "title": "Facets", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 16, "created_at": "2018-05-12T03:00:07Z", "updated_at": "2019-05-29T21:39:12Z", "closed_at": "2018-05-16T15:32:12Z", "author_association": "OWNER", "pull_request": null, "body": "Ability to display facets and facet counts on the table view.\r\n\r\nFacets can be specified in the URL with `?_facet=column&_facet=othercolumn` or the default facets for a table can be set using a new `\"facets\": [...]` property in `metadata.json`\r\n\r\n- [x] Implement `?_facet=`\r\n- [x] Implement `metadata.json` `facets` key\r\n- [x] Design for how facets should be presented\r\n- [x] Facets should be able to toggle off as well as on\r\n- [x] Expand labels for facets that are foreign keys\r\n- [x] Suggest potential facets (if we can do so within a tight time limit)\r\n- [x] Documentation", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/255/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 322551723, "node_id": "MDU6SXNzdWUzMjI1NTE3MjM=", "number": 256, "title": "Break up app.py into separate view modules", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-12T23:56:33Z", "updated_at": "2018-05-14T03:05:37Z", "closed_at": "2018-05-14T03:05:37Z", "author_association": "OWNER", "pull_request": null, "body": "`views/table.py` and `views/database.py` and `views/utils.py` as a starting point.\r\n\r\nLikewise, create `tests/test_views_table.py` and `tests/test_views_database.py` - these will contain both HTML and API test for those views.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/256/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 322591993, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg3NjY4ODkw", "number": 257, "title": "Refactor views", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2018-05-13T13:00:50Z", "updated_at": "2018-05-14T03:04:25Z", "closed_at": "2018-05-14T03:04:24Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/257", "body": "* Split out view classes from main `app.py`\r\n* Run [black](https://github.com/ambv/black) against resulting code to apply opinionated source code formatting\r\n* Run [isort](https://github.com/timothycrosley/isort) to re-order my imports\r\n\r\nRefs #256 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/257/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 322741659, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg3NzcwMzQ1", "number": 258, "title": "Add new metadata key persistent_urls which removes the hash from all database urls", "user": {"value": 247131, "label": "philroche"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-14T09:39:18Z", "updated_at": "2018-05-21T07:38:15Z", "closed_at": "2018-05-21T07:38:15Z", "author_association": "NONE", "pull_request": "simonw/datasette/pulls/258", "body": "Add new metadata key \"persistent_urls\" which removes the hash from all database urls when set to \"true\"\r\n\r\nThis PR is just to gauge if this, or something like it, is something you would consider merging?\r\n\r\nI understand the reason why the substring of the hash is included in the url but\r\nthere are some use cases where the urls should persist across deployments. For bookmarks\r\nfor example or for scripts that use the JSON API.\r\n\r\nThis is the initial commit for this feature. Tests and documentation updates to follow.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/258/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 322787470, "node_id": "MDU6SXNzdWUzMjI3ODc0NzA=", "number": 259, "title": "inspect() should detect many-to-many relationships", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-05-14T12:03:58Z", "updated_at": "2019-05-23T03:55:37Z", "closed_at": "2019-05-23T03:55:37Z", "author_association": "OWNER", "pull_request": null, "body": "Relates to #255 - in particular supporting facets across M2M relationships.\r\n\r\nIt should be possible for `.inspect()` to notice when a table has two foreign keys to two different tables, and assume that this means there is a M2M relationship between those tables.\r\n\r\nWhen rendering a table with a m2m relationship we could display the first X associated records as a comma separated list of hyperlinks in a new column on the table view, with a column name derived from the table on the other side.\r\n\r\nSince SQLite doesn't have RANK or an equivalent of https://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/ this would be implemented as N+1 queries (one query per cell that we want to display an m2m summary). This should be OK in SQLite: https://sqlite.org/np1queryprob.html", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/259/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323223872, "node_id": "MDU6SXNzdWUzMjMyMjM4NzI=", "number": 260, "title": "Validate metadata.json on startup", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 7, "created_at": "2018-05-15T13:42:56Z", "updated_at": "2023-06-21T12:51:22Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "It's easy to misspell the name of a database or table and then be puzzled when the metadata settings silently fail.\r\n\r\nTo avoid this, let's sanity check the provided metadata.json on startup and quit with a useful error message if we find any obvious mistakes.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/260/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 323459939, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg4MzEyNDEx", "number": 261, "title": "Facets improvements plus suggested facets", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-05-16T03:52:39Z", "updated_at": "2018-05-16T15:27:26Z", "closed_at": "2018-05-16T15:27:25Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/261", "body": "Refs #255", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/261/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 323671577, "node_id": "MDU6SXNzdWUzMjM2NzE1Nzc=", "number": 263, "title": "Facets should not execute for ?shape=array|object", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-16T15:26:13Z", "updated_at": "2021-06-02T02:54:34Z", "closed_at": "2021-06-02T02:54:34Z", "author_association": "OWNER", "pull_request": null, "body": "Split off from #255 - there's no point executing the facet SQL for the `?_shape=array` and `?_shape=object` API responses.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/263/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323673899, "node_id": "MDU6SXNzdWUzMjM2NzM4OTk=", "number": 264, "title": "Make it possible to customize various facet settings", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-16T15:31:34Z", "updated_at": "2018-05-18T06:18:00Z", "closed_at": "2018-05-18T05:11:52Z", "author_association": "OWNER", "pull_request": null, "body": "The new Facets implementation from #255 includes several hard-coded settings which should be made configurable somehow:\r\n\r\nNumber of rows to return in a facet (maybe this should also be an option that can be set via quersytring argument, e.g. `?_facet=qSpecies:40`):\r\n\r\nhttps://github.com/simonw/datasette/blob/9959a9e4deec8e3e178f919e8b494214d5faa7fd/datasette/views/table.py#L539\r\n\r\nTime limit for executing a facet:\r\n\r\nhttps://github.com/simonw/datasette/blob/9959a9e4deec8e3e178f919e8b494214d5faa7fd/datasette/views/table.py#L559-L562\r\n\r\nMaximum unique values returned in order for a column to be suggested as a facet:\r\n\r\nhttps://github.com/simonw/datasette/blob/9959a9e4deec8e3e178f919e8b494214d5faa7fd/datasette/views/table.py#L646-L647\r\n\r\nTime limit for calculating if a column should be a suggested facet:\r\n\r\nhttps://github.com/simonw/datasette/blob/9959a9e4deec8e3e178f919e8b494214d5faa7fd/datasette/views/table.py#L664-L667\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/264/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323677499, "node_id": "MDU6SXNzdWUzMjM2Nzc0OTk=", "number": 265, "title": "Add links to example Datasette instances to appropiate places in docs", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2018-05-16T15:40:20Z", "updated_at": "2018-06-18T15:52:15Z", "closed_at": "2018-06-18T15:52:15Z", "author_association": "OWNER", "pull_request": null, "body": "Links to working examples would really help, especially on these pages:\r\n\r\n* http://datasette.readthedocs.io/en/latest/json_api.html\r\n* http://datasette.readthedocs.io/en/latest/sql_queries.html\r\n* http://datasette.readthedocs.io/en/latest/facets.html\r\n* http://datasette.readthedocs.io/en/latest/full_text_search.html", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/265/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323681589, "node_id": "MDU6SXNzdWUzMjM2ODE1ODk=", "number": 266, "title": "Export to CSV", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 27, "created_at": "2018-05-16T15:50:24Z", "updated_at": "2021-06-17T18:14:24Z", "closed_at": "2018-06-18T06:05:25Z", "author_association": "OWNER", "pull_request": null, "body": "Datasette needs to be able to export data to CSV.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/266/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323716411, "node_id": "MDU6SXNzdWUzMjM3MTY0MTE=", "number": 267, "title": "Documentation for URL hashing, redirects and cache policy", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-16T17:29:01Z", "updated_at": "2019-06-24T06:41:02Z", "closed_at": "2019-06-24T06:41:02Z", "author_association": "OWNER", "pull_request": null, "body": "See my comments on #258 for a starting point", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/267/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323718842, "node_id": "MDU6SXNzdWUzMjM3MTg4NDI=", "number": 268, "title": "Mechanism for ranking results from SQLite full-text search", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 12, "created_at": "2018-05-16T17:36:40Z", "updated_at": "2022-01-13T22:21:28Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This isn't particularly straight-forward - all the more reason for Datasette to implement it for you. This article is helpful: http://charlesleifer.com/blog/using-sqlite-full-text-search-with-python/", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/268/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 323726888, "node_id": "MDU6SXNzdWUzMjM3MjY4ODg=", "number": 269, "title": "If a facet fails due to timing out, let the user know somehow", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-05-16T18:01:47Z", "updated_at": "2018-05-18T06:11:46Z", "closed_at": "2018-05-18T06:11:46Z", "author_association": "OWNER", "pull_request": null, "body": "Refs #255 - right now facets fail silently if the user requested them but they take longer than 200ms to calculate - see also #264", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/269/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 323830051, "node_id": "MDU6SXNzdWUzMjM4MzAwNTE=", "number": 270, "title": "--limit= CLI option for setting limits", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-17T00:14:24Z", "updated_at": "2018-05-18T06:19:31Z", "closed_at": "2018-05-18T06:16:39Z", "author_association": "OWNER", "pull_request": null, "body": "#264 calls for four new datasette limit options, on top of the two existing ones:\r\n\r\n* `--max_returned_rows`\r\n* `--sql_time_limit_ms`\r\n\r\nThese are already clogging up `datasette serve --help` a bit.\r\n\r\nHow about this syntax instead?\r\n\r\n datasette --limit max_returned_rows:100 \\\r\n --limit facet_timeout_ms:500 demo.db\r\n\r\nThen we can add as many new user over-rideable limits as we like without clogging up `--help` too much - though it would be good to have a way of optionally listings their documentation as well.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/270/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 324162476, "node_id": "MDU6SXNzdWUzMjQxNjI0NzY=", "number": 271, "title": "Mechanism for automatically picking up changes when on-disk .db file changes", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-05-17T19:53:15Z", "updated_at": "2019-01-10T21:35:18Z", "closed_at": "2019-01-10T21:35:18Z", "author_association": "OWNER", "pull_request": null, "body": "It would be useful if Datasette could spot when a SQLite database file changes on disk and restart itself (hence re-running .inspect() and picking up the new content hash). Ideally this could happen in an atomic way so no requests get dropped during the switch-over.\r\n\r\nThis may not play well with SQLite opening databases in immutable mode. Research required.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/271/reactions\", \"total_count\": 2, \"+1\": 2, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 324451322, "node_id": "MDU6SXNzdWUzMjQ0NTEzMjI=", "number": 273, "title": "Figure out a way to have /-/version return current git commit hash", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-05-18T15:16:56Z", "updated_at": "2018-05-22T19:35:22Z", "closed_at": "2018-05-22T19:35:22Z", "author_association": "OWNER", "pull_request": null, "body": "https://fivethirtyeight.datasettes.com/-/versions reports Datasette version `0.21`\r\n\r\nThis isn't actually correct. The deploy script for that site actually deploys current master using `https://github.com/simonw/datasette/archive/master.zip`: https://github.com/simonw/fivethirtyeight-datasette/blob/66b4b0dfedd7237bc8c02d3e26d905bca7b84069/Dockerfile#L9\r\n\r\nIdeally this would show the current commit hash, but I'm not at all sure if it's possible to derive that from `pip install https://github.com/simonw/datasette/archive/master.zip`. Is there another mechanism that could be used to reliably `pip install` current master but still provide access to the most recent commit hash?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/273/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 324652142, "node_id": "MDU6SXNzdWUzMjQ2NTIxNDI=", "number": 274, "title": "Rename --limit to --config, add --help-config", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-05-19T18:57:42Z", "updated_at": "2018-05-20T17:04:55Z", "closed_at": "2018-05-20T17:04:11Z", "author_association": "OWNER", "pull_request": null, "body": "#270 introduced `--limit` but on further thought it should be called `--config` instead.\r\n\r\n`--page_size` should becomes `--config default_page_size:1000`\r\n\r\nAdd `--help-config` to show full help showing all config settings.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/274/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 324720095, "node_id": "MDU6SXNzdWUzMjQ3MjAwOTU=", "number": 275, "title": "\"config\" section in metadata.json (root, database and table level)", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-20T16:02:28Z", "updated_at": "2023-08-23T01:28:37Z", "closed_at": "2023-08-23T01:28:37Z", "author_association": "OWNER", "pull_request": null, "body": "Split off from #274 \r\n\r\nMetadata should an optional `\"config\"` section at root, table or database level.\r\n\r\nThe TableView and RowView and DatabaseView and BaseView classes could all have a `.config(\"key\")` method which knows how to resolve the hierarchy of configs.\r\n\r\nThis will allow individual tables (or databases) to set their own config settings for things like `sql_time_limit_ms`", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/275/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 324835838, "node_id": "MDU6SXNzdWUzMjQ4MzU4Mzg=", "number": 276, "title": "Handle spatialite geometry columns better", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 21, "created_at": "2018-05-21T08:46:55Z", "updated_at": "2022-03-21T22:22:20Z", "closed_at": "2022-03-21T22:22:20Z", "author_association": "CONTRIBUTOR", "pull_request": null, "body": "I'd like to see spatialite geometry columns rendered more sensibly - at the moment they come through as well-known-binary unless you use custom SQL, and WKB isn't of much use to anyone on the web.\r\n\r\nIn HTML: they should be shown either as simple lat/long (if it's just a point, for example), or as a sensible placeholder if they're more complex geometries.\r\n\r\nIn JSON: they should be GeoJSON geometries, (which means they can be automatically fed into a leaflet map with no further messing around).\r\n\r\nIn CSV: they should be WKT.\r\n\r\nI briefly wondered if this should go into a plugin, but I suspect it needs hooking in at a deeper level than the plugin architecture will support any time soon.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/276/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 324836533, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg5MzE4NDUz", "number": 277, "title": "Refactor inspect logic", "user": {"value": 45057, "label": "russss"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-05-21T08:49:31Z", "updated_at": "2018-05-22T16:07:24Z", "closed_at": "2018-05-22T14:03:07Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/277", "body": "This pulls the logic for inspect out into a new file which makes it a bit easier to understand.\r\n\r\nThis was going to be the first part of an implementation for #276, but it seems like that might take a while so I'm going to PR a few bits of refactoring individually.", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/277/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 325294102, "node_id": "MDU6SXNzdWUzMjUyOTQxMDI=", "number": 278, "title": "Build smallest possible Docker image with Datasette plus recent SQLite (with json1) plus Spatialite 4.4.0", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-22T13:28:40Z", "updated_at": "2018-05-23T17:43:36Z", "closed_at": "2018-05-23T17:43:36Z", "author_association": "OWNER", "pull_request": null, "body": "A Dockerfile that does the following:\r\n\r\n* Bundles Datasette master\r\n* Python 3.6 most recent version (or 3.7 if it has been released)\r\n* SQLite 3.23.1 (or most recent release) such that \"import sqite3\" in Python gets that version. Ideally with the json1 module baked in by default, but having it loadable as an optional module is fine too\r\n* SpatiaLite 4.4.0-RC0 (or most recent version) such that it can be loaded as an optional module\r\n* Uses multi-stage builds to stay as small as possible\r\n\r\nNote that the current \"release\" of SpatiaLite is 4.3.0 which is missing key features like https://www.gaia-gis.it/fossil/libspatialite/wiki?name=KNN - 4.4.0 probably needs to be compiled from source.\r\n\r\nI don't know the best way to get a current SQLite version bundled for Python 3. Maybe https://github.com/coleifer/pysqlite3 ?", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/278/reactions\", \"total_count\": 2, \"+1\": 2, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 325352370, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg5NzA3Mzc0", "number": 279, "title": "Add version number support with Versioneer", "user": {"value": 198537, "label": "rgieseke"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-05-22T15:39:45Z", "updated_at": "2018-05-22T19:35:23Z", "closed_at": "2018-05-22T19:35:22Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/279", "body": "I think that's all for getting Versioneer support, I've been happily using it in a couple of projects ... \r\n\r\n```\r\nIn [2]: datasette.__version__\r\nOut[2]: '0.22+3.g6e12445'\r\n```\r\nRepo:\r\nhttps://github.com/warner/python-versioneer\r\n\r\nVersioneer Licence:\r\nPublic Domain (CC0-1.0)\r\n\r\nCloses #273\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/279/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 325373747, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg5NzIzNzE2", "number": 280, "title": "Build Dockerfile with recent Sqlite + Spatialite", "user": {"value": 565628, "label": "r4vi"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 10, "created_at": "2018-05-22T16:33:50Z", "updated_at": "2018-06-28T11:26:23Z", "closed_at": "2018-05-23T17:43:35Z", "author_association": "CONTRIBUTOR", "pull_request": "simonw/datasette/pulls/280", "body": "This solves #278 without bloating the Dockerfile too much, the image size is now\r\n495MB (original was ~240MB) but it could be reduced significantly if we only\r\ncopied the output of the compilation of spatialite and friends to\r\n/usr/local/lib, instead of the entirety of it however that will take more time.\r\n\r\nIn the python code change references to `import sqlite3` to `import pysqlite3`\r\nand it should use the compiled version of sqlite3.23.1. You don't need to\r\ntry/except because pysqlite3 falls back to builtin sqlite3 if there is no\r\ncompiled version.\r\n\r\n```bash\r\n $ docker run --rm -it datasette spatialite\r\n SpatiaLite version ..: 4.4.0-RC0\tSupported Extensions:\r\n - 'VirtualShape'\t[direct Shapefile access]\r\n - 'VirtualDbf'\t\t[direct DBF access]\r\n - 'VirtualXL'\t\t[direct XLS access]\r\n - 'VirtualText'\t\t[direct CSV/TXT access]\r\n - 'VirtualNetwork'\t[Dijkstra shortest path]\r\n - 'RTree'\t\t[Spatial Index - R*Tree]\r\n - 'MbrCache'\t\t[Spatial Index - MBR cache]\r\n - 'VirtualSpatialIndex'\t[R*Tree metahandler]\r\n - 'VirtualElementary'\t[ElemGeoms metahandler]\r\n - 'VirtualKNN'\t[K-Nearest Neighbors metahandler]\r\n - 'VirtualXPath'\t[XML Path Language - XPath]\r\n - 'VirtualFDO'\t\t[FDO-OGR interoperability]\r\n - 'VirtualGPKG'\t[OGC GeoPackage interoperability]\r\n - 'VirtualBBox'\t\t[BoundingBox tables]\r\n - 'SpatiaLite'\t\t[Spatial SQL - OGC]\r\n PROJ.4 version ......: Rel. 4.9.3, 15 August 2016\r\n GEOS version ........: 3.5.1-CAPI-1.9.1 r4246\r\n TARGET CPU ..........: x86_64-linux-gnu\r\n the SPATIAL_REF_SYS table already contains some row(s)\r\n SQLite version ......: 3.23.1\r\n Enter \".help\" for instructions\r\n SQLite version 3.23.1 2018-04-10 17:39:29\r\n Enter \".help\" for instructions\r\n Enter SQL statements terminated with a \";\"\r\n spatialite>\r\n```\r\n\r\n```bash\r\n$ docker run --rm -it datasette python -c \"import pysqlite3; print(pysqlite3.sqlite_version)\"\r\n3.23.1\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/280/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 325553991, "node_id": "MDExOlB1bGxSZXF1ZXN0MTg5ODYwMDUy", "number": 281, "title": "Reduces image size using Alpine + Multistage (re: #278)", "user": {"value": 487897, "label": "iMerica"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-23T05:27:05Z", "updated_at": "2018-05-26T02:10:38Z", "closed_at": "2018-05-26T02:10:38Z", "author_association": "NONE", "pull_request": "simonw/datasette/pulls/281", "body": "Hey Simon! \r\n\r\nI got the image size down from 256MB to 110MB. \r\n\r\nSeems to be working okay, but you might want to test it a bit more.\r\n\r\nExample output of `docker run --rm -it datasette`\r\n```\r\nServe! files=() on port 8001\r\n[2018-05-23 05:23:08 +0000] [1] [INFO] Goin' Fast @ http://127.0.0.1:8001\r\n[2018-05-23 05:23:08 +0000] [1] [INFO] Starting worker [1]\r\n```\r\n\r\nRelated: https://github.com/simonw/datasette/issues/278\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/281/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 325705981, "node_id": "MDU6SXNzdWUzMjU3MDU5ODE=", "number": 282, "title": "Faceting breaks pagination", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-23T13:29:47Z", "updated_at": "2018-05-23T13:53:39Z", "closed_at": "2018-05-23T13:42:07Z", "author_association": "OWNER", "pull_request": null, "body": "e.g. on https://fivethirtyeight.datasettes.com/fivethirtyeight-5de27e3/nba-elo%2Fnbaallelo?_facet=lg_id#facet-lg_id - click the \"next page\" link: https://fivethirtyeight.datasettes.com/fivethirtyeight-5de27e3/nba-elo%2Fnbaallelo?_facet=lg_id&_next=100\r\n\r\n Invalid SQL: near \"and\": syntax error", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/282/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 325958506, "node_id": "MDU6SXNzdWUzMjU5NTg1MDY=", "number": 283, "title": "Support cross-database joins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 26, "created_at": "2018-05-24T04:18:39Z", "updated_at": "2021-06-06T09:40:18Z", "closed_at": "2021-02-18T22:16:46Z", "author_association": "OWNER", "pull_request": null, "body": "SQLite has the ability to attach multiple databases to a single connection and then run joins across multiple databases.\r\n\r\nSince Datasette supports more than one database, this would make a pretty neat feature.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/283/reactions\", \"total_count\": 2, \"+1\": 2, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 326182814, "node_id": "MDU6SXNzdWUzMjYxODI4MTQ=", "number": 284, "title": "Ability to enable/disable specific features via --config", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2018-05-24T15:47:56Z", "updated_at": "2018-05-25T06:05:02Z", "closed_at": "2018-05-25T05:51:09Z", "author_association": "OWNER", "pull_request": null, "body": "`--config` settings from #274 can currently only be integers.\r\n\r\nI'd like them to be available as boooeans too. Then we can use them to have that are turned on by default but can be turned off.\r\n\r\nFirst features to get this treatment:\r\n\r\n- [x] `allow_sql` - whether or not the `?sql=` parameter is allowed and form is displayed\r\n- [X] `allow_facet` - is `?_facet=` allowed or do we only run facets defined in `metadata.json`\r\n- [X] `allow_download` - do we let users download the full SQLite database file?\r\n- [X] `suggest_facets` - do we attempt to calculate suggested facets?\r\n\r\nRefs #275 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/284/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 326189744, "node_id": "MDU6SXNzdWUzMjYxODk3NDQ=", "number": 285, "title": "num_threads and cache_max_age should be --config options", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-05-24T16:04:51Z", "updated_at": "2018-05-27T00:53:35Z", "closed_at": "2018-05-27T00:43:33Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/simonw/datasette/blob/58b5a37dbbf13868a46bcbb284509434e66eca25/datasette/app.py#L106\r\n\r\nAnd\r\n\r\nhttps://github.com/simonw/datasette/blob/58b5a37dbbf13868a46bcbb284509434e66eca25/datasette/views/base.py#L325\r\n\r\nRefs #275 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/285/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 326599525, "node_id": "MDU6SXNzdWUzMjY1OTk1MjU=", "number": 286, "title": "Database hash should include current datasette version", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-05-25T17:03:42Z", "updated_at": "2018-05-25T17:07:36Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Right now deploying a new version of datasette doesn't invalidate existing URLs, so users may still see a cached copy of the old templates.\r\n\r\nWe can fix this by including the current datasette version in the input to the hash function (which currently just the database file contents).", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/286/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 326617744, "node_id": "MDU6SXNzdWUzMjY2MTc3NDQ=", "number": 287, "title": "?_shape=arrayfirst", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-05-25T18:11:03Z", "updated_at": "2018-05-27T00:32:53Z", "closed_at": "2018-05-27T00:32:29Z", "author_association": "OWNER", "pull_request": null, "body": "Return an array of single items (the first item in each row returned from the SQL query).", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/287/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 326767626, "node_id": "MDU6SXNzdWUzMjY3Njc2MjY=", "number": 288, "title": "Support multiple filters of the same type", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-26T21:13:12Z", "updated_at": "2019-04-15T23:45:04Z", "closed_at": "2019-04-15T23:44:26Z", "author_association": "OWNER", "pull_request": null, "body": "This should work for example:\r\n\r\nhttps://fivethirtyeight.datasettes.com/fivethirtyeight-5de27e3/biopics%2Fbiopics?year_release__not=2014&year_release__not=2015", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/288/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 326768188, "node_id": "MDU6SXNzdWUzMjY3NjgxODg=", "number": 289, "title": "?_ttl= parameter to control caching", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-26T21:22:55Z", "updated_at": "2018-05-26T22:22:47Z", "closed_at": "2018-05-26T22:17:48Z", "author_association": "OWNER", "pull_request": null, "body": "This would allow clients to specify the max-age caching header that should be returned with the query.\r\n\r\nMost important this will allow caching to be completely urned off for specific queries using `?_ttl=0`. Sending 0 should cause a `Cache-Control: no-cache` header to be returned.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/289/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 326778161, "node_id": "MDU6SXNzdWUzMjY3NzgxNjE=", "number": 290, "title": "Consider increasing the default for num_sql_threads (currently 3)", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-05-27T00:52:41Z", "updated_at": "2018-05-27T00:52:41Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I ran a very rough micro-benchmark on the new `num_sql_threads` config option (added in #285)\r\n\r\n datasette --config num_sql_threads:1 fivethirtyeight.db\r\n\r\nThen\r\n\r\n ab -n 100 -c 10 'http://127.0.0.1:8011/fivethirtyeight-2628db9/twitter-ratio%2Fsenators'\r\n\r\n| Number of threads | Requests/second |\r\n|---|---|\r\n| 1 | 4.57 |\r\n| 3 | 9.77 |\r\n| 10 | 13.53 |\r\n| 20 | 15.24 \r\n| 50 | 8.21 | \r\n\r\nThis was on my early 2018 OS X laptop. Need to benchmark in other common environments before making a decision on changing the default. That said, the default of 3 was a number I plucked out of thin air.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/290/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null}