Skip to content

Commit 690c492

Browse files
committed
added convert_to_sql_value
There are a bunch of places in the codebase which need to check if value are Enums, JSON, or Table instances, and convert them to values the database will understand. This logic has now been centralised into the `convert_to_sql_value` function.
1 parent 16535e9 commit 690c492

File tree

4 files changed

+45
-25
lines changed

4 files changed

+45
-25
lines changed

piccolo/columns/combination.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from __future__ import annotations
2-
from enum import Enum
32
import typing as t
43

54
from piccolo.columns.operators.comparison import ComparisonOperator
65
from piccolo.custom_types import Combinable, Iterable
76
from piccolo.querystring import QueryString
7+
from piccolo.query.sql_values import convert_to_sql_value
88

99
if t.TYPE_CHECKING:
1010
from piccolo.columns.base import Column
@@ -121,20 +121,17 @@ def clean_value(self, value: t.Any) -> t.Any:
121121
# it should still work.
122122
Band.select().where(Band.manager == guido).run_sync()
123123
124-
"""
125-
from piccolo.table import Table
124+
Also, convert Enums to their underlying values, and serialise any JSON.
126125
127-
if isinstance(value, Table):
128-
return value.id
129-
else:
130-
return value
126+
"""
127+
return convert_to_sql_value(value=value, column=self.column)
131128

132129
@property
133130
def values_querystring(self) -> QueryString:
134-
if isinstance(self.values, Undefined):
135-
raise ValueError("values is undefined")
131+
values = self.values
136132

137-
values = [i.value if isinstance(i, Enum) else i for i in self.values]
133+
if isinstance(values, Undefined):
134+
raise ValueError("values is undefined")
138135

139136
template = ", ".join(["{}" for _ in values])
140137
return QueryString(template, *values)
@@ -143,12 +140,8 @@ def values_querystring(self) -> QueryString:
143140
def querystring(self) -> QueryString:
144141
args: t.List[t.Any] = []
145142
if self.value != UNDEFINED:
146-
value = (
147-
self.value.value
148-
if isinstance(self.value, Enum)
149-
else self.value
150-
)
151-
args.append(value)
143+
args.append(self.value)
144+
152145
if self.values != UNDEFINED:
153146
args.append(self.values_querystring)
154147

piccolo/query/mixins.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from __future__ import annotations
22
from dataclasses import dataclass, field
3-
from enum import Enum
43
import typing as t
54

65
from piccolo.columns import And, Column, Secret, Where, Or
76
from piccolo.custom_types import Combinable
7+
from piccolo.query.sql_values import convert_to_sql_value
88
from piccolo.querystring import QueryString
99

1010
if t.TYPE_CHECKING: # pragma: no cover
@@ -171,6 +171,7 @@ def add(self, *instances: Table, table_class: t.Type[Table]):
171171
for instance in instances:
172172
if not isinstance(instance, table_class):
173173
raise TypeError("Incompatible type added.")
174+
174175
self._add += instances
175176

176177

@@ -271,11 +272,11 @@ def values(self, values: t.Dict[t.Union[Column, str], t.Any]):
271272

272273
def get_sql_values(self) -> t.List[t.Any]:
273274
"""
274-
Convert any Enums into values.
275+
Convert any Enums into values, and serialise any JSON.
275276
"""
276277
return [
277-
value.value if isinstance(value, Enum) else value
278-
for value in self._values.values()
278+
convert_to_sql_value(value=value, column=column)
279+
for column, value in self._values.items()
279280
]
280281

281282

piccolo/query/sql_values.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import annotations
2+
from enum import Enum
3+
import typing as t
4+
5+
from piccolo.utils.encoding import dump_json
6+
7+
if t.TYPE_CHECKING:
8+
from piccolo.columns import Column
9+
10+
11+
def convert_to_sql_value(value: t.Any, column: Column) -> t.Any:
12+
"""
13+
Some values which can be passed into Piccolo queries aren't valid in the
14+
database. For example, Enums, Table instances, and dictionaries for JSON
15+
columns.
16+
"""
17+
from piccolo.table import Table
18+
from piccolo.columns.column_types import JSON, JSONB
19+
20+
if isinstance(value, Table):
21+
return value.id
22+
elif isinstance(value, Enum):
23+
return value.value
24+
elif isinstance(column, (JSON, JSONB)) and not isinstance(value, str):
25+
return dump_json(value)
26+
else:
27+
return value

piccolo/table.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from __future__ import annotations
22
from dataclasses import dataclass, field
3-
from enum import Enum
43
import inspect
54
import itertools
65
import types
@@ -38,6 +37,7 @@
3837
)
3938
from piccolo.query.methods.indexes import Indexes
4039
from piccolo.query.methods.create_index import CreateIndex
40+
from piccolo.query.sql_values import convert_to_sql_value
4141
from piccolo.querystring import QueryString, Unquoted
4242
from piccolo.utils import _camel_to_snake
4343

@@ -418,10 +418,9 @@ def querystring(self) -> QueryString:
418418
"""
419419
args_dict = {}
420420
for col in self._meta.columns:
421-
value = self[col._meta.name]
422-
args_dict[col._meta.name] = (
423-
value.value if isinstance(value, Enum) else value
424-
)
421+
column_name = col._meta.name
422+
value = convert_to_sql_value(value=self[column_name], column=col)
423+
args_dict[column_name] = value
425424

426425
def is_unquoted(arg):
427426
return type(arg) == Unquoted

0 commit comments

Comments
 (0)