html_url,issue_url,id,node_id,user,created_at,updated_at,author_association,body,reactions,issue,performed_via_github_app
https://github.com/simonw/datasette/issues/1863#issuecomment-1331089156,https://api.github.com/repos/simonw/datasette/issues/1863,1331089156,IC_kwDOBm6k_c5PVs8E,9599,2022-11-29T18:08:53Z,2022-11-29T18:08:53Z,OWNER,"I do think this needs type checking - I just tried and you really can send a string to an integer column and have it work, which feels bad.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1330974099,https://api.github.com/repos/simonw/datasette/issues/1863,1330974099,IC_kwDOBm6k_c5PVQ2T,9599,2022-11-29T17:03:00Z,2022-11-29T17:11:05Z,OWNER,I've decided that I won't do that validation for the first version of this - I'm going to teach `dclient` to send the correct types instead: https://github.com/simonw/dclient/issues/6#issuecomment-1330963953,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1324539030,https://api.github.com/repos/simonw/datasette/issues/1863,1324539030,IC_kwDOBm6k_c5O8tyW,9599,2022-11-23T04:35:14Z,2022-11-23T04:35:14Z,OWNER,If I do that I should probably update `insert` to do those validation checks as well.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1324531750,https://api.github.com/repos/simonw/datasette/issues/1863,1324531750,IC_kwDOBm6k_c5O8sAm,9599,2022-11-23T04:20:47Z,2022-11-23T04:20:47Z,OWNER,"... which does imply that I'm going to do an extra layer of validation over what SQLite provides. SQLite will happily allow a text string to be added to a supposedly integer column. I'm not going to allow that - I'll return a validation error instead, unless the string can be safely coerced to the correct type.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1324531085,https://api.github.com/repos/simonw/datasette/issues/1863,1324531085,IC_kwDOBm6k_c5O8r2N,9599,2022-11-23T04:19:28Z,2022-11-23T04:19:28Z,OWNER,Had a design conversation with myself in https://github.com/simonw/dclient/issues/6 where I decided that the API should allow string values to be sent to integer columns which would be automatically converted *if possible to do so* - as an API usability feature.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1320563197,https://api.github.com/repos/simonw/datasette/issues/1863,1320563197,IC_kwDOBm6k_c5OtjH9,9599,2022-11-18T21:47:35Z,2022-11-18T21:48:07Z,OWNER,"Incomplete implementation of this view:
```python
class RowUpdateView(BaseView):
name = ""row-update""
def __init__(self, datasette):
self.ds = datasette
async def post(self, request):
database_route = tilde_decode(request.url_vars[""database""])
table = tilde_decode(request.url_vars[""table""])
try:
db = self.ds.get_database(route=database_route)
except KeyError:
return _error([""Database not found: {}"".format(database_route)], 404)
database_name = db.name
if not await db.table_exists(table):
return _error([""Table not found: {}"".format(table)], 404)
pk_values = urlsafe_components(request.url_vars[""pks""])
sql, params, pks = await row_sql_params_pks(db, table, pk_values)
results = await db.execute(sql, params, truncate=True)
rows = list(results.rows)
if not rows:
return _error([f""Record not found: {pk_values}""], 404)
# Ensure user has permission to update this row
if not await self.ds.permission_allowed(
request.actor, ""update-row"", resource=(database_name, table)
):
return _error([""Permission denied""], 403)
body = await request.post_body()
try:
data = json.loads(body)
except json.JSONDecodeError as e:
return _error([""Invalid JSON: {}"".format(e)])
if not isinstance(data, dict):
return _error([""JSON must be a dictionary""])
def update_row(conn):
sqlite_utils.Database(conn)[table].update(pk_values, updates)
await db.execute_write_fn(update_row)
result = {""ok"": True}
if data.get(""return""):
result[""row""] = {""row-here"": ""TODO""}
return Response.json(result, status=200)
```
This is before the refactor in:
- #1896","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1317755263,https://api.github.com/repos/simonw/datasette/issues/1863,1317755263,IC_kwDOBm6k_c5Oi1l_,9599,2022-11-16T22:24:59Z,2022-11-16T22:24:59Z,OWNER,"In trying to write this I realize that there's a lot of duplicated code with delete row, specifically around resolving the incoming URL into a row (or a database or a table).
Since this is so common, I think it's worth extracting the logic out first.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1315812212,https://api.github.com/repos/simonw/datasette/issues/1863,1315812212,IC_kwDOBm6k_c5ObbN0,9599,2022-11-15T20:12:02Z,2022-11-15T20:12:02Z,OWNER,"If the update succeeds it will return `{""ok"": true}`.
For consistency with `/db/table/-/insert` you can pass `""return"": true` and it will return a `""row""` key with the now-updated full row.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1315809867,https://api.github.com/repos/simonw/datasette/issues/1863,1315809867,IC_kwDOBm6k_c5ObapL,9599,2022-11-15T20:09:44Z,2022-11-15T20:09:44Z,OWNER,"I'm also not going to implement `""alter"": true` yet (which would add any missing columns based on the update) - I'll hold that off for a later feature.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1315809260,https://api.github.com/repos/simonw/datasette/issues/1863,1315809260,IC_kwDOBm6k_c5Obafs,9599,2022-11-15T20:09:11Z,2022-11-15T20:09:11Z,OWNER,"I'm going to use the error format I've been experimenting with here:
- #1875
```json
{
""type"": ""https://example.net/validation-error"",
""title"": ""Your request is not valid."",
""errors"": [
{
""detail"": ""must be a positive integer"",
""pointer"": ""#/age""
},
{
""detail"": ""must be 'green', 'red' or 'blue'"",
""pointer"": ""#/profile/color""
}
]
}
```
I'm not quite ready to commit to a `type` URL though, so I'll leave that to be solved later should I fully embrace that RFC.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1315808062,https://api.github.com/repos/simonw/datasette/issues/1863,1315808062,IC_kwDOBm6k_c5ObaM-,9599,2022-11-15T20:08:04Z,2022-11-15T20:08:04Z,OWNER,"The initial design I'm going to implement will look like this:
```
POST /db/table/1/-/update
Authorization: Bearer xxx
Content-Type: application/json
```
```json
{
""update"": {
""name"": ""New name""
}
}
```
Any fields that are not yet columns will return an error.
Should it enforce types, in as much as an integer column should have a JSON integer passed to it, or should it allow strings containing valid integers?
I'm going to allow strings, mainly as a workaround for the fact that JavaScript integers have a maximum size.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1302790013,https://api.github.com/repos/simonw/datasette/issues/1863,1302790013,IC_kwDOBm6k_c5Npv99,9599,2022-11-03T23:32:30Z,2022-11-03T23:32:30Z,OWNER,"I'm not going to allow updates to primary keys. If you need to do that, you can instead delete the record and then insert a new one with the new primary keys you wanted - or maybe use a custom SQL query.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1302785086,https://api.github.com/repos/simonw/datasette/issues/1863,1302785086,IC_kwDOBm6k_c5Npuw-,9599,2022-11-03T23:24:33Z,2022-11-03T23:24:56Z,OWNER,"Thinking more about validation: I'm considering if this should validate that columns which are defined as SQLite foreign keys are being updated to values that exist in those other tables.
I like the sound of this. It seems like a sensible default behaviour for Datasette. And it fits with the fact that Datasette treats foreign keys specially elsewhere in the interface.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1302760549,https://api.github.com/repos/simonw/datasette/issues/1863,1302760549,IC_kwDOBm6k_c5Npoxl,9599,2022-11-03T22:43:04Z,2022-11-03T23:21:31Z,OWNER,"The `id=(int, ...)` thing is weird, but is apparently Pydantic syntax for a required field?
https://cs.github.com/starlite-api/starlite/blob/28ddc847c4cb072f0d5d21a9ecd5259711f12ec9/docs/usage/11-data-transfer-objects.md#L161 confirms:
> 1. For required fields use a tuple of type + ellipsis, for example `(str, ...)`.
> 2. For optional fields use a tuple of type + `None`, for example `(str, None)`
> 3. To set a default value use a tuple of type + default value, for example `(str, ""Hello World"")`","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1302760382,https://api.github.com/repos/simonw/datasette/issues/1863,1302760382,IC_kwDOBm6k_c5Npou-,9599,2022-11-03T22:42:47Z,2022-11-03T22:42:47Z,OWNER,"```python
print(create_model('document', id=(int, ...), title=(str, None)).schema_json(indent=2))
```
```json
{
""title"": ""document"",
""type"": ""object"",
""properties"": {
""id"": {
""title"": ""Id"",
""type"": ""integer""
},
""title"": {
""title"": ""Title"",
""type"": ""string""
}
},
""required"": [
""id""
]
}
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,
https://github.com/simonw/datasette/issues/1863#issuecomment-1302759174,https://api.github.com/repos/simonw/datasette/issues/1863,1302759174,IC_kwDOBm6k_c5NpocG,9599,2022-11-03T22:40:47Z,2022-11-03T22:40:47Z,OWNER,"I'm considering Pydantic for this, see:
- https://github.com/simonw/datasette/issues/1882#issuecomment-1302716350
In particular the `create_model()` method: https://pydantic-docs.helpmanual.io/usage/models/#dynamic-model-creation
This would give me good validation. It would also, weirdly, give me the ability to output JSON schema. Maybe I could have this as the JSON schema for a row?
`/db/table/-/json-schema`","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1425029242,