From bc8409941fb609eba646c29ae3ec40b8cdd122a4 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sun, 26 Jul 2020 09:43:45 -0700 Subject: [PATCH] --raw option, refs #123 --- docs/cli.rst | 11 +++++++++++ sqlite_utils/cli.py | 11 +++++++++-- tests/test_cli.py | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/cli.rst b/docs/cli.rst index 55be13c..cbcf1ee 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -142,6 +142,17 @@ You can use the ``--fmt`` (or ``-f``) option to specify different table formats, For a full list of table format options, run ``sqlite-utils query --help``. +.. _cli_query_raw: + +Returning raw data from a query, such as binary content +======================================================= + +If your table contains binary data in a ``BLOB`` you can use the ``--raw`` option to output specific columns directly to standard out. + +For example, to retrieve a binary image from a ``BLOB`` column and store it in a file you can use the following:: + + $ sqlite-utils photos.db "select contents from photos where id=1" --raw > myphoto.jpg + .. _cli_rows: Returning all rows in a table diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index 7c87945..4e70fd4 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -675,7 +675,8 @@ def drop_view(path, view): ) @click.argument("sql") @output_options -def query(path, sql, nl, arrays, csv, no_headers, table, fmt, json_cols): +@click.option("-r", "--raw", is_flag=True, help="Raw output, first column of first row") +def query(path, sql, nl, arrays, csv, no_headers, table, fmt, json_cols, raw): "Execute SQL query and return the results as JSON" db = sqlite_utils.Database(path) with db.conn: @@ -686,7 +687,13 @@ def query(path, sql, nl, arrays, csv, no_headers, table, fmt, json_cols): cursor = [[cursor.rowcount]] else: headers = [c[0] for c in cursor.description] - if table: + if raw: + data = cursor.fetchone()[0] + if isinstance(data, bytes): + sys.stdout.buffer.write(data) + else: + sys.stdout.write(str(data)) + elif table: print(tabulate.tabulate(list(cursor), headers=headers, tablefmt=fmt)) elif csv: writer = csv_std.writer(sys.stdout) diff --git a/tests/test_cli.py b/tests/test_cli.py index e9a317d..bf4e8ce 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -797,6 +797,21 @@ def test_query_json_with_json_cols(db_path): assert expected == result_rows.output.strip() +@pytest.mark.parametrize( + "content,is_binary", + [(b"\x00\x0Fbinary", True), ("this is text", False), (1, False), (1.5, False)], +) +def test_query_raw(db_path, content, is_binary): + Database(db_path)["files"].insert({"content": content}) + result = CliRunner().invoke( + cli.cli, [db_path, "select content from files", "--raw"] + ) + if is_binary: + assert result.stdout_bytes == content + else: + assert result.output == str(content) + + def test_query_memory_does_not_create_file(tmpdir): owd = os.getcwd() try: