From 9f6085b4e4c8289b34c6a3d40ba72d77ed62b4ef Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sun, 3 May 2020 08:24:39 -0700 Subject: [PATCH] create-table --ignore and --replace, refs #27 --- docs/cli.rst | 2 ++ docs/python-api.rst | 2 ++ sqlite_utils/cli.py | 20 +++++++++++++++++++- tests/test_cli.py | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/docs/cli.rst b/docs/cli.rst index 6aa2833..7c0c9c5 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -399,6 +399,8 @@ You can specify foreign key relationships between the tables you are creating us [author_id] INTEGER REFERENCES [authors]([id]) ) +If a table with the same name already exists, you will get an error. You can choose to silently ignore this error with ``--ignore``, or you can replace the existing table with a new, empty table using ``--replace``. + .. _cli_add_column: Adding columns diff --git a/docs/python-api.rst b/docs/python-api.rst index ded39ce..148f794 100644 --- a/docs/python-api.rst +++ b/docs/python-api.rst @@ -262,6 +262,8 @@ The first argument here is a dictionary specifying the columns you would like to This method takes optional arguments ``pk=``, ``column_order=``, ``foreign_keys=``, ``not_null=set()`` and ``defaults=dict()`` - explained below. +You can pass ``ignore=True`` to silently ignore an existing table and do nothing, or ``replace=True`` to replace that table with a new, empty table. + .. _python_api_compound_primary_keys: Compound primary keys diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index a29c3af..8a7fabb 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -554,7 +554,13 @@ def upsert( type=(str, str, str), help="Column, other table, other column to set as a foreign key", ) -def create_table(path, table, columns, pk, not_null, default, fk): +@click.option( + "--ignore", is_flag=True, help="If table already exists, do nothing", +) +@click.option( + "--replace", is_flag=True, help="If table already exists, replace it", +) +def create_table(path, table, columns, pk, not_null, default, fk, ignore, replace): "Add an index to the specified table covering the specified columns" db = sqlite_utils.Database(path) if len(columns) % 2 == 1: @@ -571,6 +577,18 @@ def create_table(path, table, columns, pk, not_null, default, fk): "column types must be one of {}".format(VALID_COLUMN_TYPES) ) coltypes[name] = ctype.upper() + # Does table already exist? + if table in db.table_names(): + if ignore: + return + elif replace: + db[table].drop() + else: + raise click.ClickException( + 'Table "{}" already exists. Use --replace to delete and replace it.'.format( + table + ) + ) db[table].create( coltypes, pk=pk, not_null=not_null, defaults=dict(default), foreign_keys=fk ) diff --git a/tests/test_cli.py b/tests/test_cli.py index 36e9b72..7d653e1 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -960,3 +960,42 @@ def test_create_table_foreign_key(): " [author_id] INTEGER REFERENCES [authors]([id])\n" ")" ) == db["books"].schema + + +def test_create_table_error_if_table_exists(): + runner = CliRunner() + with runner.isolated_filesystem(): + db = Database("test.db") + db["dogs"].insert({"name": "Cleo"}) + result = runner.invoke( + cli.cli, ["create-table", "test.db", "dogs", "id", "integer"] + ) + assert 1 == result.exit_code + assert ( + 'Error: Table "dogs" already exists. Use --replace to delete and replace it.' + == result.output.strip() + ) + + +def test_create_table_ignore(): + runner = CliRunner() + with runner.isolated_filesystem(): + db = Database("test.db") + db["dogs"].insert({"name": "Cleo"}) + result = runner.invoke( + cli.cli, ["create-table", "test.db", "dogs", "id", "integer", "--ignore"] + ) + assert 0 == result.exit_code + assert "CREATE TABLE [dogs] (\n [name] TEXT\n)" == db["dogs"].schema + + +def test_create_table_replace(): + runner = CliRunner() + with runner.isolated_filesystem(): + db = Database("test.db") + db["dogs"].insert({"name": "Cleo"}) + result = runner.invoke( + cli.cli, ["create-table", "test.db", "dogs", "id", "integer", "--replace"] + ) + assert 0 == result.exit_code + assert "CREATE TABLE [dogs] (\n [id] INTEGER\n)" == db["dogs"].schema