-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1010 Add support for
CAST
to convert between types (#1011)
* add `cast` function * fix typo * revert accidental `test_array.py` changes they weren't meant to be in this branch
- Loading branch information
1 parent
acaa750
commit 9d1ab2d
Showing
12 changed files
with
415 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
Aggregate functions | ||
=================== | ||
|
||
.. currentmodule:: piccolo.query.functions.aggregate | ||
|
||
Avg | ||
--- | ||
|
||
.. autoclass:: Avg | ||
:class-doc-from: class | ||
|
||
Count | ||
----- | ||
|
||
.. autoclass:: Count | ||
:class-doc-from: class | ||
|
||
Min | ||
--- | ||
|
||
.. autoclass:: Min | ||
:class-doc-from: class | ||
|
||
Max | ||
--- | ||
|
||
.. autoclass:: Max | ||
:class-doc-from: class | ||
|
||
Sum | ||
--- | ||
|
||
.. autoclass:: Sum | ||
:class-doc-from: class |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
Basic Usage | ||
=========== | ||
|
||
Select queries | ||
-------------- | ||
|
||
Functions can be used in ``select`` queries - here's an example, where we | ||
convert the values to uppercase: | ||
|
||
.. code-block:: python | ||
>>> from piccolo.query.functions import Upper | ||
>>> await Band.select( | ||
... Upper(Band.name, alias="name") | ||
... ) | ||
[{"name": "PYTHONISTAS"}] | ||
Where clauses | ||
------------- | ||
|
||
Functions can also be used in ``where`` clauses. | ||
|
||
.. code-block:: python | ||
>>> from piccolo.query.functions import Length | ||
>>> await Band.select( | ||
... Band.name | ||
... ).where( | ||
... Length(Band.name) > 10 | ||
... ) | ||
[{"name": "Pythonistas"}] | ||
Update queries | ||
-------------- | ||
|
||
And even in ``update`` queries: | ||
|
||
.. code-block:: python | ||
>>> from piccolo.query.functions import Upper | ||
>>> await Band.update( | ||
... {Band.name: Upper(Band.name)}, | ||
... force=True | ||
... ).returning(Band.name) | ||
[{"name": "PYTHONISTAS"}, {"name": "RUSTACEANS"}, {"name": "C-SHARPS"}] | ||
Pretty much everywhere. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
Functions | ||
========= | ||
|
||
Functions can be used to modify how queries are run, and what is returned. | ||
|
||
.. toctree:: | ||
:maxdepth: 1 | ||
|
||
./basic_usage | ||
./string | ||
./type_conversion | ||
./aggregate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
String functions | ||
================ | ||
|
||
.. currentmodule:: piccolo.query.functions.string | ||
|
||
Length | ||
------ | ||
|
||
.. autoclass:: Length | ||
:class-doc-from: class | ||
|
||
Lower | ||
----- | ||
|
||
.. autoclass:: Lower | ||
:class-doc-from: class | ||
|
||
Ltrim | ||
----- | ||
|
||
.. autoclass:: Ltrim | ||
:class-doc-from: class | ||
|
||
Reverse | ||
------- | ||
|
||
.. autoclass:: Reverse | ||
:class-doc-from: class | ||
|
||
Rtrim | ||
----- | ||
|
||
.. autoclass:: Rtrim | ||
:class-doc-from: class | ||
|
||
Upper | ||
----- | ||
|
||
.. autoclass:: Upper | ||
:class-doc-from: class |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
Type conversion functions | ||
========================= | ||
|
||
Cast | ||
---- | ||
|
||
.. currentmodule:: piccolo.query.functions.type_conversion | ||
|
||
.. autoclass:: Cast | ||
|
||
Notes on databases | ||
------------------ | ||
|
||
Postgres and CockroachDB have very rich type systems, and you can convert | ||
between most types. SQLite is more limited. | ||
|
||
The following query will work in Postgres / Cockroach, but you might get | ||
unexpected results in SQLite, because it doesn't have a native ``TIME`` column | ||
type: | ||
|
||
.. code-block:: python | ||
>>> from piccolo.columns import Time | ||
>>> from piccolo.query.functions import Cast | ||
>>> await Concert.select(Cast(Concert.starts, Time())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import typing as t | ||
|
||
from piccolo.columns.base import Column | ||
from piccolo.querystring import QueryString | ||
|
||
|
||
class Cast(QueryString): | ||
def __init__( | ||
self, | ||
identifier: t.Union[Column, QueryString], | ||
as_type: Column, | ||
alias: t.Optional[str] = None, | ||
): | ||
""" | ||
Cast a value to a different type. For example:: | ||
>>> from piccolo.query.functions import Cast | ||
>>> await Concert.select( | ||
... Cast(Concert.starts, Time(), "start_time") | ||
... ) | ||
[{"start_time": datetime.time(19, 0)}] | ||
:param identifier: | ||
Identifies what is being converted (e.g. a column). | ||
:param as_type: | ||
The type to be converted to. | ||
""" | ||
# Make sure the identifier is a supported type. | ||
|
||
if not isinstance(identifier, (Column, QueryString)): | ||
raise ValueError( | ||
"The identifier is an unsupported type - only Column and " | ||
"QueryString instances are allowed." | ||
) | ||
|
||
####################################################################### | ||
# Convert `as_type` to a string which can be used in the query. | ||
|
||
if not isinstance(as_type, Column): | ||
raise ValueError("The `as_type` value must be a Column instance.") | ||
|
||
# We need to give the column a reference to a table, and hence | ||
# the database engine, as the column type is sometimes dependent | ||
# on which database is being used. | ||
from piccolo.table import Table, create_table_class | ||
|
||
table: t.Optional[t.Type[Table]] = None | ||
|
||
if isinstance(identifier, Column): | ||
table = identifier._meta.table | ||
elif isinstance(identifier, QueryString): | ||
table = ( | ||
identifier.columns[0]._meta.table | ||
if identifier.columns | ||
else None | ||
) | ||
|
||
as_type._meta.table = table or create_table_class("Table") | ||
as_type_string = as_type.column_type | ||
|
||
####################################################################### | ||
# Preserve the original alias from the column. | ||
|
||
if isinstance(identifier, Column): | ||
alias = ( | ||
alias | ||
or identifier._alias | ||
or identifier._meta.get_default_alias() | ||
) | ||
|
||
####################################################################### | ||
|
||
super().__init__( | ||
f"CAST({{}} AS {as_type_string})", | ||
identifier, | ||
alias=alias, | ||
) | ||
|
||
|
||
__all__ = ("Cast",) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.