From 71664b8fcf5e4a5331291f130c955a1ad1a9996d Mon Sep 17 00:00:00 2001 From: Parker Gurney Date: Wed, 5 Aug 2026 14:06:58 -0700 Subject: [PATCH] insert-files: support fixed value columns via -c colname:text:value Extends the -c/--column spec so a column can be populated with a literal value for every inserted file, e.g. -c file_type:text:gif, without a separate update pass. Existing colname:coldef shorthands and compound --pk behavior are unchanged. Closes #140 --- docs/cli.rst | 7 +++++ sqlite_utils/cli.py | 15 +++++++++-- tests/test_insert_files.py | 54 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/docs/cli.rst b/docs/cli.rst index 2e506dd..a4b88ce 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -1747,6 +1747,13 @@ You can change the name of one of these columns using a ``-c colname:coldef`` pa sqlite-utils insert-files gifs.db images *.gif \ -c path -c md5 -c last_modified:mtime --pk=path +You can also populate a column with a fixed value for every file using a ``-c colname:text:value`` parameter. This is useful for tagging every row from a given import with the same value, without a separate update pass: + +.. code-block:: bash + + sqlite-utils insert-files gifs.db images *.gif \ + -c path -c content -c file_type:text:gif --pk=path + You can pass ``--replace`` or ``--upsert`` to indicate what should happen if you try to insert a file with an existing primary key. Pass ``--alter`` to cause any missing columns to be added to the table. The full list of column definitions you can use is as follows: diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index dab4b67..169849d 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -2978,8 +2978,19 @@ def insert_files( "size": lambda p, data=stdin_data: len(data), } for coldef in column: - if ":" in coldef: - colname, coltype = coldef.rsplit(":", 1) + parts = coldef.split(":", 2) + if len(parts) == 3: + # Fixed value, e.g. -c file_type:text:gif + colname, coltype, fixed_value = parts + if coltype != "text": + raise click.ClickException( + "Fixed value column definitions must use " + "'colname:text:value', not '{}'".format(coldef) + ) + row[colname] = fixed_value + continue + elif len(parts) == 2: + colname, coltype = parts else: colname, coltype = coldef, coldef try: diff --git a/tests/test_insert_files.py b/tests/test_insert_files.py index 1724d2d..8894aea 100644 --- a/tests/test_insert_files.py +++ b/tests/test_insert_files.py @@ -117,6 +117,60 @@ def test_insert_files(silent, pk_args, expected_pks): assert set(db["files"].pks) == set(expected_pks) +def test_insert_files_fixed_value_column(): + runner = CliRunner() + with runner.isolated_filesystem(): + tmpdir = pathlib.Path(".") + db_path = str(tmpdir / "files.db") + (tmpdir / "one.gif").write_text("gif content", "utf-8") + result = runner.invoke( + cli.cli, + [ + "insert-files", + db_path, + "files", + str(tmpdir / "one.gif"), + "-c", + "path", + "-c", + "content", + "-c", + "file_type:text:gif", + "--pk", + "path", + "--pk", + "file_type", + ], + catch_exceptions=False, + ) + assert result.exit_code == 0, result.output + db = Database(db_path) + row = next(iter(db["files"].rows)) + assert row["file_type"] == "gif" + assert set(db["files"].pks) == {"path", "file_type"} + + +def test_insert_files_fixed_value_column_bad_type(): + runner = CliRunner() + with runner.isolated_filesystem(): + tmpdir = pathlib.Path(".") + db_path = str(tmpdir / "files.db") + (tmpdir / "one.gif").write_text("gif content", "utf-8") + result = runner.invoke( + cli.cli, + [ + "insert-files", + db_path, + "files", + str(tmpdir / "one.gif"), + "-c", + "file_type:mtime:gif", + ], + ) + assert result.exit_code == 1 + assert "colname:text:value" in result.output + + @pytest.mark.parametrize( "use_text,encoding,input,expected", (