Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/src/piccolo/query_clauses/on_conflict.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Instead, if we want to update the ``popularity``:
... Band(name="Pythonistas", popularity=1200)
... ).on_conflict(
... action="DO UPDATE",
... target=Band.name,
... values=[Band.popularity]
... )

Expand All @@ -93,8 +94,9 @@ If we fetch the data from the database, we'll see that it was updated:

Using the ``target`` argument, we can specify which constraint we're concerned
with. By specifying ``target=Band.name`` we're only concerned with the unique
constraint for the ``band`` column. If you omit the ``target`` argument, then
it works for all constraints on the table.
constraint for the ``band`` column. If you omit the ``target`` argument on
``DO NOTHING`` action, then it works for all constraints on the table. For
``DO UPDATE`` action, ``target`` is mandatory and must be provided.

.. code-block:: python
:emphasize-lines: 5
Expand Down
5 changes: 5 additions & 0 deletions piccolo/query/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,11 @@ def on_conflict(
else:
raise ValueError("Unrecognised `on conflict` action.")

if target is None and action_ == OnConflictAction.do_update:
raise ValueError(
"The `target` option must be provided with DO UPDATE."
)

if where and action_ == OnConflictAction.do_nothing:
raise ValueError(
"The `where` option can only be used with DO NOTHING."
Expand Down
21 changes: 21 additions & 0 deletions tests/table/test_insert.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,27 @@ def test_do_update_tuple_values(self):
],
)

def test_do_update_no_target(self):
"""
Make sure that `DO UPDATE` with no `target` raises an exception.
"""
Band = self.Band

new_popularity = self.band.popularity + 1000

with self.assertRaises(ValueError) as manager:
Band.insert(
Band(name=self.band.name, popularity=new_popularity)
).on_conflict(
action="DO UPDATE",
values=[(Band.popularity, new_popularity + 2000)],
).run_sync()

self.assertEqual(
manager.exception.__str__(),
"The `target` option must be provided with DO UPDATE.",
)

def test_do_update_no_values(self):
"""
Make sure that `DO UPDATE` with no `values` raises an exception.
Expand Down