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/1890#issuecomment-1316242752,https://api.github.com/repos/simonw/datasette/issues/1890,1316242752,IC_kwDOBm6k_c5OdEVA,9599,2022-11-16T03:10:52Z,2022-11-16T03:12:47Z,OWNER,"https://bugs.webkit.org/show_bug.cgi?id=201768 - "" Datalist option's label not used"" - marked as RESOLVED FIXED on March 31st 2020.
The commit: https://trac.webkit.org/changeset/259330/webkit
And here's the test mirrored on GitHub: https://cs.github.com/qtwebkit/webkit-mirror/blob/cc3fcd0b4bad1f7cf77c26e34aa01d16618d6d5e/LayoutTests/fast/forms/datalist/datalist-option-labels.html?q=datalist-option-labels.html","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1448143294,
https://github.com/simonw/sqlite-utils/issues/512#issuecomment-1316437748,https://api.github.com/repos/simonw/sqlite-utils/issues/512,1316437748,IC_kwDOCGYnMM5Odz70,9599,2022-11-16T06:24:31Z,2022-11-16T06:24:31Z,OWNER,"```
sqlite-utils % pipx run no_implicit_optional .
Calculating full-repo metadata...
Executing codemod...
11.43s 98% complete, 0.24s estimated for 5 files to go...
```
Then:
```
Finished codemodding 239 files!
- Transformed 239 files successfully.
- Skipped 0 files.
- Failed to codemod 0 files.
- 0 warnings were generated.
```
Here's the diff:
```diff
diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py
index a06f4b7..e819d17 100644
--- a/sqlite_utils/db.py
+++ b/sqlite_utils/db.py
@@ -297,12 +297,12 @@ class Database:
def __init__(
self,
- filename_or_conn: Union[str, pathlib.Path, sqlite3.Connection] = None,
+ filename_or_conn: Optional[Union[str, pathlib.Path, sqlite3.Connection]] = None,
memory: bool = False,
- memory_name: str = None,
+ memory_name: Optional[str] = None,
recreate: bool = False,
recursive_triggers: bool = True,
- tracer: Callable = None,
+ tracer: Optional[Callable] = None,
use_counts_table: bool = False,
):
assert (filename_or_conn is not None and (not memory and not memory_name)) or (
@@ -341,7 +341,7 @@ class Database:
self.conn.close()
@contextlib.contextmanager
- def tracer(self, tracer: Callable = None):
+ def tracer(self, tracer: Optional[Callable] = None):
""""""
Context manager to temporarily set a tracer function - all executed SQL queries will
be passed to this.
@@ -378,7 +378,7 @@ class Database:
def register_function(
self,
- fn: Callable = None,
+ fn: Optional[Callable] = None,
deterministic: bool = False,
replace: bool = False,
name: Optional[str] = None,
@@ -879,7 +879,7 @@ class Database:
pk: Optional[Any] = None,
foreign_keys: Optional[ForeignKeysType] = None,
column_order: Optional[List[str]] = None,
- not_null: Iterable[str] = None,
+ not_null: Optional[Iterable[str]] = None,
defaults: Optional[Dict[str, Any]] = None,
hash_id: Optional[str] = None,
hash_id_columns: Optional[Iterable[str]] = None,
@@ -1129,7 +1129,7 @@ class Database:
sql += "" [{}]"".format(name)
self.execute(sql)
- def init_spatialite(self, path: str = None) -> bool:
+ def init_spatialite(self, path: Optional[str] = None) -> bool:
""""""
The ``init_spatialite`` method will load and initialize the SpatiaLite extension.
The ``path`` argument should be an absolute path to the compiled extension, which
@@ -1182,7 +1182,7 @@ class Queryable:
def count_where(
self,
- where: str = None,
+ where: Optional[str] = None,
where_args: Optional[Union[Iterable, dict]] = None,
) -> int:
""""""
@@ -1213,12 +1213,12 @@ class Queryable:
def rows_where(
self,
- where: str = None,
+ where: Optional[str] = None,
where_args: Optional[Union[Iterable, dict]] = None,
- order_by: str = None,
+ order_by: Optional[str] = None,
select: str = ""*"",
- limit: int = None,
- offset: int = None,
+ limit: Optional[int] = None,
+ offset: Optional[int] = None,
) -> Generator[dict, None, None]:
""""""
Iterate over every row in this table or view that matches the specified where clause.
@@ -1251,11 +1251,11 @@ class Queryable:
def pks_and_rows_where(
self,
- where: str = None,
+ where: Optional[str] = None,
where_args: Optional[Union[Iterable, dict]] = None,
- order_by: str = None,
- limit: int = None,
- offset: int = None,
+ order_by: Optional[str] = None,
+ limit: Optional[int] = None,
+ offset: Optional[int] = None,
) -> Generator[Tuple[Any, Dict], None, None]:
""""""
Like ``.rows_where()`` but returns ``(pk, row)`` pairs - ``pk`` can be a single value or tuple.
@@ -1345,7 +1345,7 @@ class Table(Queryable):
pk: Optional[Any] = None,
foreign_keys: Optional[ForeignKeysType] = None,
column_order: Optional[List[str]] = None,
- not_null: Iterable[str] = None,
+ not_null: Optional[Iterable[str]] = None,
defaults: Optional[Dict[str, Any]] = None,
batch_size: int = 100,
hash_id: Optional[str] = None,
@@ -1545,7 +1545,7 @@ class Table(Queryable):
pk: Optional[Any] = None,
foreign_keys: Optional[ForeignKeysType] = None,
column_order: Optional[List[str]] = None,
- not_null: Iterable[str] = None,
+ not_null: Optional[Iterable[str]] = None,
defaults: Optional[Dict[str, Any]] = None,
hash_id: Optional[str] = None,
hash_id_columns: Optional[Iterable[str]] = None,
@@ -2464,7 +2464,7 @@ class Table(Queryable):
columns: Optional[Iterable[str]] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
- where: str = None,
+ where: Optional[str] = None,
where_args: Optional[Union[Iterable, dict]] = None,
quote: bool = False,
) -> Generator[dict, None, None]:
@@ -2527,7 +2527,7 @@ class Table(Queryable):
def delete_where(
self,
- where: str = None,
+ where: Optional[str] = None,
where_args: Optional[Union[Iterable, dict]] = None,
analyze: bool = False,
) -> ""Table"":
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450952393,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316253186,https://api.github.com/repos/simonw/datasette/issues/1893,1316253186,IC_kwDOBm6k_c5OdG4C,9599,2022-11-16T03:16:36Z,2022-11-16T03:16:36Z,OWNER,Yeah I haven't written this down anywhere but Datasette definitely has an undocumented preference for lower-case SQL.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317314064,https://api.github.com/repos/simonw/datasette/issues/1893,1317314064,IC_kwDOBm6k_c5OhJ4Q,95570,2022-11-16T16:36:46Z,2022-11-16T16:36:46Z,CONTRIBUTOR,"With
```patch
diff --git a/datasette/templates/_codemirror_foot.html b/datasette/templates/_codemirror_foot.html
index ed709b3..74fe18e 100644
--- a/datasette/templates/_codemirror_foot.html
+++ b/datasette/templates/_codemirror_foot.html
@@ -7,7 +7,11 @@
sqlFormat.hidden = false;
}
if (sqlInput) {
- var editor = (window.editor = cm.editorFromTextArea(sqlInput));
+ var editor = (window.editor = cm.editorFromTextArea(sqlInput, {
+ schema: {
+ compound_three_primary_keys: [""pk1"", ""pk2"", ""pk3"", ""content""],
+ },
+ }));
```
we get table autocompletion and column completion if you name the table in the query (see screencast). I do see bugs with escaped table names like `""'123_starts_with_digits'"": [""col1"", ""col2""]` or `""[123_starts_with_digits]"": [""col1"", ""col2""]` where it doesn't seem to pick up the column names though. I think it needs some further testing and debugging.
https://user-images.githubusercontent.com/95570/202238521-e613b4e2-ba92-4418-9068-fc022edaee93.mp4
","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316243602,https://api.github.com/repos/simonw/datasette/issues/1893,1316243602,IC_kwDOBm6k_c5OdEiS,95570,2022-11-16T03:11:46Z,2022-11-16T03:11:46Z,CONTRIBUTOR,Was just reviewing the SQL options and there's an [upperCaseKeywords](https://github.com/codemirror/lang-sql#user-content-sqlconfig.uppercasekeywords) if we'd rather have SELECT vs select. Datasette seems to prefer lowercase so probably best to keep it as-is,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317456909,https://api.github.com/repos/simonw/datasette/issues/1893,1317456909,IC_kwDOBm6k_c5OhswN,9599,2022-11-16T18:17:39Z,2022-11-16T18:17:39Z,OWNER,"Tiny feature request (since you're in this code already) - I keep hitting Command+Enter on my macOS keyboard to submit the query, but the correct shortcut is Shift+Enter. Would be great if both worked!","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316231560,https://api.github.com/repos/simonw/datasette/issues/1893,1316231560,IC_kwDOBm6k_c5OdBmI,9599,2022-11-16T02:59:00Z,2022-11-16T02:59:00Z,OWNER,"The resize handle doesn't appear on Mobile Safari on iPhone - I don't think that particularly matters though.
The textarea does get a weird border around it when focused on iPhone though.
Focused:
![BF34E8FB-E35C-4CAB-9BFB-8EEF7E29B16C_1_201_a](https://user-images.githubusercontent.com/9599/202072748-c85bab94-a039-4ed6-8185-3cac25c78ed3.jpeg)
Not focused:
![31A5CF38-D540-4A1A-8A7D-E29453D150F4_1_201_a](https://user-images.githubusercontent.com/9599/202072744-d9f0ea62-13b7-46ff-afe1-6d88d7fb8b53.jpeg)
","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/sqlite-utils/issues/512#issuecomment-1316530539,https://api.github.com/repos/simonw/sqlite-utils/issues/512,1316530539,IC_kwDOCGYnMM5OeKlr,9599,2022-11-16T07:49:50Z,2022-11-16T07:49:50Z,OWNER,Tests passed.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450952393,
https://github.com/simonw/sqlite-utils/issues/512#issuecomment-1316447182,https://api.github.com/repos/simonw/sqlite-utils/issues/512,1316447182,IC_kwDOCGYnMM5Od2PO,9599,2022-11-16T06:32:31Z,2022-11-16T06:32:31Z,OWNER,"Test failed again: https://github.com/simonw/sqlite-utils/actions/runs/3476950474/jobs/5812663096
`E: Failed to fetch http://azure.archive.ubuntu.com/ubuntu/pool/universe/s/spatialite/libsqlite3-mod-spatialite_4.3.0a-6build1_amd64.deb Unable to connect to azure.archive.ubuntu.com:http:`
That looks like an intermittent error. I'll try running it again in the morning.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450952393,
https://github.com/simonw/datasette/issues/1896#issuecomment-1317757112,https://api.github.com/repos/simonw/datasette/issues/1896,1317757112,IC_kwDOBm6k_c5Oi2C4,9599,2022-11-16T22:26:52Z,2022-11-16T22:33:13Z,OWNER,"Some ideas from walking the dog:
Challenge: standard URL routing of request to database/table/row
Standardize on the named components of the URL patterns - `database`, `table`, `pks`
Async function that takes the request and the Datasette instance and returns a Resolved instance with:
```
.level - database or table or row (better name?)
.database - the name of the database
.db - the database object
.table - the name of the table (or view)
.is_view perhaps?
.pk_values if it's a row
```
Should this attempt to resolve names queries too?
```
.where_sql - the where fragment you use
.where_params - accompanying dictionary
await datasette.resolve_request(request)
```
Or even better three methods:
```python
datasette.resolve_database(request)
datasette.resolve_table(request)
datasette.resolve_row(request)
```
These can be typed correctly
Methods raise `NotFound` if not found","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1452364777,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316401895,https://api.github.com/repos/simonw/datasette/issues/1893,1316401895,IC_kwDOBm6k_c5OdrLn,9599,2022-11-16T05:50:40Z,2022-11-16T05:50:40Z,OWNER,"So I think our dialect (at least to start with) should be:
```
keywords:
""and as asc between by case cast current current_date current_time current_timestamp desc distinct each else escape except exists explain filter first for from full generated group having if in index inner intersect into isnull join last left like limit not null or order outer over pragma primary query raise range regexp right rollback row select set table temp temporary then to union unique using values view virtual when where"",
// https://www.sqlite.org/datatype3.html
types: ""null integer real text blob"",
builtin:
""""
```
I left `builtin` blank here because I don't think we need any of those things at all.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317834838,https://api.github.com/repos/simonw/datasette/issues/1893,1317834838,IC_kwDOBm6k_c5OjJBW,95570,2022-11-16T23:50:58Z,2022-11-16T23:50:58Z,CONTRIBUTOR,"Should we empty out the fixture schema to avoid fixture autocomplete showing up on live databases in the interim, or are you planning to tackle #1897 shortly?","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316412234,https://api.github.com/repos/simonw/datasette/issues/1893,1316412234,IC_kwDOBm6k_c5OdttK,9599,2022-11-16T06:00:39Z,2022-11-16T06:01:36Z,OWNER,"Should note though that this is a classic example of GPT-3 making stuff up in places.
> current: Returns the current date, time, or timestamp
`select current` throws an error for me: https://latest.datasette.io/_memory?sql=select+current
`select current_date, current_time, current_timestamp` works though: https://latest.datasette.io/_memory?sql=select+current_date%2C+current_time%2C+current_timestamp
So let's drop `current` from the list. I'm OK with it though, I think it's likely good enough for the first attempt at this.
We should drop `temp` and `temporary` too.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316141764,https://api.github.com/repos/simonw/datasette/issues/1893,1316141764,IC_kwDOBm6k_c5OcrrE,9599,2022-11-16T01:26:59Z,2022-11-16T01:26:59Z,OWNER,"Resizing works great for me - and the page automatically sizes the editor to fit an existing query, e.g. on https://datasette-pr-1893.vercel.app/fixtures?sql=select+id%2C+content%2C+content2%0D%0A++from+primary_key_multiple_columns_explicit_label%0D%0A++order+by+id%0D%0A++limit+101","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317522323,https://api.github.com/repos/simonw/datasette/issues/1893,1317522323,IC_kwDOBm6k_c5Oh8uT,95570,2022-11-16T18:59:49Z,2022-11-16T18:59:49Z,CONTRIBUTOR,Or I guess you could return only the escaped table name and then we could derive the unescaped from the client side (removing the outer `[]` when present),"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316232588,https://api.github.com/repos/simonw/datasette/issues/1893,1316232588,IC_kwDOBm6k_c5OdB2M,9599,2022-11-16T03:00:04Z,2022-11-16T03:00:04Z,OWNER,"Oops, the tests are failing because of a test failure I introduced here:
- #1890","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/issues/1890#issuecomment-1316233532,https://api.github.com/repos/simonw/datasette/issues/1890,1316233532,IC_kwDOBm6k_c5OdCE8,9599,2022-11-16T03:00:58Z,2022-11-16T03:00:58Z,OWNER,"Oops, introduced a test failure:
```
def test_table_html_foreign_key_facets(app_client):
response = app_client.get(
""/fixtures/foreign_key_references?_facet=foreign_key_with_blank_label""
)
assert response.status == 200
> assert (
'
' in '\n\n\n fixtures: foreign_key_references: 2 rows\n \n\n\n\n\n'
E + where '\n\n\n fixtures: foreign_key_references: 2 rows\n \n\n\n\n\n' = .text
```
Need to fix this test:
https://github.com/simonw/datasette/blob/eac028d3f77aa5473a5fcf59240635a1bca80f7d/tests/test_table_html.py#L616-L624","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1448143294,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317831425,https://api.github.com/repos/simonw/datasette/issues/1893,1317831425,IC_kwDOBm6k_c5OjIMB,9599,2022-11-16T23:47:05Z,2022-11-16T23:47:05Z,OWNER,"OK, let's do it! Thanks so much for this.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316400688,https://api.github.com/repos/simonw/datasette/issues/1893,1316400688,IC_kwDOBm6k_c5Odq4w,9599,2022-11-16T05:49:31Z,2022-11-16T05:49:31Z,OWNER,"OK, I decided to play around with GPT-3 for this. https://beta.openai.com/playground
I prompted:
```
For each keyword say it it can be used in a SQLite select statement: and as asc between by case cast
cross current current_date current_time current_timestamp desc detach distinct each else end escape
except exclude exclusive exists explain fail filter first following for foreign from full generated glob
group groups having if ignore immediate in index indexed initially inner insert instead intersect into
is isnull join key last left like limit match materialized natural no not nothing notnull null nulls of
offset on or order others outer over partition plan pragma preceding primary query raise range recursive
references regexp reindex release rename replace restrict returning right rollback row rows savepoint
select set table temp temporary then ties to transaction trigger unbounded union unique update using
vacuum values view virtual when where window with without
- and: yes
- as: yes
- asc: yes
- between: yes
- by: yes
- case: yes
- cast: yes
- current: yes
- current_date: yes
- current_time: yes
- current_timestamp: yes
- desc: yes
- detach: no
- distinct: yes
- each: yes
- else: yes
- end: yes
- escape: yes
- except: no
- exclude: yes
- exclusive: no
```
Having given it these examples I ran it a few times:
```
- exists: yes
- explain: no
- fail: no
- filter: yes
- first: yes
- following: no
- for: yes
- foreign: no
- from: yes
- full: no
- generated: no
- glob: yes
- group: yes
- groups: no
- having: yes
- if: yes
- ignore: no
- immediate: no
- in: yes
- index: yes
- indexed: no
- initially: no
- inner: no
- insert: no
- instead: no
- intersect: no
- into: yes
- is: yes
- isnull: yes
- join: yes
- key: no
- last: yes
- left: yes
- like: yes
- limit: yes
- match: no
- materialized: no
-natural: yes
- no: no
- not: no
- nothing: no
- notnull: yes
- null: yes
- nulls: yes
- of: no
- offset: yes
- on: yes
- or: yes
- order: yes
- others: yes
- outer: no
- over: no
- partition: no
- pragma: no
- preceding: no
- primary: no
- query: no
- raise: no
- range: no
- recursive: no
- references: no
- regexp: yes
- reindex: no
- release: no
- rename: no
- replace: no
- restrict: no
- returning: yes
- right: yes
- rollback: no
- row: yes
- rows: no
- savepoint: no
- select: yes
- set: no
- table: yes
- temp: yes
- temporary: yes
- then: yes
- ties: no
- to: yes
- transaction: no
- trigger: no
- unbounded: no
- union: yes
- unique: yes
- update: no
- using: yes
- vacuum: no
- values: yes
- view: yes
- virtual: no
- when: yes
- where: yes
- window: no
- with: yes
- without: no
```
I added this:
```
A space separated list of all of the keywords for which the answer was yes:
```
It replied:
```
and as asc between by case cast current current_date current_time current_timestamp desc distinct each else escape except exists explain filter first for from full generated group having if in index inner intersect into isnull join last left like limit not null or order outer over pragma primary query raise range regexp right rollback row select set table temp temporary then to union unique using values view virtual when where
```
Then I tried doing this:
```
Produce a short summary of how each of those are used:
- and:
```
This kind of worked too! It ended up defining every keyword, not just the ones for which the ""is it used in select"" was ""yes"", but it gave me this list:
> - and: Used to combine multiple conditions in a WHERE clause
> - as: Rename a column or table in the output of a query
> - asc: Sort results in ascending order
> - between: Used in a WHERE clause to specify a range
> - by: Specifies how to sort the results of a query
> - case: Used to create different outputs based on conditions
> - cast: Converts a value from one data type to another
> - current: Returns the current date, time, or timestamp
> - current_date: Returns the current date
> - current_time: Returns the current time
> - current_timestamp: Returns the current timestamp
> - desc: Sort results in descending order
> - distinct: Selects only unique values
> - each: Used with aggregate functions
> - else: Used with the CASE statement
> - escape: Used to escape special characters in a string
> - except: Returns all rows from the first query that are not in the second query
> - exists: Used with subqueries
> - explain: Analyzes a query and returns information about it
> - fail: Used with the ON CONFLICT clause
> - filter: Used to specify conditions for aggregate functions
> - first: Used to specify conditions for aggregate functions
> - following: Used with window functions
> - for: Used to specify conditions for aggregate functions
> - foreign: Creates a foreign key
> - from: Specifies the table(s) to select data from
> - full: Used with outer joins
> - generated: Used with generated columns
> - glob: Used to match a string with a pattern
> - group: Groups together rows that have the same values
> - groups: Used with aggregate functions
> - having: Specifies conditions for groups
> - if: Used with the ON CONFLICT clause
> - ignore: Used with the ON CONFLICT clause
> - immediate: Used with the ON CONFLICT clause
> - in: Used to check if a value is in a list
> - index: Creates an index on a column or columns
> - indexed: Used with the ON CONFLICT clause
> - initially: Used with the ON CONFLICT clause
> - inner: Creates an inner join
> - insert: Inserts new data into a table
> - instead: Used with triggers
> - intersect: Returns all rows that are in both queries
> - into: Specifies the table to insert data into
> - is: Used to compare values
> - isnull: Checks if a value is null
> - join: Joins two or more tables together
> - key: Creates a primary key or unique key
> - last: Used to specify conditions for aggregate functions
> - left: Creates a left join
> - like: Checks if a value matches a pattern
> - limit: Specifies the maximum number of rows to return
> - not: Negates a condition
> - null: Specifies a null value
> - nulls: Used with the ORDER BY clause
> - of: Used with window functions
> - offset: Specifies the number of rows to skip
> - on: Specifies conditions for a join
> - or: Checks if either condition is true
> - order: Specifies how to sort the results of a query
> - others: Used with the CASE statement
> - outer: Creates an outer join
> - over: Used with window functions
> - partition: Used with window functions
> - pragma: Used to query or change various internal settings
> - preceding: Used with window functions
> - primary: Creates a primary key
> - query: Used with the ON CONFLICT clause
> - raise: Used with the ON CONFLICT clause
> - range: Used with window functions
> - recursive: Used with common table expressions
> - references: Creates a foreign key
> - regexp: Checks if a value matches a regular expression
> - reindex: Recreates an index
> - release: Used with savepoints
> - rename: Changes the name of a table or column
> - replace: Inserts new data into a table or updates existing data
> - restrict: Used with savepoints
> - returning: Returns data from inserted or updated rows
> - right: Creates a right join
> - rollback: Rolls back a transaction
> - row: Used with aggregate functions
> - select: Selects data from a table
> - set: Changes the value of a column
> - table: Specifies the table(s) to select data from
> - temp: Creates a temporary table
> - temporary: Creates a temporary table
> - then: Used with the CASE statement
> - ties: Used with the ORDER BY clause
> - to: Used with common table expressions
> - transaction: Starts a transaction
> - trigger: Creates a trigger
> - unbounded: Used with window functions
> - union: Returns all rows from both queries
> - unique: Creates a unique constraint
> - update: Updates existing data in a table
> - using: Specifies the table(s) to join
> - vacuum: Optimizes a database
> - values: Specifies the values to insert into a table
> - view: Creates a view
> - virtual: Creates a virtual table
> - when: Used with the CASE statement
> - where: Specifies conditions for a query
> - window: Used with window functions
> - with: Specifies common table expressions used in a query
> - without: Used with indexes","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317520304,https://api.github.com/repos/simonw/datasette/issues/1893,1317520304,IC_kwDOBm6k_c5Oh8Ow,95570,2022-11-16T18:58:43Z,2022-11-16T18:58:43Z,CONTRIBUTOR,Nice. And is it possible to include another field which is an escaped table name (only when necessary) - i.e. `[123_starts_with_digits]`. Or is that easy enough to derive on the client? I'm thinking we'd map those to Completion objects so that CM would show the non escaped text but complete to escaped.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
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/1897#issuecomment-1317840727,https://api.github.com/repos/simonw/datasette/issues/1897,1317840727,IC_kwDOBm6k_c5OjKdX,9599,2022-11-16T23:57:52Z,2022-11-16T23:57:52Z,OWNER,In terms of permissions: if you have `execute-sql` permission for a database then it's OK for you to see the table columns for that database.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1452457263,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316236448,https://api.github.com/repos/simonw/datasette/issues/1893,1316236448,IC_kwDOBm6k_c5OdCyg,9599,2022-11-16T03:04:57Z,2022-11-16T03:04:57Z,OWNER,If you rebase from `main` you should get the fix for that test failure.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316227073,https://api.github.com/repos/simonw/datasette/issues/1893,1316227073,IC_kwDOBm6k_c5OdAgB,9599,2022-11-16T02:54:22Z,2022-11-16T02:54:32Z,OWNER,"If you can get a version of this working with table and column autocompletion just using a static JavaScript object in the source code with the right tables and columns, I'm happy to take on the work of turning that static object into something that Datasette includes in the page itself with all of the correct values.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317837416,https://api.github.com/repos/simonw/datasette/issues/1893,1317837416,IC_kwDOBm6k_c5OjJpo,9599,2022-11-16T23:54:02Z,2022-11-16T23:54:02Z,OWNER,"I'm going to tackle #1897 in the next few minutes.
Tests failed due to Prettier check, just pushed a fix so it would ignore `.bundle.js` too.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/issues/1897#issuecomment-1317839781,https://api.github.com/repos/simonw/datasette/issues/1897,1317839781,IC_kwDOBm6k_c5OjKOl,9599,2022-11-16T23:56:47Z,2022-11-16T23:56:47Z,OWNER,I'm going to call this `table_columns` in the template context (because `schema` might mean `CREATE TABLE ...`.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1452457263,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317831555,https://api.github.com/repos/simonw/datasette/issues/1893,1317831555,IC_kwDOBm6k_c5OjIOD,9599,2022-11-16T23:47:13Z,2022-11-16T23:47:13Z,OWNER,I'll open a follow-up issue to fix the schema.,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317465874,https://api.github.com/repos/simonw/datasette/issues/1893,1317465874,IC_kwDOBm6k_c5Ohu8S,9599,2022-11-16T18:21:17Z,2022-11-16T18:21:54Z,OWNER,"I was worrying about the server-side overhead of collecting together all of the tables and column names for databases that might have hundreds of tables... but then I remember that I built the `_internal` table precisely for this kind of thing - so gathering all of that data should still only be a single SQL query against an in-memory database.
https://latest.datasette.io/login-as-root and then visit this page for an example query: https://latest.datasette.io/_internal?sql=select%0D%0A++database_name%2C%0D%0A++table_name%2C%0D%0A++json_group_array%28name%29%0D%0Afrom%0D%0A++columns%0D%0Awhere%0D%0A++database_name+%21%3D+%27_internal%27%0D%0Agroup+by%0D%0A++database_name%2C%0D%0A++table_name
```sql
select
database_name,
table_name,
json_group_array(name)
from
columns
where
database_name != '_internal'
group by
database_name,
table_name
```
database_name | table_name | json_group_array(name)
-- | -- | --
extra_database | searchable | [""pk"",""text1"",""text2""]
extra_database | searchable_fts | [""__langid"",""content"",""docid"",""searchable_fts"",""text1"",""text2""]
extra_database | searchable_fts_content | [""c0text1"",""c1text2"",""c2content"",""docid""]
extra_database | searchable_fts_segdir | [""end_block"",""idx"",""leaves_end_block"",""level"",""root"",""start_block""]
extra_database | searchable_fts_segments | [""block"",""blockid""]
fixtures | 123_starts_with_digits | [""content""]
fixtures | Table With Space In Name | [""content"",""pk""]
fixtures | attraction_characteristic | [""name"",""pk""]
fixtures | binary_data | [""data""]
fixtures | complex_foreign_keys | [""f1"",""f2"",""f3"",""pk""]
fixtures | compound_primary_key | [""content"",""pk1"",""pk2""]
","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317715580,https://api.github.com/repos/simonw/datasette/issues/1893,1317715580,IC_kwDOBm6k_c5Oir58,95570,2022-11-16T21:49:51Z,2022-11-16T21:49:51Z,CONTRIBUTOR,"I think the table completion still has some quirks to work out. Something like
```
schema: {
""[123_starts_with_digits]"": [""content""],
}
```
Seems to work alright, although it will append it after any other numbers you've started typing - so you end up with `select * from 12[123_starts_with_digits]` if you typed ""12"" to get the completion to appear. This might just be an issue with numeric names, I haven't tested it in a lot of detail.
You can do
```
searchable: [
{
label: ""name with . and spaces"",
apply: ""[name with . and spaces]"",
},
""pk"",
""text1"",
""text2"",
],
```
Which is pretty neat and will show the non-escaped string but complete to the escaped one. You can't easily do that with the table names themselves (you can pass a `tables` array like so https://github.com/codemirror/lang-sql/blob/ebf115fffdbe07f91465ccbd82868c587f8182bc/src/sql.ts#L121 but it will overwrite the columns from the schema ).
It's buggy enough (bad output for these unusual table names) that I'd suggest that work gets moved into a follow up to the upgrade to 6. That would give space to sort out how to deliver that to the view directly, figure out where name escaping should happen, and have overall testing to uncover bugs and fix papercuts before enabling it.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316135244,https://api.github.com/repos/simonw/datasette/issues/1893,1316135244,IC_kwDOBm6k_c5OcqFM,9599,2022-11-16T01:21:41Z,2022-11-16T01:21:41Z,OWNER,"I just deployed a demo instance like this (using the commit hash from this PR):
```bash
datasette publish vercel fixtures.db \
--branch 544f7025900b78f63c34b9985522271ba5fd9c0f \
--project datasette-pr-1893 \
--scope datasette \
--about 'PR 1893' \
--about_url https://github.com/simonw/datasette/pull/1893
```
Here's the result: https://datasette-pr-1893.vercel.app/fixtures","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317789308,https://api.github.com/repos/simonw/datasette/issues/1893,1317789308,IC_kwDOBm6k_c5Oi958,95570,2022-11-16T22:59:57Z,2022-11-16T22:59:57Z,CONTRIBUTOR,"I can push up a commit that uses the static fixtures schema for testing, but given that the query used to generate it is authed we would still need some work to make that work on live data, right? Ideally it could come down to db and query views directly to avoid waiting on an extra xhr and managing that state change.On Nov 16, 2022, at 2:16 PM, Simon Willison ***@***.***> wrote:
Honestly I'm not too bothered if table names with weird characters don't work correctly here - I care about those in the Datasette fixtures.db database because Datasette aims to support ANY valid SQLite database, so I need stuff in the test suite that includes weird edge cases like this. But I would hope very few people actually create tables with spaces in their names, so it's not a huge concern to me if autocompletion doesn't work properly for those.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***>","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/issues/1880#issuecomment-1317420812,https://api.github.com/repos/simonw/datasette/issues/1880,1317420812,IC_kwDOBm6k_c5Ohj8M,525934,2022-11-16T17:50:29Z,2022-11-16T17:50:29Z,NONE,"I appreciate your response @simonw - thanks!
I'll clarify what we need further - let's imagine we have 2000 SQLLite databases (for 2000 tenants), but we only want to run _one_ datasette instance for each of those tenants to query/use datasette against their _own_ database only. This means the ""connection"" between datasette and the SQLLite database would be dynamic, based on the tenantID that's required on an incoming request.
Is there any specific config or other considerations in this use case, to minimize memory use on a single, efficient VM and serve queries to all these tenants?
cc @muadham","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1433576351,
https://github.com/simonw/datasette/pull/1893#issuecomment-1316387382,https://api.github.com/repos/simonw/datasette/issues/1893,1316387382,IC_kwDOBm6k_c5Odno2,95570,2022-11-16T05:33:55Z,2022-11-16T05:33:55Z,CONTRIBUTOR,I added a commit to make our own dialect at https://github.com/simonw/datasette/pull/1893/commits/e273fc8ed5341bdf0b622e722d761bd2acc30a90. Pulled in the full list of keywords from https://www.sqlite.org/lang_keywords.html but haven't gone through and pruned it to only include common select keywords. @simonw you'll have better knowledge than me on that - do you want to take a first shot at narrowing that down to the set that people will be using in the editor?,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317744563,https://api.github.com/repos/simonw/datasette/issues/1893,1317744563,IC_kwDOBm6k_c5Oiy-z,9599,2022-11-16T22:16:03Z,2022-11-16T22:16:03Z,OWNER,"Honestly I'm not too bothered if table names with weird characters don't work correctly here - I care about those in the Datasette `fixtures.db` database because Datasette aims to support ANY valid SQLite database, so I need stuff in the test suite that includes weird edge cases like this. But I would hope very few people actually create tables with spaces in their names, so it's not a huge concern to me if autocompletion doesn't work properly for those.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/issues/1897#issuecomment-1317838892,https://api.github.com/repos/simonw/datasette/issues/1897,1317838892,IC_kwDOBm6k_c5OjKAs,9599,2022-11-16T23:55:42Z,2022-11-16T23:55:42Z,OWNER,"Here's where the schema is hard-coded at the moment: https://github.com/simonw/datasette/blob/00e233d7a7f6443cb95fb5227c23580c48551cad/datasette/templates/_codemirror_foot.html#L2-L7
I figured out how to extract that data from the `_internal` table in this comment: https://github.com/simonw/datasette/pull/1893#issuecomment-1317475720
Although that used JSON functions which may (in a real edge-case) not be available in the version of SQLite that Datasette is running on, so probably going to use a regular SQL query and then assemble the JSON separately.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1452457263,
https://github.com/simonw/datasette/pull/1893#issuecomment-1317475720,https://api.github.com/repos/simonw/datasette/issues/1893,1317475720,IC_kwDOBm6k_c5OhxWI,9599,2022-11-16T18:25:16Z,2022-11-16T18:25:16Z,OWNER,"Here's a query that returns the exact JSON we need to pass to the schema:
https://latest.datasette.io/_internal?sql=with+inner+as+%28%0D%0A++select%0D%0A++++table_name%2C%0D%0A++++json_group_array%28name%29+as+table_columns%0D%0A++from%0D%0A++++columns%0D%0A++where%0D%0A++++database_name+%3D+%3Adatabase%0D%0A++group+by%0D%0A++++table_name%0D%0A%29%0D%0Aselect%0D%0A++json_group_object%28table_name%2C+table_columns%29%0D%0Afrom%0D%0A++inner&database=fixtures
```sql
with inner as (
select
table_name,
json_group_array(name) as table_columns
from
columns
where
database_name = :database
group by
table_name
)
select
json_group_object(table_name, table_columns)
from
inner
```
Returns (after pretty-printing):
```json
{
""123_starts_with_digits"": [
""content""
],
""Table With Space In Name"": [
""content"",
""pk""
],
""attraction_characteristic"": [
""name"",
""pk""
],
""binary_data"": [
""data""
],
""complex_foreign_keys"": [
""f1"",
""f2"",
""f3"",
""pk""
],
""compound_primary_key"": [
""content"",
""pk1"",
""pk2""
],
""compound_three_primary_keys"": [
""content"",
""pk1"",
""pk2"",
""pk3""
],
""custom_foreign_key_label"": [
""foreign_key_with_custom_label"",
""pk""
],
""facet_cities"": [
""id"",
""name""
],
""facetable"": [
""_city_id"",
""_neighborhood"",
""complex_array"",
""created"",
""distinct_some_null"",
""n"",
""on_earth"",
""pk"",
""planet_int"",
""state"",
""tags""
],
""foreign_key_references"": [
""foreign_key_compound_pk1"",
""foreign_key_compound_pk2"",
""foreign_key_with_blank_label"",
""foreign_key_with_label"",
""foreign_key_with_no_label"",
""pk""
],
""infinity"": [
""value""
],
""no_primary_key"": [
""a"",
""b"",
""c"",
""content""
],
""primary_key_multiple_columns"": [
""content"",
""content2"",
""id""
],
""primary_key_multiple_columns_explicit_label"": [
""content"",
""content2"",
""id""
],
""roadside_attraction_characteristics"": [
""attraction_id"",
""characteristic_id""
],
""roadside_attractions"": [
""address"",
""latitude"",
""longitude"",
""name"",
""pk"",
""url""
],
""searchable"": [
""name with . and spaces"",
""pk"",
""text1"",
""text2""
],
""searchable_fts"": [
""__langid"",
""docid"",
""name with . and spaces"",
""searchable_fts"",
""text1"",
""text2""
],
""searchable_fts_docsize"": [
""docid"",
""size""
],
""searchable_fts_segdir"": [
""end_block"",
""idx"",
""leaves_end_block"",
""level"",
""root"",
""start_block""
],
""searchable_fts_segments"": [
""block"",
""blockid""
],
""searchable_fts_stat"": [
""id"",
""value""
],
""searchable_tags"": [
""searchable_id"",
""tag""
],
""select"": [
""and"",
""group"",
""having"",
""json""
],
""simple_primary_key"": [
""content"",
""id""
],
""sortable"": [
""content"",
""pk1"",
""pk2"",
""sortable"",
""sortable_with_nulls"",
""sortable_with_nulls_2"",
""text""
],
""table/with/slashes.csv"": [
""content"",
""pk""
],
""tags"": [
""tag""
],
""units"": [
""distance"",
""frequency"",
""pk""
]
}
```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1450363982,
https://github.com/simonw/datasette/issues/1890#issuecomment-1316240839,https://api.github.com/repos/simonw/datasette/issues/1890,1316240839,IC_kwDOBm6k_c5OdD3H,9599,2022-11-16T03:09:11Z,2022-11-16T03:09:11Z,OWNER,"Here's a polyfill for `