simonw / sqlite-utils

Python CLI utility and library for manipulating SQLite databases
https://sqlite-utils.datasette.io
Apache License 2.0
1.62k stars 109 forks source link

`--raw-lines` option, like `--raw` for multiple lines #539

Closed simonw closed 1 year ago

simonw commented 1 year ago

I wanted to output newline-separated output of the first column of every row in the results - like --row but for more than one line.

simonw commented 1 year ago

Prototype:

diff --git a/docs/cli-reference.rst b/docs/cli-reference.rst
index 153e5f9..c830518 100644
--- a/docs/cli-reference.rst
+++ b/docs/cli-reference.rst
@@ -124,6 +124,7 @@ See :ref:`cli_query`.
       --json-cols                 Detect JSON cols and output them as JSON, not
                                   escaped strings
       -r, --raw                   Raw output, first column of first row
+      --raw-lines                 Raw output, first column of each row
       -p, --param <TEXT TEXT>...  Named :parameters for SQL query
       --functions TEXT            Python code defining one or more custom SQL
                                   functions
@@ -192,6 +193,7 @@ See :ref:`cli_memory`.
       --json-cols                 Detect JSON cols and output them as JSON, not
                                   escaped strings
       -r, --raw                   Raw output, first column of first row
+      --raw-lines                 Raw output, first column of each row
       -p, --param <TEXT TEXT>...  Named :parameters for SQL query
       --encoding TEXT             Character encoding for CSV input, defaults to
                                   utf-8
diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py
index d25b1df..da0e4b6 100644
--- a/sqlite_utils/cli.py
+++ b/sqlite_utils/cli.py
@@ -1653,6 +1653,7 @@ def drop_view(path, view, ignore, load_extension):
 )
 @output_options
 @click.option("-r", "--raw", is_flag=True, help="Raw output, first column of first row")
+@click.option("--raw-lines", is_flag=True, help="Raw output, first column of each row")
 @click.option(
     "-p",
     "--param",
@@ -1677,6 +1678,7 @@ def query(
     fmt,
     json_cols,
     raw,
+    raw_lines,
     param,
     load_extension,
     functions,
@@ -1700,7 +1702,19 @@ def query(
         _register_functions(db, functions)

     _execute_query(
-        db, sql, param, raw, table, csv, tsv, no_headers, fmt, nl, arrays, json_cols
+        db,
+        sql,
+        param,
+        raw,
+        raw_lines,
+        table,
+        csv,
+        tsv,
+        no_headers,
+        fmt,
+        nl,
+        arrays,
+        json_cols,
     )

@@ -1728,6 +1742,7 @@ def query(
 )
 @output_options
 @click.option("-r", "--raw", is_flag=True, help="Raw output, first column of first row")
+@click.option("--raw-lines", is_flag=True, help="Raw output, first column of each row")
 @click.option(
     "-p",
     "--param",
@@ -1773,6 +1788,7 @@ def memory(
     fmt,
     json_cols,
     raw,
+    raw_lines,
     param,
     encoding,
     no_detect_types,
@@ -1879,12 +1895,36 @@ def memory(
         _register_functions(db, functions)

     _execute_query(
-        db, sql, param, raw, table, csv, tsv, no_headers, fmt, nl, arrays, json_cols
+        db,
+        sql,
+        param,
+        raw,
+        raw_lines,
+        table,
+        csv,
+        tsv,
+        no_headers,
+        fmt,
+        nl,
+        arrays,
+        json_cols,
     )

 def _execute_query(
-    db, sql, param, raw, table, csv, tsv, no_headers, fmt, nl, arrays, json_cols
+    db,
+    sql,
+    param,
+    raw,
+    raw_lines,
+    table,
+    csv,
+    tsv,
+    no_headers,
+    fmt,
+    nl,
+    arrays,
+    json_cols,
 ):
     with db.conn:
         try:
@@ -1903,6 +1943,13 @@ def _execute_query(
                 sys.stdout.buffer.write(data)
             else:
                 sys.stdout.write(str(data))
+        elif raw_lines:
+            for row in cursor:
+                data = row[0]
+                if isinstance(data, bytes):
+                    sys.stdout.buffer.write(data + b"\n")
+                else:
+                    sys.stdout.write(str(data) + "\n")
         elif fmt or table:
             print(
                 tabulate.tabulate(

Needs tests and more documentation.

simonw commented 1 year ago

I'm tempted to upgrade --raw to do this instead, but that would be a breaking change.

simonw commented 1 year ago

This worked:

sqlite-utils memory /tmp/books3.json:nl \
  'select name from books3' --raw-lines > titles.txt
simonw commented 1 year ago

Documentation: