From 18f190e28334d821be78a1dbbf31d7610fc1f9c1 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 22 Jul 2023 12:48:04 -0700 Subject: [PATCH] sqlite-utils rename-table command, refs #565 --- docs/cli-reference.rst | 23 +++++++++++++++++++++++ docs/cli.rst | 13 +++++++++++++ sqlite_utils/cli.py | 25 +++++++++++++++++++++++++ tests/test_cli.py | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) diff --git a/docs/cli-reference.rst b/docs/cli-reference.rst index 9f9a4e8..68dc1d2 100644 --- a/docs/cli-reference.rst +++ b/docs/cli-reference.rst @@ -40,6 +40,8 @@ This page lists the ``--help`` for every ``sqlite-utils`` CLI sub-command. "vacuum": "cli_vacuum", "dump": "cli_dump", "add-column": "cli_add_column", + "rename-table": "cli_renaming_tables", + "duplicate": "cli_duplicate_table", "add-foreign-key": "cli_add_foreign_key", "add-foreign-keys": "cli_add_foreign_keys", "index-foreign-keys": "cli_index_foreign_keys", @@ -1328,6 +1330,8 @@ reset-counts duplicate ========= +See :ref:`cli_duplicate_table`. + :: Usage: sqlite-utils duplicate [OPTIONS] PATH TABLE NEW_TABLE @@ -1340,6 +1344,25 @@ duplicate -h, --help Show this message and exit. +.. _cli_ref_rename_table: + +rename-table +============ + +See :ref:`cli_renaming_tables`. + +:: + + Usage: sqlite-utils rename-table [OPTIONS] PATH TABLE NEW_NAME + + Rename this table. + + Options: + --ignore If table does not exist, do nothing + --load-extension TEXT Path to SQLite extension, with optional :entrypoint + -h, --help Show this message and exit. + + .. _cli_ref_drop_table: drop-table diff --git a/docs/cli.rst b/docs/cli.rst index 7ed53b6..e5df34c 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -1936,6 +1936,19 @@ If a table with the same name already exists, you will get an error. You can cho You can also pass ``--transform`` to transform the existing table to match the new schema. See :ref:`python_api_explicit_create` in the Python library documentation for details of how this option works. +.. _cli_renaming_tables: + +Renaming a table +================ + +Yo ucan rename a table using the ``rename-table`` command: + +.. code-block:: bash + + sqlite-utils rename-table mydb.db oldname newname + +Pass ``--ignore`` to ignore any errors caused by the table not existing, or the new name already being in use. + .. _cli_duplicate_table: Duplicating tables diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index e10de8c..00b3d6a 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -1584,6 +1584,31 @@ def duplicate(path, table, new_table, ignore, load_extension): raise click.ClickException('Table "{}" does not exist'.format(table)) +@cli.command(name="rename-table") +@click.argument( + "path", + type=click.Path(file_okay=True, dir_okay=False, allow_dash=False), + required=True, +) +@click.argument("table") +@click.argument("new_name") +@click.option("--ignore", is_flag=True, help="If table does not exist, do nothing") +@load_extension_option +def rename_table(path, table, new_name, ignore, load_extension): + """ + Rename this table. + """ + db = sqlite_utils.Database(path) + _load_extensions(db, load_extension) + try: + db.rename_table(table, new_name) + except sqlite3.OperationalError as ex: + if not ignore: + raise click.ClickException( + 'Table "{}" could not be renamed. {}'.format(table, str(ex)) + ) + + @cli.command(name="drop-table") @click.argument( "path", diff --git a/tests/test_cli.py b/tests/test_cli.py index 57e852a..305535b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2274,6 +2274,38 @@ def test_analyze(tmpdir, options, expected): assert list(db["sqlite_stat1"].rows) == expected +def test_rename_table(tmpdir): + db_path = str(tmpdir / "test.db") + db = Database(db_path) + db["one"].insert({"id": 1, "name": "Cleo"}, pk="id") + # First try a non-existent table + result_error = CliRunner().invoke( + cli.cli, + ["rename-table", db_path, "missing", "two"], + catch_exceptions=False, + ) + assert result_error.exit_code == 1 + assert result_error.output == ( + 'Error: Table "missing" could not be renamed. ' "no such table: missing\n" + ) + # And check --ignore works + result_error2 = CliRunner().invoke( + cli.cli, + ["rename-table", db_path, "missing", "two", "--ignore"], + catch_exceptions=False, + ) + assert result_error2.exit_code == 0 + previous_columns = db["one"].columns_dict + # Now try for a table that exists + result = CliRunner().invoke( + cli.cli, + ["rename-table", db_path, "one", "two"], + catch_exceptions=False, + ) + assert result.exit_code == 0 + assert db["two"].columns_dict == previous_columns + + def test_duplicate_table(tmpdir): db_path = str(tmpdir / "test.db") db = Database(db_path)