mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-08-02 15:34:10 +02:00
Added --table and --fmt options for table output using tabulate
This commit is contained in:
parent
dbf239e3fc
commit
6c3f5e6479
4 changed files with 101 additions and 13 deletions
31
docs/cli.rst
31
docs/cli.rst
|
|
@ -60,7 +60,7 @@ If you want to pretty-print the output further, you can pipe it through ``python
|
|||
Running queries and returning CSV
|
||||
=================================
|
||||
|
||||
You can use the ``--csv`` option to return results as CSV::
|
||||
You can use the ``--csv`` option (or ``-c`` shortcut) to return results as CSV::
|
||||
|
||||
$ sqlite-utils dogs.db "select * from dogs" --csv
|
||||
id,age,name
|
||||
|
|
@ -73,6 +73,31 @@ This will default to including the column names as a header row. To exclude the
|
|||
1,4,Cleo
|
||||
2,2,Pancakes
|
||||
|
||||
.. _cli_query_table:
|
||||
|
||||
Running queries and outputting a table
|
||||
======================================
|
||||
|
||||
You can use the ``--table`` option (or ``-t`` shortcut) to output query results as a table::
|
||||
|
||||
$ sqlite-utils dogs.db "select * from dogs" --table
|
||||
id age name
|
||||
---- ----- --------
|
||||
1 4 Cleo
|
||||
2 2 Pancakes
|
||||
|
||||
You can use the ``--fmt`` (or ``-f``) option to specify different table formats, for example ``rst`` for reStructuredText::
|
||||
|
||||
$ sqlite-utils dogs.db "select * from dogs" --table --fmt rst
|
||||
==== ===== ========
|
||||
id age name
|
||||
==== ===== ========
|
||||
1 4 Cleo
|
||||
2 2 Pancakes
|
||||
==== ===== ========
|
||||
|
||||
For a full list of table format options, run ``sqlite-utils query --help``.
|
||||
|
||||
.. _cli_rows:
|
||||
|
||||
Returning all rows in a table
|
||||
|
|
@ -84,7 +109,7 @@ You can return every row in a specified table using the ``rows`` subcommand::
|
|||
[{"id": 1, "age": 4, "name": "Cleo"},
|
||||
{"id": 2, "age": 2, "name": "Pancakes"}]
|
||||
|
||||
This command accepts the same output options as ``query`` - so you can pass ``--nl``, ``--csv`` and ``--no-headers``.
|
||||
This command accepts the same output options as ``query`` - so you can pass ``--nl``, ``--csv``, ``--no-headers``, ``--table`` and ``--fmt``.
|
||||
|
||||
.. _cli_tables:
|
||||
|
||||
|
|
@ -124,7 +149,7 @@ Use ``--columns`` to include a list of columns in each table::
|
|||
{"table": "Gosh2", "count": 0, "columns": ["c1", "c2", "c3"]},
|
||||
{"table": "dogs", "count": 2, "columns": ["id", "age", "name"]}]
|
||||
|
||||
The ``--nl``, ``--csv`` and ``--no-headers`` options are all available.
|
||||
The ``--nl``, ``--csv`` and ``--table`` options are all available.
|
||||
|
||||
.. _cli_inserting_data:
|
||||
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -22,7 +22,7 @@ setup(
|
|||
version=VERSION,
|
||||
license="Apache License, Version 2.0",
|
||||
packages=find_packages(),
|
||||
install_requires=["click", "click-default-group"],
|
||||
install_requires=["click", "click-default-group", "tabulate"],
|
||||
setup_requires=["pytest-runner"],
|
||||
extras_require={"test": ["pytest", "black"]},
|
||||
entry_points="""
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import itertools
|
|||
import json
|
||||
import sys
|
||||
import csv as csv_std
|
||||
import tabulate
|
||||
import sqlite3
|
||||
|
||||
|
||||
|
|
@ -23,8 +24,17 @@ def output_options(fn):
|
|||
is_flag=True,
|
||||
default=False,
|
||||
),
|
||||
click.option("--csv", is_flag=True, help="Output CSV"),
|
||||
click.option("-c", "--csv", is_flag=True, help="Output CSV"),
|
||||
click.option("--no-headers", is_flag=True, help="Omit CSV headers"),
|
||||
click.option("-t", "--table", is_flag=True, help="Output as a table"),
|
||||
click.option(
|
||||
"-f",
|
||||
"--fmt",
|
||||
help="Table format - one of {}".format(
|
||||
", ".join(tabulate.tabulate_formats)
|
||||
),
|
||||
default="simple",
|
||||
),
|
||||
)
|
||||
):
|
||||
fn = decorator(fn)
|
||||
|
|
@ -60,7 +70,7 @@ def cli():
|
|||
is_flag=True,
|
||||
default=False,
|
||||
)
|
||||
def tables(path, fts4, fts5, counts, nl, arrays, csv, no_headers, columns):
|
||||
def tables(path, fts4, fts5, counts, nl, arrays, csv, no_headers, table, fmt, columns):
|
||||
"""List the tables in the database"""
|
||||
db = sqlite_utils.Database(path)
|
||||
headers = ["table"]
|
||||
|
|
@ -82,7 +92,9 @@ def tables(path, fts4, fts5, counts, nl, arrays, csv, no_headers, columns):
|
|||
row.append(cols)
|
||||
yield row
|
||||
|
||||
if csv:
|
||||
if table:
|
||||
print(tabulate.tabulate(_iter(), headers=headers, tablefmt=fmt))
|
||||
elif csv:
|
||||
writer = csv_std.writer(sys.stdout)
|
||||
if not no_headers:
|
||||
writer.writerow(headers)
|
||||
|
|
@ -175,7 +187,7 @@ def insert_upsert_options(fn):
|
|||
click.argument("json_file", type=click.File(), required=True),
|
||||
click.option("--pk", help="Column to use as the primary key, e.g. id"),
|
||||
click.option("--nl", is_flag=True, help="Expect newline-delimited JSON"),
|
||||
click.option("--csv", is_flag=True, help="Expect CSV"),
|
||||
click.option("-c", "--csv", is_flag=True, help="Expect CSV"),
|
||||
click.option(
|
||||
"--batch-size", type=int, default=100, help="Commit every X records"
|
||||
),
|
||||
|
|
@ -244,12 +256,14 @@ def upsert(path, table, json_file, pk, nl, csv, batch_size):
|
|||
)
|
||||
@click.argument("sql")
|
||||
@output_options
|
||||
def query(path, sql, nl, arrays, csv, no_headers):
|
||||
def query(path, sql, nl, arrays, csv, no_headers, table, fmt):
|
||||
"Execute SQL query and return the results as JSON"
|
||||
db = sqlite_utils.Database(path)
|
||||
cursor = iter(db.conn.execute(sql))
|
||||
headers = [c[0] for c in cursor.description]
|
||||
if csv:
|
||||
if table:
|
||||
print(tabulate.tabulate(list(cursor), headers=headers, tablefmt=fmt))
|
||||
elif csv:
|
||||
writer = csv_std.writer(sys.stdout)
|
||||
if not no_headers:
|
||||
writer.writerow([c[0] for c in cursor.description])
|
||||
|
|
@ -266,19 +280,21 @@ def query(path, sql, nl, arrays, csv, no_headers):
|
|||
type=click.Path(file_okay=True, dir_okay=False, allow_dash=False),
|
||||
required=True,
|
||||
)
|
||||
@click.argument("table")
|
||||
@click.argument("dbtable")
|
||||
@output_options
|
||||
@click.pass_context
|
||||
def rows(ctx, path, table, nl, arrays, csv, no_headers):
|
||||
def rows(ctx, path, dbtable, nl, arrays, csv, no_headers, table, fmt):
|
||||
"Output all rows in the specified table"
|
||||
ctx.invoke(
|
||||
query,
|
||||
path=path,
|
||||
sql="select * from [{}]".format(table),
|
||||
sql="select * from [{}]".format(dbtable),
|
||||
nl=nl,
|
||||
arrays=arrays,
|
||||
csv=csv,
|
||||
no_headers=no_headers,
|
||||
table=table,
|
||||
fmt=fmt,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,53 @@ def test_tables_counts_and_columns_csv(db_path):
|
|||
) == result.output.strip()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"fmt,expected",
|
||||
[
|
||||
(
|
||||
"simple",
|
||||
(
|
||||
"c1 c2 c3\n"
|
||||
"----- ----- ----------\n"
|
||||
"verb0 noun0 adjective0\n"
|
||||
"verb1 noun1 adjective1\n"
|
||||
"verb2 noun2 adjective2\n"
|
||||
"verb3 noun3 adjective3"
|
||||
),
|
||||
),
|
||||
(
|
||||
"rst",
|
||||
(
|
||||
"===== ===== ==========\n"
|
||||
"c1 c2 c3\n"
|
||||
"===== ===== ==========\n"
|
||||
"verb0 noun0 adjective0\n"
|
||||
"verb1 noun1 adjective1\n"
|
||||
"verb2 noun2 adjective2\n"
|
||||
"verb3 noun3 adjective3\n"
|
||||
"===== ===== =========="
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_output_table(db_path, fmt, expected):
|
||||
db = Database(db_path)
|
||||
with db.conn:
|
||||
db["rows"].insert_all(
|
||||
[
|
||||
{
|
||||
"c1": "verb{}".format(i),
|
||||
"c2": "noun{}".format(i),
|
||||
"c3": "adjective{}".format(i),
|
||||
}
|
||||
for i in range(4)
|
||||
]
|
||||
)
|
||||
result = CliRunner().invoke(cli.cli, ["rows", db_path, "rows", "-t", "-f", fmt])
|
||||
assert 0 == result.exit_code
|
||||
assert expected == result.output.strip()
|
||||
|
||||
|
||||
def test_enable_fts(db_path):
|
||||
assert None == Database(db_path)["Gosh"].detect_fts()
|
||||
result = CliRunner().invoke(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue