Skip to content

Commit

Permalink
sqlite-utils add-foreign-key books.db books author_id authors id
Browse files Browse the repository at this point in the history
Command for adding foreign keys to existing tables. Closes #2
  • Loading branch information
simonw committed Feb 24, 2019
1 parent e1ca938 commit f8d3b7c
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 5 deletions.
13 changes: 13 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,19 @@ You can add a column using the ``add-column`` command::

The last argument here is the type of the column to be created. You can use one of ``text``, ``integer``, ``float`` or ``blob``.

.. _cli_add_foreign_key:

Adding foreign key constraints
==============================

The ``add-foreign-key`` command can be used to add new foreign key references to an existing table - something which SQLite's ``ALTER TABLE`` command does not support.

See :ref:`python_api_add_foreign_key` in the Python API documentation for further details and warnings (this could corrupt your database).

To add a foreign key constraint pointing the ``books.author_id`` column to ``authors.id`` in another table, do this::

$ sqlite-utils add-foreign-key books.db books author_id authors id

.. _cli_create_index:

Creating indexes
Expand Down
26 changes: 26 additions & 0 deletions sqlite_utils/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import click
from click_default_group import DefaultGroup
import sqlite_utils
from sqlite_utils.db import AlterError
import itertools
import json
import sys
Expand Down Expand Up @@ -154,6 +155,31 @@ def add_column(path, table, col_name, col_type):
db[table].add_column(col_name, col_type)


@cli.command(name="add-foreign-key")
@click.argument(
"path",
type=click.Path(exists=True, file_okay=True, dir_okay=False, allow_dash=False),
required=True,
)
@click.argument("table")
@click.argument("column")
@click.argument("other_table")
@click.argument("other_column")
def add_foreign_key(path, table, column, other_table, other_column):
"""
Add a new foreign key constraint to an existing table. Example usage:
$ sqlite-utils add-foreign-key my.db books author_id authors id
WARNING: Could corrupt your database! Back up your database file first.
"""
db = sqlite_utils.Database(path)
try:
db[table].add_foreign_key(column, other_table, other_column)
except AlterError as e:
raise click.ClickException(e)


@cli.command(name="create-index")
@click.argument(
"path",
Expand Down
42 changes: 37 additions & 5 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sqlite_utils import cli, Database
from sqlite_utils.db import Index
from sqlite_utils.db import Index, ForeignKey
from click.testing import CliRunner
import json
import os
Expand Down Expand Up @@ -200,14 +200,46 @@ def test_add_column(db_path, col_name, col_type, expected_schema):
assert expected_schema == collapse_whitespace(db["dogs"].schema)


def test_add_column_error_invalid_type(db_path):
def test_add_foreign_key(db_path):
db = Database(db_path)
db.create_table("dogs", {"name": str})
db["authors"].insert_all(
[{"id": 1, "name": "Sally"}, {"id": 2, "name": "Asheesh"}], pk="id"
)
db["books"].insert_all(
[
{"title": "Hedgehogs of the world", "author_id": 1},
{"title": "How to train your wolf", "author_id": 2},
]
)
assert (
0
== CliRunner()
.invoke(
cli.cli, ["add-foreign-key", db_path, "books", "author_id", "authors", "id"]
)
.exit_code
)
assert [
ForeignKey(
table="books", column="author_id", other_table="authors", other_column="id"
)
] == db["books"].foreign_keys
# Error if we try to add it twice:
result = CliRunner().invoke(
cli.cli, ["add-foreign-key", db_path, "books", "author_id", "authors", "id"]
)

assert 0 != result.exit_code
assert (
"Error: Foreign key already exists for author_id => authors.id"
== result.output.strip()
)
# Error if we try against an invalid cgolumn
result = CliRunner().invoke(
cli.cli, ["add-column", db_path, "dogs", "blah", "badtype"]
cli.cli, ["add-foreign-key", db_path, "books", "author_id", "authors", "bad"]
)
assert 0 != result.exit_code
assert "invalid choice: badtype" in result.output
assert "Error: No such column: authors.bad" == result.output.strip()


def test_enable_fts(db_path):
Expand Down

0 comments on commit f8d3b7c

Please sign in to comment.