datasette-explain 0.2__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,22 +1,18 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: datasette-explain
3
- Version: 0.2
3
+ Version: 0.2.2
4
4
  Summary: Explain SQL queries executed using Datasette
5
- Home-page: https://github.com/simonw/datasette-explain
6
5
  Author: Simon Willison
7
- License: Apache License, Version 2.0
6
+ License-Expression: Apache-2.0
7
+ License-File: LICENSE
8
+ Classifier: Framework :: Datasette
9
+ Requires-Dist: datasette
10
+ Requires-Python: >=3.10
11
+ Project-URL: Homepage, https://datasette.io/plugins/datasette-explain
12
+ Project-URL: Changelog, https://github.com/simonw/datasette-explain/releases
8
13
  Project-URL: Issues, https://github.com/simonw/datasette-explain/issues
9
14
  Project-URL: CI, https://github.com/simonw/datasette-explain/actions
10
- Project-URL: Changelog, https://github.com/simonw/datasette-explain/releases
11
- Classifier: Framework :: Datasette
12
- Classifier: License :: OSI Approved :: Apache Software License
13
- Requires-Python: >=3.7
14
15
  Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: datasette
17
- Provides-Extra: test
18
- Requires-Dist: pytest; extra == "test"
19
- Requires-Dist: pytest-asyncio; extra == "test"
20
16
 
21
17
  # datasette-explain
22
18
 
@@ -30,29 +26,25 @@ Explain SQL queries executed using Datasette
30
26
  ## Installation
31
27
 
32
28
  Install this plugin in the same environment as Datasette.
33
-
34
- datasette install datasette-explain
35
-
36
- This plugin requires a Datasette 1.0 alpha or higher.
37
-
29
+ ```bash
30
+ datasette install datasette-explain
31
+ ```
38
32
  ## Usage
39
33
 
40
34
  The plugin adds JavaScript to the query editor page which will constantly update the page with information gained from running EXPLAIN QUERY PLAN queries against the entered SQL.
41
35
 
42
36
  This may result in an error message, or it may show the query plan along with any tables used by the query.
43
37
 
44
- ## Development
38
+ ## Demo
45
39
 
46
- To set up this plugin locally, first checkout the code. Then create a new virtual environment:
40
+ You can see this plugin in action on [datasette.simonwillison.net](https://datasette.simonwillison.net/simonwillisonblog?sql=select%0D%0A++blog_tag.tag%2C%0D%0A++blog_blogmark.link_title%2C%0D%0A++blog_blogmark.link_url%0D%0Afrom%0D%0A++blog_blogmark_tags%0D%0A++join+blog_tag+on+tag_id+%3D+blog_tag.id%0D%0A++join+blog_blogmark+on+blog_blogmark_tags.blogmark_id+%3D+blog_blogmark.id%0D%0Aorder+by+blog_blogmark.id+desc).
47
41
 
48
- cd datasette-explain
49
- python3 -m venv venv
50
- source venv/bin/activate
42
+ <img src="https://raw.githubusercontent.com/simonw/datasette-explain/main/datasette-explain-screenshot.jpg" alt="Demo of this plugin - a SQL query shows the explain plan as well as the three tables that were used in the query (their names and columns)" width="832">
51
43
 
52
- Now install the dependencies and test dependencies:
53
-
54
- pip install -e '.[test]'
55
-
56
- To run the tests:
44
+ ## Development
57
45
 
58
- pytest
46
+ To set up this plugin locally, first checkout the code. Then run the tests using [uv](https://docs.astral.sh/uv/):
47
+ ```bash
48
+ cd datasette-explain
49
+ uv run pytest
50
+ ```
@@ -10,29 +10,25 @@ Explain SQL queries executed using Datasette
10
10
  ## Installation
11
11
 
12
12
  Install this plugin in the same environment as Datasette.
13
-
14
- datasette install datasette-explain
15
-
16
- This plugin requires a Datasette 1.0 alpha or higher.
17
-
13
+ ```bash
14
+ datasette install datasette-explain
15
+ ```
18
16
  ## Usage
19
17
 
20
18
  The plugin adds JavaScript to the query editor page which will constantly update the page with information gained from running EXPLAIN QUERY PLAN queries against the entered SQL.
21
19
 
22
20
  This may result in an error message, or it may show the query plan along with any tables used by the query.
23
21
 
24
- ## Development
22
+ ## Demo
25
23
 
26
- To set up this plugin locally, first checkout the code. Then create a new virtual environment:
24
+ You can see this plugin in action on [datasette.simonwillison.net](https://datasette.simonwillison.net/simonwillisonblog?sql=select%0D%0A++blog_tag.tag%2C%0D%0A++blog_blogmark.link_title%2C%0D%0A++blog_blogmark.link_url%0D%0Afrom%0D%0A++blog_blogmark_tags%0D%0A++join+blog_tag+on+tag_id+%3D+blog_tag.id%0D%0A++join+blog_blogmark+on+blog_blogmark_tags.blogmark_id+%3D+blog_blogmark.id%0D%0Aorder+by+blog_blogmark.id+desc).
27
25
 
28
- cd datasette-explain
29
- python3 -m venv venv
30
- source venv/bin/activate
26
+ <img src="https://raw.githubusercontent.com/simonw/datasette-explain/main/datasette-explain-screenshot.jpg" alt="Demo of this plugin - a SQL query shows the explain plan as well as the three tables that were used in the query (their names and columns)" width="832">
31
27
 
32
- Now install the dependencies and test dependencies:
33
-
34
- pip install -e '.[test]'
35
-
36
- To run the tests:
28
+ ## Development
37
29
 
38
- pytest
30
+ To set up this plugin locally, first checkout the code. Then run the tests using [uv](https://docs.astral.sh/uv/):
31
+ ```bash
32
+ cd datasette-explain
33
+ uv run pytest
34
+ ```
@@ -102,13 +102,16 @@ JS = """
102
102
  }
103
103
  let previousSql = '';
104
104
  const sqlForm = document.querySelector('form.sql');
105
+ if (!sqlForm) return;
105
106
  const div = document.createElement('div');
106
107
  div.style.marginTop = '1em';
107
108
  div.style.marginBottom = '1em';
108
109
  sqlForm.appendChild(div);
109
110
  setInterval(() => {
110
111
  const formData = Object.fromEntries(new FormData(sqlForm).entries());
111
- const sql = editor.state.doc.toString();
112
+ const sql = window.editor ? window.editor.state.doc.toString()
113
+ : (document.querySelector('pre#sql-query')?.textContent
114
+ || formData.sql || '');
112
115
  formData.sql = sql;
113
116
  const params = new URLSearchParams(formData).toString();
114
117
  if (sql !== previousSql) {
@@ -0,0 +1,38 @@
1
+ [project]
2
+ name = "datasette-explain"
3
+ version = "0.2.2"
4
+ description = "Explain SQL queries executed using Datasette"
5
+ readme = "README.md"
6
+ license = "Apache-2.0"
7
+ license-files = ["LICENSE"]
8
+ classifiers = ["Framework :: Datasette"]
9
+ requires-python = ">=3.10"
10
+ dependencies = ["datasette"]
11
+
12
+ [[project.authors]]
13
+ name = "Simon Willison"
14
+
15
+ [project.urls]
16
+ Homepage = "https://datasette.io/plugins/datasette-explain"
17
+ Changelog = "https://github.com/simonw/datasette-explain/releases"
18
+ Issues = "https://github.com/simonw/datasette-explain/issues"
19
+ CI = "https://github.com/simonw/datasette-explain/actions"
20
+
21
+ [project.entry-points.datasette]
22
+ explain = "datasette_explain"
23
+
24
+ [dependency-groups]
25
+ dev = [
26
+ "pytest",
27
+ "pytest-asyncio",
28
+ ]
29
+
30
+ [tool.pytest.ini_options]
31
+ asyncio_mode = "strict"
32
+
33
+ [tool.uv.build-backend]
34
+ module-root = ""
35
+
36
+ [build-system]
37
+ requires = ["uv_build>=0.12.9,<0.13.0"]
38
+ build-backend = "uv_build"
@@ -0,0 +1,40 @@
1
+ [project]
2
+ name = "datasette-explain"
3
+ version = "0.2.2"
4
+ description = "Explain SQL queries executed using Datasette"
5
+ readme = "README.md"
6
+ authors = [{name = "Simon Willison"}]
7
+ license = "Apache-2.0"
8
+ license-files = ["LICENSE"]
9
+ classifiers = [
10
+ "Framework :: Datasette",
11
+ ]
12
+ requires-python = ">=3.10"
13
+ dependencies = [
14
+ "datasette",
15
+ ]
16
+
17
+ [project.urls]
18
+ Homepage = "https://datasette.io/plugins/datasette-explain"
19
+ Changelog = "https://github.com/simonw/datasette-explain/releases"
20
+ Issues = "https://github.com/simonw/datasette-explain/issues"
21
+ CI = "https://github.com/simonw/datasette-explain/actions"
22
+
23
+ [project.entry-points.datasette]
24
+ explain = "datasette_explain"
25
+
26
+ [dependency-groups]
27
+ dev = [
28
+ "pytest",
29
+ "pytest-asyncio",
30
+ ]
31
+
32
+ [tool.pytest.ini_options]
33
+ asyncio_mode = "strict"
34
+
35
+ [build-system]
36
+ requires = ["uv_build>=0.12.9,<0.13.0"]
37
+ build-backend = "uv_build"
38
+
39
+ [tool.uv.build-backend]
40
+ module-root = ""
@@ -1,58 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: datasette-explain
3
- Version: 0.2
4
- Summary: Explain SQL queries executed using Datasette
5
- Home-page: https://github.com/simonw/datasette-explain
6
- Author: Simon Willison
7
- License: Apache License, Version 2.0
8
- Project-URL: Issues, https://github.com/simonw/datasette-explain/issues
9
- Project-URL: CI, https://github.com/simonw/datasette-explain/actions
10
- Project-URL: Changelog, https://github.com/simonw/datasette-explain/releases
11
- Classifier: Framework :: Datasette
12
- Classifier: License :: OSI Approved :: Apache Software License
13
- Requires-Python: >=3.7
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: datasette
17
- Provides-Extra: test
18
- Requires-Dist: pytest; extra == "test"
19
- Requires-Dist: pytest-asyncio; extra == "test"
20
-
21
- # datasette-explain
22
-
23
- [![PyPI](https://img.shields.io/pypi/v/datasette-explain.svg)](https://pypi.org/project/datasette-explain/)
24
- [![Changelog](https://img.shields.io/github/v/release/simonw/datasette-explain?include_prereleases&label=changelog)](https://github.com/simonw/datasette-explain/releases)
25
- [![Tests](https://github.com/simonw/datasette-explain/workflows/Test/badge.svg)](https://github.com/simonw/datasette-explain/actions?query=workflow%3ATest)
26
- [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/datasette-explain/blob/main/LICENSE)
27
-
28
- Explain SQL queries executed using Datasette
29
-
30
- ## Installation
31
-
32
- Install this plugin in the same environment as Datasette.
33
-
34
- datasette install datasette-explain
35
-
36
- This plugin requires a Datasette 1.0 alpha or higher.
37
-
38
- ## Usage
39
-
40
- The plugin adds JavaScript to the query editor page which will constantly update the page with information gained from running EXPLAIN QUERY PLAN queries against the entered SQL.
41
-
42
- This may result in an error message, or it may show the query plan along with any tables used by the query.
43
-
44
- ## Development
45
-
46
- To set up this plugin locally, first checkout the code. Then create a new virtual environment:
47
-
48
- cd datasette-explain
49
- python3 -m venv venv
50
- source venv/bin/activate
51
-
52
- Now install the dependencies and test dependencies:
53
-
54
- pip install -e '.[test]'
55
-
56
- To run the tests:
57
-
58
- pytest
@@ -1,11 +0,0 @@
1
- LICENSE
2
- README.md
3
- setup.py
4
- datasette_explain/__init__.py
5
- datasette_explain.egg-info/PKG-INFO
6
- datasette_explain.egg-info/SOURCES.txt
7
- datasette_explain.egg-info/dependency_links.txt
8
- datasette_explain.egg-info/entry_points.txt
9
- datasette_explain.egg-info/requires.txt
10
- datasette_explain.egg-info/top_level.txt
11
- tests/test_explain.py
@@ -1,2 +0,0 @@
1
- [datasette]
2
- explain = datasette_explain
@@ -1,5 +0,0 @@
1
- datasette
2
-
3
- [test]
4
- pytest
5
- pytest-asyncio
@@ -1 +0,0 @@
1
- datasette_explain
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
@@ -1,38 +0,0 @@
1
- from setuptools import setup
2
- import os
3
-
4
- VERSION = "0.2"
5
-
6
-
7
- def get_long_description():
8
- with open(
9
- os.path.join(os.path.dirname(os.path.abspath(__file__)), "README.md"),
10
- encoding="utf8",
11
- ) as fp:
12
- return fp.read()
13
-
14
-
15
- setup(
16
- name="datasette-explain",
17
- description="Explain SQL queries executed using Datasette",
18
- long_description=get_long_description(),
19
- long_description_content_type="text/markdown",
20
- author="Simon Willison",
21
- url="https://github.com/simonw/datasette-explain",
22
- project_urls={
23
- "Issues": "https://github.com/simonw/datasette-explain/issues",
24
- "CI": "https://github.com/simonw/datasette-explain/actions",
25
- "Changelog": "https://github.com/simonw/datasette-explain/releases",
26
- },
27
- license="Apache License, Version 2.0",
28
- classifiers=[
29
- "Framework :: Datasette",
30
- "License :: OSI Approved :: Apache Software License",
31
- ],
32
- version=VERSION,
33
- packages=["datasette_explain"],
34
- entry_points={"datasette": ["explain = datasette_explain"]},
35
- install_requires=["datasette"],
36
- extras_require={"test": ["pytest", "pytest-asyncio"]},
37
- python_requires=">=3.7",
38
- )
@@ -1,98 +0,0 @@
1
- from datasette.app import Datasette
2
- import pytest
3
- import pytest_asyncio
4
-
5
-
6
- @pytest_asyncio.fixture
7
- async def ds():
8
- datasette = Datasette(memory=True)
9
- db = datasette.add_memory_database("test")
10
- await db.execute_write("create table if not exists t1 (id integer primary key)")
11
- await db.execute_write("create table if not exists t2 (id integer primary key)")
12
- return datasette
13
-
14
-
15
- @pytest.mark.asyncio
16
- @pytest.mark.parametrize(
17
- "sql,expected",
18
- (
19
- (
20
- "select 1",
21
- {
22
- "ok": True,
23
- "explain_tree": [{"detail": "SCAN CONSTANT ROW", "children": []}],
24
- "tables": [],
25
- },
26
- ),
27
- (
28
- "select * from t1",
29
- {
30
- "ok": True,
31
- "explain_tree": [{"detail": "SCAN t1", "children": []}],
32
- "tables": [{"name": "t1", "columns": ["id"]}],
33
- },
34
- ),
35
- (
36
- "select * from t1 where id > :id",
37
- {
38
- "ok": True,
39
- "explain_tree": [
40
- {
41
- "detail": "SEARCH t1 USING INTEGER PRIMARY KEY (rowid>?)",
42
- "children": [],
43
- }
44
- ],
45
- "tables": [{"name": "t1", "columns": ["id"]}],
46
- },
47
- ),
48
- (
49
- "select id, (select id from t2 where t2.id = t1.id) from t1",
50
- {
51
- "ok": True,
52
- "explain_tree": [
53
- {"detail": "SCAN t1", "children": []},
54
- {
55
- "detail": "CORRELATED SCALAR SUBQUERY 1",
56
- "children": [
57
- {
58
- "detail": "SEARCH t2 USING INTEGER PRIMARY KEY (rowid=?)",
59
- "children": [],
60
- }
61
- ],
62
- },
63
- ],
64
- "tables": [
65
- {"name": "t1", "columns": ["id"]},
66
- {"name": "t2", "columns": ["id"]},
67
- ],
68
- },
69
- ),
70
- (
71
- "select count(*) from t1 where id > :id",
72
- {
73
- "ok": True,
74
- "explain_tree": [
75
- {
76
- "detail": "SEARCH t1 USING INTEGER PRIMARY KEY (rowid>?)",
77
- "children": [],
78
- }
79
- ],
80
- "tables": [{"name": "t1", "columns": ["id"]}],
81
- },
82
- ),
83
- (
84
- "explain select count(*) from t1",
85
- {
86
- "ok": True,
87
- "explain_tree": [],
88
- "tables": [],
89
- },
90
- ),
91
- ),
92
- )
93
- async def test_explain(ds, sql, expected):
94
- params = {"sql": sql}
95
- response = await ds.client.get("/test/-/explain", params=params)
96
- assert response.status_code == 200
97
- data = response.json()
98
- assert data == expected