Skip to content

Commit 56093de

Browse files
committed
sqlite-utils transform --add-foreign-key option, closes #585
1 parent 70717dc commit 56093de

File tree

4 files changed

+83
-30
lines changed

4 files changed

+83
-30
lines changed

docs/cli-reference.rst

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -455,20 +455,25 @@ See :ref:`cli_transform_table`.
455455
--rename column2 column_renamed
456456

457457
Options:
458-
--type <TEXT CHOICE>... Change column type to INTEGER, TEXT, FLOAT or BLOB
459-
--drop TEXT Drop this column
460-
--rename <TEXT TEXT>... Rename this column to X
461-
-o, --column-order TEXT Reorder columns
462-
--not-null TEXT Set this column to NOT NULL
463-
--not-null-false TEXT Remove NOT NULL from this column
464-
--pk TEXT Make this column the primary key
465-
--pk-none Remove primary key (convert to rowid table)
466-
--default <TEXT TEXT>... Set default value for this column
467-
--default-none TEXT Remove default from this column
468-
--drop-foreign-key TEXT Drop foreign key constraint for this column
469-
--sql Output SQL without executing it
470-
--load-extension TEXT Path to SQLite extension, with optional :entrypoint
471-
-h, --help Show this message and exit.
458+
--type <TEXT CHOICE>... Change column type to INTEGER, TEXT, FLOAT or
459+
BLOB
460+
--drop TEXT Drop this column
461+
--rename <TEXT TEXT>... Rename this column to X
462+
-o, --column-order TEXT Reorder columns
463+
--not-null TEXT Set this column to NOT NULL
464+
--not-null-false TEXT Remove NOT NULL from this column
465+
--pk TEXT Make this column the primary key
466+
--pk-none Remove primary key (convert to rowid table)
467+
--default <TEXT TEXT>... Set default value for this column
468+
--default-none TEXT Remove default from this column
469+
--add-foreign-key <TEXT TEXT TEXT>...
470+
Add a foreign key constraint from a column to
471+
another table with another column
472+
--drop-foreign-key TEXT Drop foreign key constraint for this column
473+
--sql Output SQL without executing it
474+
--load-extension TEXT Path to SQLite extension, with optional
475+
:entrypoint
476+
-h, --help Show this message and exit.
472477

473478

474479
.. _cli_ref_extract:

docs/cli.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,9 @@ Every option for this table (with the exception of ``--pk-none``) can be specifi
20612061
``--drop-foreign-key column``
20622062
Drop the specified foreign key.
20632063

2064+
``--add-foregn-key column other_table other_column``
2065+
Add a foreign key constraint to ``column`` pointing to ``other_table.other_column``.
2066+
20642067
If you want to see the SQL that will be executed to make the change without actually executing it, add the ``--sql`` flag. For example:
20652068

20662069
.. code-block:: bash

