Skip to content

Commit bfd74a3

Browse files
committed
upsert() detects existing compound primary keys
Closes #629
1 parent b5d0080 commit bfd74a3

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

sqlite_utils/db.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3554,6 +3554,11 @@ def insert_all(
35543554
if hash_id_columns and hash_id is None:
35553555
hash_id = "id"
35563556

3557+
if upsert and not pk and not hash_id and self.exists():
3558+
existing_pks = [column.name for column in self.columns if column.is_pk]
3559+
if existing_pks:
3560+
pk = existing_pks[0] if len(existing_pks) == 1 else tuple(existing_pks)
3561+
35573562
if upsert and (not pk and not hash_id):
35583563
raise PrimaryKeyRequired("upsert() requires a pk")
35593564

tests/test_upsert.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,53 @@ def test_upsert_error_if_no_pk(fresh_db):
4949
table.upsert({"id": 1, "name": "Cleo"})
5050

5151

52+
def test_upsert_error_if_existing_table_has_no_pk(fresh_db):
53+
table = fresh_db.create_table("table", {"id": int, "name": str})
54+
with pytest.raises(PrimaryKeyRequired):
55+
table.upsert({"id": 1, "name": "Cleo"})
56+
57+
58+
@pytest.mark.parametrize("use_old_upsert", (False, True))
59+
def test_upsert_uses_compound_pk_from_existing_table(use_old_upsert):
60+
# https://github.com/simonw/sqlite-utils/issues/629
61+
db = Database(memory=True, use_old_upsert=use_old_upsert)
62+
db.execute("""
63+
create table summary (
64+
Source text,
65+
Object text,
66+
Category text,
67+
Count integer,
68+
primary key (Source, Object, Category)
69+
)
70+
""")
71+
table = db["summary"]
72+
table.upsert(
73+
{
74+
"Source": "Client A",
75+
"Object": "Accounts",
76+
"Category": "All",
77+
"Count": 3,
78+
}
79+
)
80+
assert table.last_pk == ("Client A", "Accounts", "All")
81+
table.upsert(
82+
{
83+
"Source": "Client A",
84+
"Object": "Accounts",
85+
"Category": "All",
86+
"Count": 4,
87+
}
88+
)
89+
assert list(table.rows) == [
90+
{
91+
"Source": "Client A",
92+
"Object": "Accounts",
93+
"Category": "All",
94+
"Count": 4,
95+
}
96+
]
97+
98+
5299
def test_upsert_with_hash_id(fresh_db):
53100
table = fresh_db["table"]
54101
table.upsert({"foo": "bar"}, hash_id="pk")

0 commit comments

Comments
 (0)