Skip to content

Commit

Permalink
New help for --lines and --all and --convert and --import, refs #356
Browse files Browse the repository at this point in the history
  • Loading branch information
simonw committed Jan 6, 2022
1 parent f3fd861 commit 9e286cc
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 19 deletions.
2 changes: 1 addition & 1 deletion docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ This supports nested imports as well, for example to use `ElementTree <https://d
'xml.etree.ElementTree.fromstring(value).attrib["title"]' \
--import=xml.etree.ElementTree

Your code will be automatically wrapped in a function, but you can also define a function called `convert(value)` which will be called, if available::
Your code will be automatically wrapped in a function, but you can also define a function called ``convert(value)`` which will be called, if available::

$ sqlite-utils convert content.db articles headline '
def convert(value):
Expand Down
98 changes: 80 additions & 18 deletions sqlite_utils/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,14 +639,34 @@ def insert_upsert_options(fn):
required=True,
),
click.argument("table"),
click.argument("json_file", type=click.File("rb"), required=True),
click.argument("file", type=click.File("rb"), required=True),
click.option(
"--pk", help="Columns to use as the primary key, e.g. id", multiple=True
),
click.option(
"--flatten",
is_flag=True,
help='Flatten nested JSON objects, so {"a": {"b": 1}} becomes {"a_b": 1}',
),
click.option("--nl", is_flag=True, help="Expect newline-delimited JSON"),
click.option("--flatten", is_flag=True, help="Flatten nested JSON objects"),
click.option("-c", "--csv", is_flag=True, help="Expect CSV"),
click.option("--tsv", is_flag=True, help="Expect TSV"),
click.option("-c", "--csv", is_flag=True, help="Expect CSV input"),
click.option("--tsv", is_flag=True, help="Expect TSV input"),
click.option(
"--lines",
is_flag=True,
help="Treat each line as a single value called 'line'",
),
click.option(
"--all", is_flag=True, help="Treat input as a single value called 'all'"
),
click.option("--convert", help="Python code to convert each item"),
click.option(
"--import",
"imports",
type=str,
multiple=True,
help="Python modules to import",
),
click.option("--delimiter", help="Delimiter to use for CSV files"),
click.option("--quotechar", help="Quote character to use for CSV/TSV"),
click.option(
Expand Down Expand Up @@ -696,12 +716,16 @@ def insert_upsert_options(fn):
def insert_upsert_implementation(
path,
table,
json_file,
file,
pk,
nl,
flatten,
nl,
csv,
tsv,
lines,
all,
convert,
imports,
delimiter,
quotechar,
sniff,
Expand Down Expand Up @@ -732,7 +756,7 @@ def insert_upsert_implementation(
if pk and len(pk) == 1:
pk = pk[0]
encoding = encoding or "utf-8-sig"
buffered = io.BufferedReader(json_file, buffer_size=4096)
buffered = io.BufferedReader(file, buffer_size=4096)
decoded = io.TextIOWrapper(buffered, encoding=encoding)
tracker = None
if csv or tsv:
Expand All @@ -759,6 +783,9 @@ def insert_upsert_implementation(
if detect_types:
tracker = TypeTracker()
docs = tracker.wrap(docs)
elif convert:
fn = _compile_code(convert, imports)
docs = (fn(line) for line in decoded)
else:
try:
if nl:
Expand Down Expand Up @@ -851,12 +878,16 @@ def _find_variables(tb, vars):
def insert(
path,
table,
json_file,
file,
pk,
nl,
flatten,
nl,
csv,
tsv,
lines,
all,
convert,
imports,
delimiter,
quotechar,
sniff,
Expand All @@ -874,21 +905,40 @@ def insert(
default,
):
"""
Insert records from JSON file into a table, creating the table if it
Insert records from FILE into a table, creating the table if it
does not already exist.
Input should be a JSON array of objects, unless --nl or --csv is used.
By default the input is expected to be a JSON array of objects. Or:
\b
- Use --nl for newline-delimited JSON objects
- Use --csv or --tsv for comma-separated or tab-separated input
- Use --lines to write each incoming line to a column called "line"
- Use --all to write the entire input to a column called "all"
You can also use --convert to pass a fragment of Python code that will
be used to convert each input.
Your Python code will be passed a "row" variable representing the
imported row, and can return a modified row.
If you are using --lines your code will be passed a "line" variable,
and for --all an "all" variable.
"""
try:
insert_upsert_implementation(
path,
table,
json_file,
file,
pk,
nl,
flatten,
nl,
csv,
tsv,
lines,
all,
convert,
imports,
delimiter,
quotechar,
sniff,
Expand All @@ -915,12 +965,16 @@ def insert(
def upsert(
path,
table,
json_file,
file,
pk,
nl,
flatten,
nl,
csv,
tsv,
lines,
all,
convert,
imports,
batch_size,
delimiter,
quotechar,
Expand All @@ -943,12 +997,16 @@ def upsert(
insert_upsert_implementation(
path,
table,
json_file,
file,
pk,
nl,
flatten,
nl,
csv,
tsv,
lines,
all,
convert,
imports,
delimiter,
quotechar,
sniff,
Expand Down Expand Up @@ -1191,7 +1249,11 @@ def query(
multiple=True,
help="Additional databases to attach - specify alias and filepath",
)
@click.option("--flatten", is_flag=True, help="Flatten nested JSON objects")
@click.option(
"--flatten",
is_flag=True,
help='Flatten nested JSON objects, so {"foo": {"bar": 1}} becomes {"foo_bar": 1}',
)
@output_options
@click.option("-r", "--raw", is_flag=True, help="Raw output, first column of first row")
@click.option(
Expand Down

0 comments on commit 9e286cc

Please sign in to comment.