sha,message,author_date,committer_date,raw_author,raw_author_label,raw_committer,raw_committer_label,repo,repo_label,author,author_label,committer,committer_label b2dee11fcd989d9e2a7bf4de1e23dbc320c05013,"Databases now get distinct colours A left border based on their content hash. Closes #31",2017-11-09T14:12:42Z,2017-11-09T14:14:40Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw abb591d83264bbf11a5eb9daf03011d051e8f833,"Added --reload argument to 'immutabase serve' command Uses hupper to restart the server when the code changes. Useful for development. Depends on https://pypi.python.org/pypi/hupper",2017-11-09T13:46:16Z,2017-11-09T14:14:26Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 8af7bc100c681975894f49f4ffd6d26a06e93f60,"Added a MANIFEST.in Now python setup.py bdist_wheel creates a .whl that includes the CSS.",2017-11-09T02:39:42Z,2017-11-09T02:39:42Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 7e0cedae3d920797f6f9411aea90a2b1d86ac9c7,"Now using bootstrap 4 beta Refs #16",2017-11-06T02:49:07Z,2017-11-06T02:49:07Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 9e9e9613907b6a2a8a051fdda93c0d26344ee110,Fixed error in RowView,2017-11-06T02:38:06Z,2017-11-06T02:38:06Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 25c241fa5a0f8868e3c1bc5be4f5888caa47d864,Renamed project to immutabase,2017-11-06T02:32:13Z,2017-11-06T02:32:13Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw a0bb9da17fb95ac5e3bcd3c8d800d33c25a71bbc,"Now requires DB files to be passed as arguments Refs #40",2017-11-06T02:24:43Z,2017-11-06T02:24:43Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 186c513a61a091b9f83d788e25b08f41a84ed9a3,"Support parameterized SQL and block potentially harmful queries You can now call arbitrary SQL like this: /flights?sql=select%20*%20from%20airports%20where%20country%20like%20:c&c=iceland Unescaped, those querystring params look like this: sql = select * from airports where country like :c c = iceland So SQL can be constructed with named parameters embedded in it, which will then be read from the querystring and correctly escaped. This means we can aggressively filter the SQL parameter for potentially dangerous syntax. For the moment we enforce that it starts with a SELECT statement and we ban the sequence ""pragma"" from it entirely. If you need to use pragma in a query, you can use the new named parameter mechanism. Fixes #39",2017-11-05T02:49:18Z,2017-11-05T02:49:18Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 31b21f5c5e15fc3acab7fabb170c1da71dc3c98c,"Moved all SQLite queries to threads SQLite operations are blocking, but we're running everything in Sanic, an asyncio web framework, so blocking operations are bad - a long-running DB operation could hold up the entire server. Instead, I've moved all SQLite operations into threads. These are managed by a concurrent.futures ThreadPoolExecutor. This means I can run up to X queries in parallel, and I can continue to queue up additional incoming HTTP traffic while the threadpool is busy. Each thread is responsible for managing its own SQLite connections - one per database. These are cached in a threadlocal. Since we are working with immutable, read-only SQLite databases it should be safe to share SQLite objects across threads. On this assumption I'm using the check_same_thread=False option. Opening a database connection looks like this: conn = sqlite3.connect( 'file:filename.db?immutable=1', uri=True, check_same_thread=False, ) The following articles were helpful in figuring this out: * https://pymotw.com/3/asyncio/executors.html * https://marlinux.wordpress.com/2017/05/19/python-3-6-asyncio-sqlalchemy/ Closes #45. Refs #38.",2017-11-05T02:21:44Z,2017-11-05T02:21:44Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 1fc75809a6aa17860944b4cc3a4d7175cd53b1f4,"Refactored everything into a factory function I now call a factory function to construct the Sanic app: app = app_factory(files) This allows me to pass additional arguments to it, e.g. the files to serve. Also refactored my class-based views to accept jinja as an argument, e.g: app.add_route( TableView.as_view(jinja), '//' )",2017-11-05T02:13:44Z,2017-11-05T02:13:44Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 0ac8bbce2e73c0759ec48661a7b740d2c368b2a2,"Default subcommand is now serve Using click-default-group: https://github.com/click-contrib/click-default-group Also removed requirements.txt in favour of setup.py",2017-11-04T23:53:50Z,2017-11-04T23:53:50Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw edaa10587e60946e0c1935333f6b79553db33798,Configured Travis CI,2017-11-04T23:47:46Z,2017-11-04T23:47:46Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw be768f26d09fa060b1ca71785ff546dd572f3fbc,python setup.py test now runs the tests,2017-11-04T23:40:27Z,2017-11-04T23:40:27Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 2c625e31ed018f929223918240603bf2a80e665c,"Fixed bug on Row page with tables containing spaces We were attempting to run this SQL: select * from ""Order%20Details"" where ... On this page: http://0.0.0.0:8877/northwind-40d049b/Order%20Details/10250,41",2017-10-27T07:16:18Z,2017-10-27T07:16:18Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 1592fd0419f374de201926d3ba67fbf1522eed13,"Started work on cli, which also meant adding setup.py I'm using click, and click recommends using a setup.py - so I've added one of those. I also refactored code into a new datasite package. It's not quite deploying to now properly at the moment though - I seem to have messed up the path handling a bit. Also snuck in a new template for the ""Row"" view. Refs #40",2017-10-27T07:08:24Z,2017-10-27T07:08:24Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 2a9799bae651558a23ae5074edad7cc13ff0fbdc,"Implemented database summary on index page Closes #41",2017-10-27T04:05:13Z,2017-10-27T04:05:17Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 3cce63b59851495b6d9d38936356e21ea8fbad3a,"URL to allow direct database download It's just the database URL with .db on the end, e.g. /flights.db Closes #19",2017-10-25T15:19:32Z,2017-10-25T15:19:32Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw f1b0521810bbc467721e4dcc5a2ff1bf2a1ddbb8,Preserve .json through redirects,2017-10-25T15:01:22Z,2017-10-25T15:01:22Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw d94d4465d7e72e668122f81206397f4f20cf555b,"Double quote around column names This means filters still work even with column names that contain spaces",2017-10-25T14:47:20Z,2017-10-25T14:47:20Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw e55bc3b2fa6e1e8be7b7c1f5b6cb3764713b6faa,th align left for all tables,2017-10-25T14:46:38Z,2017-10-25T14:46:38Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 1c5977961f596dae5aaa18c8b2d7a10e9f42a543,Added glob and like lookups - refs #23,2017-10-25T01:53:01Z,2017-10-25T01:53:01Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 630b40038ef31b351abc2e39c3a0c7b3648814f8,"Added support for gt, gte, lt, lte lookups Refs #23",2017-10-25T01:46:49Z,2017-10-25T01:46:55Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 6823b094066c5cb1dcd3581da2ed877ed72298b7,"Set time limit of 1000ms on SQL queries Using the (undocumented in the Python docs) fact that if you return 1 from a set_progress_handler callback, SQLite will cancel the current query. Closes #35",2017-10-25T01:34:54Z,2017-10-25T01:34:54Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 2fe94641b0b2dc291d1fce3dad0fbf96294b3a32,"Don't try to show row counts for views Also handle tables/views with spaces in their name in the URL.",2017-10-25T01:33:12Z,2017-10-25T01:33:12Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw bd5f3b2ba1a627383d512d613b77d15501dfccc4,Show time taken at bottom of table page,2017-10-25T01:31:54Z,2017-10-25T01:31:54Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 3eb79e1a5fa4c164a224ae0adbe0ea16fde35758,Show total row count at top of table page,2017-10-25T01:31:43Z,2017-10-25T01:31:43Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw eef213ab4d57622dfc60c8655c0c7a18afcc844f,Show total number of rows in table,2017-10-25T00:11:36Z,2017-10-25T00:11:36Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 1ae8ea0f03cfb9f25b1e25f3194c456c3649789c,"Started implementing ?name__contains=X filters So far we support __contains=, __startswith=, __endswith= and __exact= Refs #23",2017-10-25T00:06:23Z,2017-10-25T00:06:23Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 4c7379a898df426af0c31159e5cb06d672189301,"Don't crash on weird character encodings Expecting SQLite columns to all be valid utf8 doesn't work, because we are deailing with all kinds of databases. Instead, we now use the 'replace' encoding mode to replace any non-UTF8 characters with a [X] character.",2017-10-25T00:01:34Z,2017-10-25T00:01:34Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw c371f06fdea413cfb00aa8f81b7a5535a7ecdbc4,Include took_ms in JSON output,2017-10-24T23:55:53Z,2017-10-24T23:55:53Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 2a09d3708777116daedc548078a662086552523f,Allow views to be browsed as well as tables,2017-10-24T23:55:08Z,2017-10-24T23:55:08Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 02b1814fcfdc61b1b69b5955f2b60252ff10cde9,"Redirects now preserve query string Fixes #28",2017-10-24T23:54:26Z,2017-10-24T23:54:26Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 5f806880c9766daf09fc9535171637ebb8224cab,Correctly JSON serialize sqlite3.Cursor,2017-10-24T23:53:21Z,2017-10-24T23:53:21Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw bc9379aabcedce7fbc661ac15008d8801199a045,"Added .jsono extension Returns JSON key/value objects for each row instead of lists of values. Closes #6",2017-10-24T15:07:52Z,2017-10-24T15:07:52Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw f643f7aee1b3d29df82b93a6560887a35b7a2f13,"base64 encode bytestrings from DB in JSON Fixes #29",2017-10-24T14:58:41Z,2017-10-24T14:58:41Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw b46e370ee6126aa2fa85cf789a31da38aed98496,"Link to pages-per-row Closes #1",2017-10-24T14:10:58Z,2017-10-24T14:10:58Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 6a9fdcc0718aea2cbc01ae4d60b9a1fba3601a66,"Added addressable page per row Refs #1 - only exists for tables with introspectable primary keys. Still need to link to this page. Also added first unit tests - refs #9",2017-10-24T05:54:58Z,2017-10-24T05:54:58Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 606ff9e35e007ae58a491d417f47779034bacabc,"python app.py --build to generate build-metadata.json This is now run by the Dockerfile to build this at compile time.",2017-10-24T05:53:13Z,2017-10-24T05:53:13Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw b20d7119e4f6506cdb9d5d11322e28130823adfd,Implemented template inheritance and brought back errors,2017-10-24T02:56:27Z,2017-10-24T02:56:27Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 0fa177269767e5e55c863382333fde627d2b7074,"Allow ?sql= argument against database e.g. /database-234324?sql=select * from table limit 1",2017-10-24T02:48:56Z,2017-10-24T02:48:56Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 255e2611e5c3cfdda76c9da7abdbe5af976044ac,"CORS headers for JSON responses Access-Control-Allow-Origin: *",2017-10-24T02:48:06Z,2017-10-24T02:48:06Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 12f7e1dc5624d14f644abead18bd90b420b6d97e,"Hashed URLs now have far-future cache expiry Since the URL now includes a hash of the database, we can return a Cache- Control: max-age=31536000 header for every response. The exception is our 302 redirects. These we now serve with a Link: header that tells any HTTP/2 server-push aware fronting proxies (such as Cloudfront) to push the target of the redirect. Closes #4",2017-10-24T02:36:44Z,2017-10-24T02:36:44Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 9d219140694551453bfa528e0624919eb065f9d6,"Refactored to use class based views Closes #22",2017-10-24T02:25:48Z,2017-10-24T02:25:48Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw b2372605d63248f422b6e67cb5c392236a3aa612,"Implemented multi-db support plus initial URL structure Refs #24 Fixes #15",2017-10-24T02:00:37Z,2017-10-24T02:00:37Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw 6a0c5de6154893eb4269dc7b1f160726ec6395f2,"ensure_build_metadata() function for metadata This will be run at compile time - the goal is to generate a build- metadata.json file with a bunch of useful facts about the databases that could be expensive to generate at run-time. Example metadata: { ""flights"": { ""file"": ""flights.db"", ""tables"": { ""airlines"": 6048, ""airports"": 8107, ""routes"": 67663 }, ""hash"": ""07d1283e07786b1235bb7041ea445ae103d1571565580a29eab0203c555725fd"" } So far we have a sha256 hash of the database file itself, plus a row count for each table. Fixes #11",2017-10-23T16:02:40Z,2017-10-23T16:02:40Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw f571b19d8a5fd3a19fdf679421fd55a8edbf5295,"sqlerrors() decorator catching and returning useful errors Closes #8",2017-10-23T15:28:00Z,2017-10-23T15:28:00Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw de04d7a854d71003ffcf98028eab976a936c2dba,Initial working proof of concept,2017-10-23T00:41:19Z,2017-10-23T00:41:19Z,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,2946d096d0cdefdc017559e6b57e87658736e843,Simon Willison,107914493,datasette,9599,simonw,9599,simonw