Skip to content

Commit 5124246

Browse files
authored
1224 Make Cast more flexible (#1225)
* wip * revert some changes * add type annotation back for table * improve docstring and types * remove `table` param docs
1 parent 77d63f5 commit 5124246

File tree

2 files changed

+48
-12
lines changed

2 files changed

+48
-12
lines changed

piccolo/custom_types.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
from __future__ import annotations
22

3+
import datetime
4+
import decimal
5+
import uuid
36
from collections.abc import Iterable
47
from typing import TYPE_CHECKING, Any, TypeVar, Union
58

9+
from typing_extensions import TypeAlias
10+
611
if TYPE_CHECKING: # pragma: no cover
712
from piccolo.columns.combination import And, Or, Where, WhereRaw # noqa
813
from piccolo.table import Table
@@ -16,6 +21,22 @@
1621
QueryResponseType = TypeVar("QueryResponseType", bound=Any)
1722

1823

24+
# These are types we can reasonably expect to send to the database.
25+
BasicTypes: TypeAlias = Union[
26+
bytes,
27+
datetime.date,
28+
datetime.datetime,
29+
datetime.time,
30+
datetime.timedelta,
31+
decimal.Decimal,
32+
dict,
33+
float,
34+
int,
35+
list,
36+
str,
37+
uuid.UUID,
38+
]
39+
1940
###############################################################################
2041
# For backwards compatibility:
2142

piccolo/query/functions/type_conversion.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
from __future__ import annotations
2+
13
from typing import Optional, Union
24

35
from piccolo.columns.base import Column
6+
from piccolo.custom_types import BasicTypes
47
from piccolo.querystring import QueryString
58

69

710
class Cast(QueryString):
811
def __init__(
912
self,
10-
identifier: Union[Column, QueryString],
13+
identifier: Union[Column, QueryString, BasicTypes],
1114
as_type: Column,
1215
alias: Optional[str] = None,
1316
):
@@ -17,25 +20,36 @@ def __init__(
1720
>>> from piccolo.query.functions import Cast
1821
1922
>>> await Concert.select(
20-
... Cast(Concert.starts, Time(), "start_time")
23+
... Cast(Concert.starts, Time(), alias="start_time")
2124
... )
2225
[{"start_time": datetime.time(19, 0)}]
2326
27+
You may also need ``Cast`` to explicitly tell the database which type
28+
you're sending in the query (though this is an edge case). Here is a
29+
contrived example::
30+
31+
>>> from piccolo.query.functions.math import Count
32+
33+
# This fails with asyncpg:
34+
>>> await Band.select(Count([1,2,3]))
35+
36+
If we explicitly specify the type of the array, then it works::
37+
38+
>>> await Band.select(
39+
... Count(
40+
... Cast(
41+
... [1,2,3],
42+
... Array(Integer())
43+
... ),
44+
... )
45+
... )
46+
2447
:param identifier:
25-
Identifies what is being converted (e.g. a column).
48+
Identifies what is being converted (e.g. a column, or a raw value).
2649
:param as_type:
2750
The type to be converted to.
2851
2952
"""
30-
# Make sure the identifier is a supported type.
31-
32-
if not isinstance(identifier, (Column, QueryString)):
33-
raise ValueError(
34-
"The identifier is an unsupported type - only Column and "
35-
"QueryString instances are allowed."
36-
)
37-
38-
#######################################################################
3953
# Convert `as_type` to a string which can be used in the query.
4054

4155
if not isinstance(as_type, Column):
@@ -44,6 +58,7 @@ def __init__(
4458
# We need to give the column a reference to a table, and hence
4559
# the database engine, as the column type is sometimes dependent
4660
# on which database is being used.
61+
4762
from piccolo.table import Table, create_table_class
4863

4964
table: Optional[type[Table]] = None

0 commit comments

Comments
 (0)