sqlite_utils/cli.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,6 +2406,14 @@ def schema(
24062406
"--default-none", type=str, multiple=True, help="Remove default from this column"
24072407
)
24082408
@click.option(
2409+
"add_foreign_keys",
2410+
"--add-foreign-key",
2411+
type=(str, str, str),
2412+
multiple=True,
2413+
help="Add a foreign key constraint from a column to another table with another column",
2414+
)
2415+
@click.option(
2416+
"drop_foreign_keys",
24092417
"--drop-foreign-key",
24102418
type=str,
24112419
multiple=True,
@@ -2426,7 +2434,8 @@ def transform(
24262434
pk_none,
24272435
default,
24282436
default_none,
2429-
drop_foreign_key,
2437+
add_foreign_keys,
2438+
drop_foreign_keys,
24302439
sql,
24312440
load_extension,
24322441
):
@@ -2475,8 +2484,10 @@ def transform(
24752484
elif pk_none:
24762485
kwargs["pk"] = None
24772486
kwargs["defaults"] = default_dict
2478-
if drop_foreign_key:
2479-
kwargs["drop_foreign_keys"] = drop_foreign_key
2487+
if drop_foreign_keys:
2488+
kwargs["drop_foreign_keys"] = drop_foreign_keys
2489+
if add_foreign_keys:
2490+
kwargs["add_foreign_keys"] = add_foreign_keys
24802491

24812492
if sql:
24822493
for line in db[table].transform_sql(**kwargs):

tests/test_cli.py

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,10 +1645,52 @@ def test_transform(db_path, args, expected_schema):
16451645
assert schema == expected_schema
16461646

16471647

1648-
def test_transform_drop_foreign_key(db_path):
1648+
@pytest.mark.parametrize(
1649+
"extra_args,expected_schema",
1650+
(
1651+
(
1652+
["--drop-foreign-key", "country"],
1653+
(
1654+
'CREATE TABLE "places" (\n'
1655+
" [id] INTEGER PRIMARY KEY,\n"
1656+
" [name] TEXT,\n"
1657+
" [country] INTEGER,\n"
1658+
" [city] INTEGER REFERENCES [city]([id]),\n"
1659+
" [continent] INTEGER\n"
1660+
")"
1661+
),
1662+
),
1663+
(
1664+
["--drop-foreign-key", "country", "--drop-foreign-key", "city"],
1665+
(
1666+
'CREATE TABLE "places" (\n'
1667+
" [id] INTEGER PRIMARY KEY,\n"
1668+
" [name] TEXT,\n"
1669+
" [country] INTEGER,\n"
1670+
" [city] INTEGER,\n"
1671+
" [continent] INTEGER\n"
1672+
")"
1673+
),
1674+
),
1675+
(
1676+
["--add-foreign-key", "continent", "continent", "id"],
1677+
(
1678+
'CREATE TABLE "places" (\n'
1679+
" [id] INTEGER PRIMARY KEY,\n"
1680+
" [name] TEXT,\n"
1681+
" [country] INTEGER REFERENCES [country]([id]),\n"
1682+
" [city] INTEGER REFERENCES [city]([id]),\n"
1683+
" [continent] INTEGER REFERENCES [continent]([id])\n"
1684+
")"
1685+
),
1686+
),
1687+
),
1688+
)
1689+
def test_transform_add_or_drop_foreign_key(db_path, extra_args, expected_schema):
16491690
db = Database(db_path)
16501691
with db.conn:
16511692
# Create table with three foreign keys so we can drop two of them
1693+
db["continent"].insert({"id": 1, "name": "Europe"}, pk="id")
16521694
db["country"].insert({"id": 1, "name": "France"}, pk="id")
16531695
db["city"].insert({"id": 24, "name": "Paris"}, pk="id")
16541696
db["places"].insert(
@@ -1657,6 +1699,7 @@ def test_transform_drop_foreign_key(db_path):
16571699
"name": "Caveau de la Huchette",
16581700
"country": 1,
16591701
"city": 24,
1702+
"continent": 1,
16601703
},
16611704
foreign_keys=("country", "city"),
16621705
pk="id",
@@ -1667,21 +1710,12 @@ def test_transform_drop_foreign_key(db_path):
16671710
"transform",
16681711
db_path,
16691712
"places",
1670-
"--drop-foreign-key",
1671-
"country",
1672-
],
1713+
]
1714+
+ extra_args,
16731715
)
1674-
print(result.output)
16751716
assert result.exit_code == 0
16761717
schema = db["places"].schema
1677-
assert schema == (
1678-
'CREATE TABLE "places" (\n'
1679-
" [id] INTEGER PRIMARY KEY,\n"
1680-
" [name] TEXT,\n"
1681-
" [country] INTEGER,\n"
1682-
" [city] INTEGER REFERENCES [city]([id])\n"
1683-
")"
1684-
)
1718+
assert schema == expected_schema
16851719

16861720

16871721
_common_other_schema = (

0 commit comments

Comments
 (0)