Skip to content

Commit e0933b7

Browse files
committed
improved table updating
Dictionaries with string keys, and kwargs can now be used.
1 parent f10fa32 commit e0933b7

File tree

4 files changed

+105
-23
lines changed

4 files changed

+105
-23
lines changed

piccolo/query/methods/update.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ class Update(Query):
1919

2020
def __init__(self, table: t.Type[Table], **kwargs):
2121
super().__init__(table, **kwargs)
22-
self.values_delegate = ValuesDelegate()
22+
self.values_delegate = ValuesDelegate(table=table)
2323
self.where_delegate = WhereDelegate()
2424

25-
def values(self, values: t.Dict[Column, t.Any]) -> Update:
25+
def values(
26+
self, values: t.Dict[t.Union[Column, str], t.Any] = {}, **kwargs
27+
) -> Update:
28+
values = dict(values, **kwargs)
2629
self.values_delegate.values(values)
2730
return self
2831

piccolo/query/mixins.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,16 +234,40 @@ def remove_secret_columns(self):
234234
class ValuesDelegate:
235235
"""
236236
Used to specify new column values - primarily used in update queries.
237-
238-
Example usage:
239-
240-
.values({MyTable.column_a: 1})
241237
"""
242238

239+
table: t.Type[Table]
243240
_values: t.Dict[Column, t.Any] = field(default_factory=dict)
244241

245-
def values(self, values: t.Dict[Column, t.Any]):
246-
self._values.update(values)
242+
def values(self, values: t.Dict[t.Union[Column, str], t.Any]):
243+
"""
244+
Example usage:
245+
246+
.. code-block:: python
247+
248+
.values({MyTable.column_a: 1})
249+
250+
# Or:
251+
.values({'column_a': 1})
252+
253+
# Or:
254+
.values(column_a=1})
255+
256+
"""
257+
cleaned_values: t.Dict[Column, t.Any] = {}
258+
for key, value in values.items():
259+
if isinstance(key, Column):
260+
column = key
261+
elif isinstance(key, str):
262+
column = self.table._meta.get_column_by_name(key)
263+
else:
264+
raise ValueError(
265+
f"Unrecognised key - {key} is neither a Column or the "
266+
"name of a Column."
267+
)
268+
cleaned_values[column] = value
269+
270+
self._values.update(cleaned_values)
247271

248272
def get_sql_values(self) -> t.List[t.Any]:
249273
"""

piccolo/table.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,9 @@ def table_exists(cls) -> TableExists:
626626
return TableExists(table=cls)
627627

628628
@classmethod
629-
def update(cls, values: t.Dict[Column, t.Any] = {}) -> Update:
629+
def update(
630+
cls, values: t.Dict[t.Union[Column, str], t.Any] = {}, **kwargs
631+
) -> Update:
630632
"""
631633
Update rows.
632634

tests/table/test_update.py

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,90 @@
33

44

55
class TestUpdate(DBTestCase):
6+
def check_response(self):
7+
response = (
8+
Band.select(Band.name)
9+
.where(Band.name == "Pythonistas3")
10+
.run_sync()
11+
)
12+
13+
self.assertEqual(response, [{"name": "Pythonistas3"}])
14+
615
def test_update(self):
16+
"""
17+
Make sure updating work, when passing the new values directly to the
18+
`update` method.
19+
"""
720
self.insert_rows()
821

922
Band.update({Band.name: "Pythonistas3"}).where(
1023
Band.name == "Pythonistas"
1124
).run_sync()
1225

13-
response = (
14-
Band.select(Band.name)
15-
.where(Band.name == "Pythonistas3")
16-
.run_sync()
17-
)
18-
print(f"response = {response}")
26+
self.check_response()
1927

20-
self.assertEqual(response, [{"name": "Pythonistas3"}])
28+
def test_update_with_string_keys(self):
29+
"""
30+
Make sure updating work, when passing a dictionary of values, which
31+
uses column names as keys, instead of Column instances.
32+
"""
33+
self.insert_rows()
34+
35+
Band.update({"name": "Pythonistas3"}).where(
36+
Band.name == "Pythonistas"
37+
).run_sync()
38+
39+
self.check_response()
40+
41+
def test_update_with_kwargs(self):
42+
"""
43+
Make sure updating work, when passing the new value via kwargs.
44+
"""
45+
self.insert_rows()
46+
47+
Band.update(name="Pythonistas3").where(
48+
Band.name == "Pythonistas"
49+
).run_sync()
50+
51+
self.check_response()
2152

2253
def test_update_values(self):
54+
"""
55+
Make sure updating work, when passing the new values via the `values`
56+
method.
57+
"""
2358
self.insert_rows()
2459

2560
Band.update().values({Band.name: "Pythonistas3"}).where(
2661
Band.name == "Pythonistas"
2762
).run_sync()
2863

29-
response = (
30-
Band.select(Band.name)
31-
.where(Band.name == "Pythonistas3")
32-
.run_sync()
33-
)
34-
print(f"response = {response}")
64+
self.check_response()
3565

36-
self.assertEqual(response, [{"name": "Pythonistas3"}])
66+
def test_update_values_with_string_keys(self):
67+
"""
68+
Make sure updating work, when passing the new values via the `values`
69+
method, using a column name as a dictionary key.
70+
"""
71+
self.insert_rows()
72+
73+
Band.update().values({"name": "Pythonistas3"}).where(
74+
Band.name == "Pythonistas"
75+
).run_sync()
76+
77+
self.check_response()
78+
79+
def test_update_values_with_kwargs(self):
80+
"""
81+
Make sure updating work, when passing the new values via kwargs.
82+
"""
83+
self.insert_rows()
84+
85+
Band.update().values(name="Pythonistas3").where(
86+
Band.name == "Pythonistas"
87+
).run_sync()
88+
89+
self.check_response()
3790

3891

3992
class TestIntUpdateOperators(DBTestCase):

0 commit comments

Comments
 (0)