id,node_id,number,title,user,state,locked,assignee,milestone,comments,created_at,updated_at,closed_at,author_association,pull_request,body,repo,type,active_lock_reason,performed_via_github_app,reactions,draft,state_reason
1421529723,I_kwDOBm6k_c5UutJ7,1850,Write API in Datasette core,9599,closed,0,,8658075,13,2022-10-24T22:13:24Z,2022-11-29T20:11:20Z,2022-11-29T20:11:20Z,OWNER,,"I need this for Datasette Cloud, and in thinking it through I realized that it's really time Datasette grew a default write API as well.

I'm going to mostly model this off `sqlite-utils`, since I've spent a bunch of time iterating on a pseudo-JSON API for that over the past few years (piping JSON to stdin etc).

I want this for Datasette 1.0. I'm going to be building it in the new [1.0-dev](https://github.com/simonw/datasette/tree/1.0-dev) branch, which is automatically deployed to https://latest-1-0-dev.datasette.io/ running on Cloud Run.

API features to build:

- [x] #1852
  - [x] #1856
  - [x] #1857
  - [x] #1858
  - [x] #1859
- [x] #1871
  - [x] #1888
- [x] #1868
- [x] #1851
- [x] #1863
- [x] #1864
- [x] #1866
- [x] https://github.com/simonw/datasette/issues/1882
- [x] #1862
- [x] #1874
  - [x] https://github.com/simonw/datasette/issues/1887
- [x] #1877

Bumped to later on:

- #1855
- #1878
- #1873
- #1875
- Make sure CORS works
- https://github.com/simonw/datasette/issues/1889
- Alter a table - `sqlite-utils transform` style (more powerful than straight ALTER)
- Execute SQL against a write connection
- Maybe even multiple write SQL statements bundled in a single transaction
- https://github.com/simonw/datasette/issues/1867
",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1850/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1468603401,I_kwDOBm6k_c5XiRwJ,1913,Release Datasette 1.0a0,9599,closed,0,,8658075,9,2022-11-29T19:41:42Z,2022-11-29T20:10:35Z,2022-11-29T20:10:35Z,OWNER,,"I attempted the release just now - https://github.com/simonw/datasette/releases/tag/1.0a0 -  and got an unexpected test failure:

https://github.com/simonw/datasette/actions/runs/3577355358/attempts/1

```
>       assert delete_response.status_code == 200
E       assert 404 == 200
E        +  where 404 = <Response [404 Not Found]>.status_code

/home/runner/work/datasette/datasette/tests/test_api_write.py:396: AssertionError
=========================== short test summary info ============================
FAILED tests/test_api_write.py::test_delete_row[compound_pk_table-row_for_create2-pks2-article,k] - assert 404 == 200
 +  where 404 = <Response [404 Not Found]>.status_code
```
I hit ""retry"" on that test but I expect it to fail again.

",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1913/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1432012302,I_kwDOBm6k_c5VWsYO,1877,Refactor and tidy up final write API code,9599,closed,0,,,1,2022-11-01T20:00:11Z,2022-11-29T19:44:16Z,2022-11-29T19:44:07Z,OWNER,,"- `views/table.py` has got a bit too big - I think the write classes should be pulled out into a separate module.
- [x] There's duplicate logic for deciding if the table and database exist and checking permissions",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1877/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1450312343,I_kwDOBm6k_c5WcgKX,1892,Merge 1.0-dev branch back to main,9599,closed,0,,8658075,3,2022-11-15T20:04:25Z,2022-11-29T19:40:23Z,2022-11-29T19:40:23Z,OWNER,,"I'm committed enough to the 1.0 work now that I'm ready for the `main` branch to reflect that instead.

If I need to make any dot-releases against 0.63 I can do those from a branch.",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1892/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1468592292,PR_kwDOBm6k_c5D6nzE,1912,Merge 1.0-dev (with initial write API) back into main,9599,closed,0,,,1,2022-11-29T19:31:21Z,2022-11-29T19:39:37Z,2022-11-29T19:39:36Z,OWNER,simonw/datasette/pulls/1912,"See:
- #1892

<!-- readthedocs-preview datasette start -->
----
:books: Documentation preview :books:: https://datasette--1912.org.readthedocs.build/en/1912/

<!-- readthedocs-preview datasette end -->",107914493,pull,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1912/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",0,
1450303205,I_kwDOBm6k_c5Wcd7l,1891,1.0a0 release notes,9599,closed,0,,8658075,4,2022-11-15T19:58:20Z,2022-11-29T19:23:41Z,2022-11-29T19:23:41Z,OWNER,,"This release will mainly help preview the new Datasette write API:
- #1850",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1891/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1425029275,I_kwDOBm6k_c5U8Dib,1864,Delete a single record from an existing table,9599,closed,0,,8658075,4,2022-10-27T04:53:22Z,2022-11-29T18:54:04Z,2022-11-29T18:54:04Z,OWNER,,"API design:
```
POST /db/table/row-pks/-/delete
Or...
DELETE /db/table/row-pks/-/delete
```
I'm just going to do `POST` for the moment, like I did here:
- #1874

Permission: `delete-row`

Still needed:

- [ ] Tests for rowid tables
- [ ] Tests for compound primary keys",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1864/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1468519699,I_kwDOBm6k_c5Xh9UT,1911,`/db/-/create` should support creating tables with compound primary keys,9599,closed,0,,8658075,2,2022-11-29T18:30:47Z,2022-11-29T18:50:58Z,2022-11-29T18:48:05Z,OWNER,,"Found myself needing this to write the tests for:
- #1864 ",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1911/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed
1425029242,I_kwDOBm6k_c5U8Dh6,1863,Update a single record in an existing table,9599,closed,0,,8658075,16,2022-10-27T04:53:17Z,2022-11-29T18:08:53Z,2022-11-29T18:06:37Z,OWNER,,"API design:

```
POST /db/table/row-pks/-/update
{
   ""field"": ""updated_value""
}
```
Only the fields that you pass will be updated.

Maybe this is the wrong design though? The design for insert currently looks like this:

- https://github.com/simonw/datasette/issues/1851#issuecomment-1294224185

```
POST /db/table/-/insert
Authorization: Bearer xxx
Content-Type: application/json
{
  ""row"": {
    ""id"": 1,
    ""name"": ""New name""
  }
}
```
I could use the same format for `/-/update`, but in this case the API doesn't require you to pass every field so `""row""` doesn't seem like the right key.

I think I'll go with this:

```
POST /db/table/1/-/update
Authorization: Bearer xxx
Content-Type: application/json
{
  ""update"": {
    ""name"": ""New name""
  }
}
```
The benefit of having an `""update""` key is that it allows me to use other keys in the future. Maybe a `""alter"": true` key to indicate that new columns should be added if they are missing.",107914493,issue,,,"{""url"": ""https://api.github.com/repos/simonw/datasette/issues/1863/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed