sqlitexplorer 1.0.0__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.
- sqlitexplorer-1.0.0/LICENSE +21 -0
- sqlitexplorer-1.0.0/PKG-INFO +229 -0
- sqlitexplorer-1.0.0/README.md +200 -0
- sqlitexplorer-1.0.0/pyproject.toml +58 -0
- sqlitexplorer-1.0.0/setup.cfg +4 -0
- sqlitexplorer-1.0.0/sqlitexplorer/__init__.py +10 -0
- sqlitexplorer-1.0.0/sqlitexplorer/__main__.py +6 -0
- sqlitexplorer-1.0.0/sqlitexplorer/charts.py +203 -0
- sqlitexplorer-1.0.0/sqlitexplorer/cli.py +857 -0
- sqlitexplorer-1.0.0/sqlitexplorer/completion.py +22 -0
- sqlitexplorer-1.0.0/sqlitexplorer/core.py +700 -0
- sqlitexplorer-1.0.0/sqlitexplorer/render.py +508 -0
- sqlitexplorer-1.0.0/sqlitexplorer/shell.py +254 -0
- sqlitexplorer-1.0.0/sqlitexplorer.egg-info/PKG-INFO +229 -0
- sqlitexplorer-1.0.0/sqlitexplorer.egg-info/SOURCES.txt +23 -0
- sqlitexplorer-1.0.0/sqlitexplorer.egg-info/dependency_links.txt +1 -0
- sqlitexplorer-1.0.0/sqlitexplorer.egg-info/entry_points.txt +2 -0
- sqlitexplorer-1.0.0/sqlitexplorer.egg-info/requires.txt +7 -0
- sqlitexplorer-1.0.0/sqlitexplorer.egg-info/top_level.txt +1 -0
- sqlitexplorer-1.0.0/tests/test_charts.py +108 -0
- sqlitexplorer-1.0.0/tests/test_cli.py +722 -0
- sqlitexplorer-1.0.0/tests/test_completion.py +26 -0
- sqlitexplorer-1.0.0/tests/test_core.py +370 -0
- sqlitexplorer-1.0.0/tests/test_render.py +202 -0
- sqlitexplorer-1.0.0/tests/test_shell.py +139 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 Carlos A. Planchón
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sqlitexplorer
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Explore SQLite databases from the terminal: tables, schema, stats, search, queries, charts, export/import and an interactive shell.
|
|
5
|
+
Author-email: "Carlos A. Planchón" <carlosandresplanchonprestes@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/carlosplanchon/sqlitexplorer.git
|
|
8
|
+
Keywords: sqlite,sqlite3,database,cli,terminal,explorer,chart,shell,repl
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Topic :: Database
|
|
12
|
+
Classifier: Topic :: Database :: Front-Ends
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: outfancy>=0.11
|
|
23
|
+
Requires-Dist: plotille>=6
|
|
24
|
+
Requires-Dist: typer>=0.12
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
27
|
+
Requires-Dist: ruff; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# sqlitexplorer
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
A command-line explorer for SQLite databases. It lists tables, prints schemas,
|
|
35
|
+
dumps rows, computes statistics, searches values, runs ad-hoc queries, draws
|
|
36
|
+
charts, exports and imports data, and offers an interactive shell. Tables are
|
|
37
|
+
rendered with [outfancy](https://github.com/carlosplanchon/outfancy) and charts
|
|
38
|
+
with [plotille](https://github.com/tammoippen/plotille).
|
|
39
|
+
|
|
40
|
+
[](https://github.com/carlosplanchon/sqlitexplorer/actions/workflows/ci.yml)
|
|
41
|
+
[](https://pypi.org/project/sqlitexplorer/)
|
|
42
|
+
[](https://pypi.org/project/sqlitexplorer/)
|
|
43
|
+
[](https://opensource.org/licenses/MIT)
|
|
44
|
+
[](https://deepwiki.com/carlosplanchon/sqlitexplorer)
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
Requires Python 3.10 or newer.
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
# From a clone of this repository:
|
|
52
|
+
uv tool install .
|
|
53
|
+
# or with pip:
|
|
54
|
+
pip install .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick tour
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
sqlitexplorer tables app.db # tables and views with their row counts
|
|
61
|
+
sqlitexplorer schema app.db [users] # CREATE statements, in creation order
|
|
62
|
+
sqlitexplorer describe app.db users # columns: type, NOT NULL, default, primary key
|
|
63
|
+
sqlitexplorer indexes app.db [users] # indexes and the columns they cover
|
|
64
|
+
sqlitexplorer foreign-keys app.db [posts] # foreign keys
|
|
65
|
+
sqlitexplorer info app.db [--check] # size, pragmas, object counts, integrity check
|
|
66
|
+
sqlitexplorer show app.db users # rows of a table or view
|
|
67
|
+
sqlitexplorer stats app.db users # nulls, distinct, min, max, top values per column
|
|
68
|
+
sqlitexplorer search app.db "marie" # find a text in every column of every table
|
|
69
|
+
sqlitexplorer query app.db "SELECT ..." # run SQL
|
|
70
|
+
sqlitexplorer chart app.db "SELECT day, total FROM sales ORDER BY day"
|
|
71
|
+
sqlitexplorer dump app.db # the whole database as SQL
|
|
72
|
+
sqlitexplorer export app.db users -o users.csv # rows to a file
|
|
73
|
+
sqlitexplorer import app.db people people.csv # a file into a table
|
|
74
|
+
sqlitexplorer diff app.db backup.db # compare two schemas
|
|
75
|
+
sqlitexplorer shell app.db # interactive shell
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Every command has `--help`. Databases are opened read-only and are never
|
|
79
|
+
created; commands that change data need `--write`, except `import`, which
|
|
80
|
+
always writes.
|
|
81
|
+
|
|
82
|
+
## Exploring
|
|
83
|
+
|
|
84
|
+
`show` accepts filters so most questions need no SQL:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
sqlitexplorer show app.db users -c name,age --where "age > 18" --order-by age --desc -n 20 --offset 40
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`--columns` and `--order-by` are validated against the table; `--where` is a
|
|
91
|
+
raw SQL condition.
|
|
92
|
+
|
|
93
|
+
`stats` reports, for each column, the declared type, how many NULLs, how many
|
|
94
|
+
distinct values, the minimum, the maximum and the most frequent values
|
|
95
|
+
(`--top N`). Everything but the frequent values comes from a single pass over
|
|
96
|
+
the table; on big tables use `--top 0` to skip them, `--columns` to analyse
|
|
97
|
+
only some columns, or `--sample N` to work on a random sample of N rows (the
|
|
98
|
+
output then says so). Likewise `tables --no-count` skips the row counts.
|
|
99
|
+
|
|
100
|
+
`search` looks for a case-insensitive substring in every non-BLOB column of
|
|
101
|
+
every table (`--table` restricts it, `--limit` stops early) and prints the
|
|
102
|
+
table, column, rowid and value of each match. Each table is scanned once.
|
|
103
|
+
|
|
104
|
+
## Output options
|
|
105
|
+
|
|
106
|
+
Every command that prints rows takes the same options:
|
|
107
|
+
|
|
108
|
+
| Option | Effect |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `--format`, `-f` | `table` (default), `csv`, `tsv`, `json` or `markdown` |
|
|
111
|
+
| `--null TEXT` | text shown for NULL values (default `NULL`) |
|
|
112
|
+
| `--truncate N` | cut values longer than N characters |
|
|
113
|
+
| `--page N`, `--page-size M` | print only one page of the rows; the footer goes to stderr |
|
|
114
|
+
| `--pager` | send the output to `$PAGER` (default `less -R`) when on a terminal |
|
|
115
|
+
| `--color` / `--no-color` | force or disable ANSI colors; by default only on a terminal, never when `NO_COLOR` is set |
|
|
116
|
+
| `--width N` | width to fit tables into (default: the terminal width) |
|
|
117
|
+
|
|
118
|
+
`NULL` and `BLOB` values are printed as SQL literals (`NULL`, `X'0102'`). In
|
|
119
|
+
the JSON format NULL becomes `null`, BLOBs are base64 strings and values are
|
|
120
|
+
never truncated.
|
|
121
|
+
|
|
122
|
+
When a table is wider than the terminal, the widest columns are narrowed and
|
|
123
|
+
their values wrapped so that every column and label stays visible. Use
|
|
124
|
+
`--width` or another format to get the values on one line.
|
|
125
|
+
|
|
126
|
+
Big results do not need to fit in memory: `--page` fetches only the requested
|
|
127
|
+
page (in SQL for `show`, from the cursor for `query`), and the csv, tsv, json
|
|
128
|
+
and markdown formats, `export` and `dump` are written row by row. The table
|
|
129
|
+
format is the exception, since it needs every row to size its columns.
|
|
130
|
+
|
|
131
|
+
## Queries
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
sqlitexplorer query app.db "SELECT name, age FROM users WHERE age > :min" -p min=30
|
|
135
|
+
sqlitexplorer query app.db --file report.sql # several statements, one transaction
|
|
136
|
+
echo "SELECT COUNT(*) FROM users" | sqlitexplorer query app.db -
|
|
137
|
+
sqlitexplorer query app.db "SELECT ..." --attach old=backup.db # then use old.users
|
|
138
|
+
sqlitexplorer query app.db "SELECT ..." --explain # EXPLAIN QUERY PLAN as a tree
|
|
139
|
+
sqlitexplorer query app.db "SELECT ..." --time # rows and elapsed time on stderr
|
|
140
|
+
sqlitexplorer query app.db "SELECT COUNT(*) FROM jobs" --watch 2 # re-run every 2 s, Ctrl-C stops
|
|
141
|
+
sqlitexplorer query app.db "DELETE FROM users WHERE age IS NULL" --write
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Several statements can be given at once (separated by `;`); they run in one
|
|
145
|
+
transaction that is committed at the end and rolled back on the first error.
|
|
146
|
+
`--param` values that look like numbers are bound as numbers. Attached
|
|
147
|
+
databases follow the read-only rule of the main one.
|
|
148
|
+
|
|
149
|
+
## Charts
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
sqlitexplorer chart app.db "SELECT day, sales, returns FROM daily ORDER BY day"
|
|
153
|
+
sqlitexplorer chart app.db "SELECT age FROM users" --kind hist --bins 20
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The first column is the X axis (numbers or ISO dates), every other column is a
|
|
157
|
+
series named after the column; rows with NULLs are skipped and counted on
|
|
158
|
+
stderr. `--kind` selects `line` (default), `scatter` or `hist` (first column
|
|
159
|
+
only, `--bins`). `--height`, `--width`, `--x-label`, `--y-label` and `--color`
|
|
160
|
+
adjust the drawing.
|
|
161
|
+
|
|
162
|
+
## Export, import, dump and diff
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
sqlitexplorer dump app.db -o backup.sql # replayable SQL, like .dump
|
|
166
|
+
sqlitexplorer export app.db users -f json -o users.json
|
|
167
|
+
sqlitexplorer export app.db --all -o exported/ -f csv # one file per table and view
|
|
168
|
+
sqlitexplorer import app.db people people.csv # csv, tsv or json (list of objects)
|
|
169
|
+
sqlitexplorer diff app.db backup.db # exit status 1 when the schemas differ
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`import` creates the table when it does not exist, inferring INTEGER, REAL or
|
|
173
|
+
TEXT for each column; empty CSV cells become NULL. The format comes from the
|
|
174
|
+
file extension unless `--format` is given.
|
|
175
|
+
|
|
176
|
+
## Shell
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
$ sqlitexplorer shell app.db
|
|
180
|
+
sqlitexplorer> SELECT name
|
|
181
|
+
...> FROM users;
|
|
182
|
+
sqlitexplorer> .tables
|
|
183
|
+
sqlitexplorer> .format json
|
|
184
|
+
sqlitexplorer> .quit
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Statements end with `;` and may span several lines. Dot-commands: `.tables`,
|
|
188
|
+
`.schema [NAME]`, `.describe TABLE`, `.indexes [TABLE]`, `.stats TABLE`,
|
|
189
|
+
`.format FORMAT`, `.null TEXT`, `.truncate N|off`, `.help` and `.quit`. Tab
|
|
190
|
+
completes SQL keywords, table and column names; the history is kept in
|
|
191
|
+
`$XDG_STATE_HOME/sqlitexplorer/history` (`~/.local/state` by default). With
|
|
192
|
+
`--write` every statement is committed as soon as it succeeds. SQL can also be
|
|
193
|
+
piped into the shell.
|
|
194
|
+
|
|
195
|
+
Completion of the command line itself (commands, options and table names) is
|
|
196
|
+
installed with `sqlitexplorer --install-completion`.
|
|
197
|
+
|
|
198
|
+
## Development
|
|
199
|
+
|
|
200
|
+
```sh
|
|
201
|
+
uv venv
|
|
202
|
+
uv pip install -e ".[dev]"
|
|
203
|
+
uv run pytest
|
|
204
|
+
uv run ruff check .
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Releasing
|
|
208
|
+
|
|
209
|
+
Releases are driven by version tags. Pushing `vX.Y.Z` runs the tests, builds
|
|
210
|
+
the distributions, publishes them to PyPI with
|
|
211
|
+
[trusted publishing](https://docs.pypi.org/trusted-publishers/) and creates a
|
|
212
|
+
GitHub release with the artifacts attached.
|
|
213
|
+
|
|
214
|
+
```sh
|
|
215
|
+
uv version 0.3.0 # or: uv version --bump minor
|
|
216
|
+
git commit -am "Release 0.3.0"
|
|
217
|
+
git tag v0.3.0
|
|
218
|
+
git push origin master v0.3.0
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The tag must match the version in `pyproject.toml`; the workflow refuses to
|
|
222
|
+
publish otherwise. Before the first release, register the repository as a
|
|
223
|
+
trusted publisher of the project on PyPI with the workflow name `release.yml`
|
|
224
|
+
and the environment `pypi`, and create that environment in the repository
|
|
225
|
+
settings on GitHub.
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# sqlitexplorer
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
A command-line explorer for SQLite databases. It lists tables, prints schemas,
|
|
6
|
+
dumps rows, computes statistics, searches values, runs ad-hoc queries, draws
|
|
7
|
+
charts, exports and imports data, and offers an interactive shell. Tables are
|
|
8
|
+
rendered with [outfancy](https://github.com/carlosplanchon/outfancy) and charts
|
|
9
|
+
with [plotille](https://github.com/tammoippen/plotille).
|
|
10
|
+
|
|
11
|
+
[](https://github.com/carlosplanchon/sqlitexplorer/actions/workflows/ci.yml)
|
|
12
|
+
[](https://pypi.org/project/sqlitexplorer/)
|
|
13
|
+
[](https://pypi.org/project/sqlitexplorer/)
|
|
14
|
+
[](https://opensource.org/licenses/MIT)
|
|
15
|
+
[](https://deepwiki.com/carlosplanchon/sqlitexplorer)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Requires Python 3.10 or newer.
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
# From a clone of this repository:
|
|
23
|
+
uv tool install .
|
|
24
|
+
# or with pip:
|
|
25
|
+
pip install .
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick tour
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
sqlitexplorer tables app.db # tables and views with their row counts
|
|
32
|
+
sqlitexplorer schema app.db [users] # CREATE statements, in creation order
|
|
33
|
+
sqlitexplorer describe app.db users # columns: type, NOT NULL, default, primary key
|
|
34
|
+
sqlitexplorer indexes app.db [users] # indexes and the columns they cover
|
|
35
|
+
sqlitexplorer foreign-keys app.db [posts] # foreign keys
|
|
36
|
+
sqlitexplorer info app.db [--check] # size, pragmas, object counts, integrity check
|
|
37
|
+
sqlitexplorer show app.db users # rows of a table or view
|
|
38
|
+
sqlitexplorer stats app.db users # nulls, distinct, min, max, top values per column
|
|
39
|
+
sqlitexplorer search app.db "marie" # find a text in every column of every table
|
|
40
|
+
sqlitexplorer query app.db "SELECT ..." # run SQL
|
|
41
|
+
sqlitexplorer chart app.db "SELECT day, total FROM sales ORDER BY day"
|
|
42
|
+
sqlitexplorer dump app.db # the whole database as SQL
|
|
43
|
+
sqlitexplorer export app.db users -o users.csv # rows to a file
|
|
44
|
+
sqlitexplorer import app.db people people.csv # a file into a table
|
|
45
|
+
sqlitexplorer diff app.db backup.db # compare two schemas
|
|
46
|
+
sqlitexplorer shell app.db # interactive shell
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Every command has `--help`. Databases are opened read-only and are never
|
|
50
|
+
created; commands that change data need `--write`, except `import`, which
|
|
51
|
+
always writes.
|
|
52
|
+
|
|
53
|
+
## Exploring
|
|
54
|
+
|
|
55
|
+
`show` accepts filters so most questions need no SQL:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
sqlitexplorer show app.db users -c name,age --where "age > 18" --order-by age --desc -n 20 --offset 40
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`--columns` and `--order-by` are validated against the table; `--where` is a
|
|
62
|
+
raw SQL condition.
|
|
63
|
+
|
|
64
|
+
`stats` reports, for each column, the declared type, how many NULLs, how many
|
|
65
|
+
distinct values, the minimum, the maximum and the most frequent values
|
|
66
|
+
(`--top N`). Everything but the frequent values comes from a single pass over
|
|
67
|
+
the table; on big tables use `--top 0` to skip them, `--columns` to analyse
|
|
68
|
+
only some columns, or `--sample N` to work on a random sample of N rows (the
|
|
69
|
+
output then says so). Likewise `tables --no-count` skips the row counts.
|
|
70
|
+
|
|
71
|
+
`search` looks for a case-insensitive substring in every non-BLOB column of
|
|
72
|
+
every table (`--table` restricts it, `--limit` stops early) and prints the
|
|
73
|
+
table, column, rowid and value of each match. Each table is scanned once.
|
|
74
|
+
|
|
75
|
+
## Output options
|
|
76
|
+
|
|
77
|
+
Every command that prints rows takes the same options:
|
|
78
|
+
|
|
79
|
+
| Option | Effect |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `--format`, `-f` | `table` (default), `csv`, `tsv`, `json` or `markdown` |
|
|
82
|
+
| `--null TEXT` | text shown for NULL values (default `NULL`) |
|
|
83
|
+
| `--truncate N` | cut values longer than N characters |
|
|
84
|
+
| `--page N`, `--page-size M` | print only one page of the rows; the footer goes to stderr |
|
|
85
|
+
| `--pager` | send the output to `$PAGER` (default `less -R`) when on a terminal |
|
|
86
|
+
| `--color` / `--no-color` | force or disable ANSI colors; by default only on a terminal, never when `NO_COLOR` is set |
|
|
87
|
+
| `--width N` | width to fit tables into (default: the terminal width) |
|
|
88
|
+
|
|
89
|
+
`NULL` and `BLOB` values are printed as SQL literals (`NULL`, `X'0102'`). In
|
|
90
|
+
the JSON format NULL becomes `null`, BLOBs are base64 strings and values are
|
|
91
|
+
never truncated.
|
|
92
|
+
|
|
93
|
+
When a table is wider than the terminal, the widest columns are narrowed and
|
|
94
|
+
their values wrapped so that every column and label stays visible. Use
|
|
95
|
+
`--width` or another format to get the values on one line.
|
|
96
|
+
|
|
97
|
+
Big results do not need to fit in memory: `--page` fetches only the requested
|
|
98
|
+
page (in SQL for `show`, from the cursor for `query`), and the csv, tsv, json
|
|
99
|
+
and markdown formats, `export` and `dump` are written row by row. The table
|
|
100
|
+
format is the exception, since it needs every row to size its columns.
|
|
101
|
+
|
|
102
|
+
## Queries
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
sqlitexplorer query app.db "SELECT name, age FROM users WHERE age > :min" -p min=30
|
|
106
|
+
sqlitexplorer query app.db --file report.sql # several statements, one transaction
|
|
107
|
+
echo "SELECT COUNT(*) FROM users" | sqlitexplorer query app.db -
|
|
108
|
+
sqlitexplorer query app.db "SELECT ..." --attach old=backup.db # then use old.users
|
|
109
|
+
sqlitexplorer query app.db "SELECT ..." --explain # EXPLAIN QUERY PLAN as a tree
|
|
110
|
+
sqlitexplorer query app.db "SELECT ..." --time # rows and elapsed time on stderr
|
|
111
|
+
sqlitexplorer query app.db "SELECT COUNT(*) FROM jobs" --watch 2 # re-run every 2 s, Ctrl-C stops
|
|
112
|
+
sqlitexplorer query app.db "DELETE FROM users WHERE age IS NULL" --write
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Several statements can be given at once (separated by `;`); they run in one
|
|
116
|
+
transaction that is committed at the end and rolled back on the first error.
|
|
117
|
+
`--param` values that look like numbers are bound as numbers. Attached
|
|
118
|
+
databases follow the read-only rule of the main one.
|
|
119
|
+
|
|
120
|
+
## Charts
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
sqlitexplorer chart app.db "SELECT day, sales, returns FROM daily ORDER BY day"
|
|
124
|
+
sqlitexplorer chart app.db "SELECT age FROM users" --kind hist --bins 20
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The first column is the X axis (numbers or ISO dates), every other column is a
|
|
128
|
+
series named after the column; rows with NULLs are skipped and counted on
|
|
129
|
+
stderr. `--kind` selects `line` (default), `scatter` or `hist` (first column
|
|
130
|
+
only, `--bins`). `--height`, `--width`, `--x-label`, `--y-label` and `--color`
|
|
131
|
+
adjust the drawing.
|
|
132
|
+
|
|
133
|
+
## Export, import, dump and diff
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
sqlitexplorer dump app.db -o backup.sql # replayable SQL, like .dump
|
|
137
|
+
sqlitexplorer export app.db users -f json -o users.json
|
|
138
|
+
sqlitexplorer export app.db --all -o exported/ -f csv # one file per table and view
|
|
139
|
+
sqlitexplorer import app.db people people.csv # csv, tsv or json (list of objects)
|
|
140
|
+
sqlitexplorer diff app.db backup.db # exit status 1 when the schemas differ
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`import` creates the table when it does not exist, inferring INTEGER, REAL or
|
|
144
|
+
TEXT for each column; empty CSV cells become NULL. The format comes from the
|
|
145
|
+
file extension unless `--format` is given.
|
|
146
|
+
|
|
147
|
+
## Shell
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
$ sqlitexplorer shell app.db
|
|
151
|
+
sqlitexplorer> SELECT name
|
|
152
|
+
...> FROM users;
|
|
153
|
+
sqlitexplorer> .tables
|
|
154
|
+
sqlitexplorer> .format json
|
|
155
|
+
sqlitexplorer> .quit
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Statements end with `;` and may span several lines. Dot-commands: `.tables`,
|
|
159
|
+
`.schema [NAME]`, `.describe TABLE`, `.indexes [TABLE]`, `.stats TABLE`,
|
|
160
|
+
`.format FORMAT`, `.null TEXT`, `.truncate N|off`, `.help` and `.quit`. Tab
|
|
161
|
+
completes SQL keywords, table and column names; the history is kept in
|
|
162
|
+
`$XDG_STATE_HOME/sqlitexplorer/history` (`~/.local/state` by default). With
|
|
163
|
+
`--write` every statement is committed as soon as it succeeds. SQL can also be
|
|
164
|
+
piped into the shell.
|
|
165
|
+
|
|
166
|
+
Completion of the command line itself (commands, options and table names) is
|
|
167
|
+
installed with `sqlitexplorer --install-completion`.
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
uv venv
|
|
173
|
+
uv pip install -e ".[dev]"
|
|
174
|
+
uv run pytest
|
|
175
|
+
uv run ruff check .
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Releasing
|
|
179
|
+
|
|
180
|
+
Releases are driven by version tags. Pushing `vX.Y.Z` runs the tests, builds
|
|
181
|
+
the distributions, publishes them to PyPI with
|
|
182
|
+
[trusted publishing](https://docs.pypi.org/trusted-publishers/) and creates a
|
|
183
|
+
GitHub release with the artifacts attached.
|
|
184
|
+
|
|
185
|
+
```sh
|
|
186
|
+
uv version 0.3.0 # or: uv version --bump minor
|
|
187
|
+
git commit -am "Release 0.3.0"
|
|
188
|
+
git tag v0.3.0
|
|
189
|
+
git push origin master v0.3.0
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The tag must match the version in `pyproject.toml`; the workflow refuses to
|
|
193
|
+
publish otherwise. Before the first release, register the repository as a
|
|
194
|
+
trusted publisher of the project on PyPI with the workflow name `release.yml`
|
|
195
|
+
and the environment `pypi`, and create that environment in the repository
|
|
196
|
+
settings on GitHub.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sqlitexplorer"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Explore SQLite databases from the terminal: tables, schema, stats, search, queries, charts, export/import and an interactive shell."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Carlos A. Planchón", email = "carlosandresplanchonprestes@gmail.com" },
|
|
15
|
+
]
|
|
16
|
+
keywords = ["sqlite", "sqlite3", "database", "cli", "terminal", "explorer", "chart", "shell", "repl"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Topic :: Database",
|
|
21
|
+
"Topic :: Database :: Front-Ends",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Programming Language :: Python :: 3.14",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"outfancy>=0.11",
|
|
31
|
+
"plotille>=6",
|
|
32
|
+
"typer>=0.12",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.optional-dependencies]
|
|
36
|
+
dev = [
|
|
37
|
+
"pytest>=8",
|
|
38
|
+
"ruff",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
sqlitexplorer = "sqlitexplorer.cli:main"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Repository = "https://github.com/carlosplanchon/sqlitexplorer.git"
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
include = ["sqlitexplorer*"]
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
testpaths = ["tests"]
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
line-length = 100
|
|
55
|
+
target-version = "py310"
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Explore SQLite databases from the terminal."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("sqlitexplorer")
|
|
7
|
+
except PackageNotFoundError: # pragma: no cover - source checkout that was never installed
|
|
8
|
+
__version__ = "0.0.0+unknown"
|
|
9
|
+
|
|
10
|
+
__all__ = ["__version__"]
|