Skip to content

Commit 7af1d69

Browse files
committed
Alter.set_column_type now supports a using_expression argument
1 parent ca946b7 commit 7af1d69

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

piccolo/query/methods/alter.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,30 @@ def querystring(self) -> QueryString:
9393

9494
@dataclass
9595
class SetColumnType(AlterStatement):
96-
__slots__ = ("old_column", "new_column")
96+
"""
97+
:param using_expression:
98+
Postgres can't automatically convert between certain column types. You
99+
can tell Postgres which action to take. For example
100+
`my_column_name::integer`.
101+
102+
"""
97103

98104
old_column: Column
99105
new_column: Column
106+
using_expression: t.Optional[str] = None
100107

101108
@property
102109
def querystring(self) -> QueryString:
103110
if self.new_column._meta._table is None:
104111
self.new_column._meta._table = self.old_column._meta.table
105112

106113
column_name = self.old_column._meta.name
107-
return QueryString(
114+
query = (
108115
f"ALTER COLUMN {column_name} TYPE {self.new_column.column_type}"
109116
)
117+
if self.using_expression is not None:
118+
query += f" USING {self.using_expression}"
119+
return QueryString(query)
110120

111121

112122
@dataclass
@@ -353,12 +363,21 @@ def rename_column(
353363
self._rename_columns.append(RenameColumn(column, new_name))
354364
return self
355365

356-
def set_column_type(self, old_column: Column, new_column: Column) -> Alter:
366+
def set_column_type(
367+
self,
368+
old_column: Column,
369+
new_column: Column,
370+
using_expression: t.Optional[str] = None,
371+
) -> Alter:
357372
"""
358373
Change the type of a column.
359374
"""
360375
self._set_column_type.append(
361-
SetColumnType(old_column=old_column, new_column=new_column)
376+
SetColumnType(
377+
old_column=old_column,
378+
new_column=new_column,
379+
using_expression=using_expression,
380+
)
362381
)
363382
return self
364383

tests/table/test_alter.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
from piccolo.columns.column_types import Varchar
21
from unittest import TestCase
32

4-
from piccolo.columns import BigInt, Integer, Numeric
3+
from piccolo.columns import BigInt, Integer, Numeric, Varchar
54
from piccolo.table import Table
65

76
from ..base import DBTestCase, postgres_only
@@ -186,6 +185,23 @@ def test_integer_to_varchar(self):
186185
)
187186
self.assertEqual(popularity, "1000")
188187

188+
def test_using_expression(self):
189+
"""
190+
Test the `using_expression` option, which can be used to tell Postgres
191+
how to convert certain column types.
192+
"""
193+
Band(name="1").save().run_sync()
194+
195+
alter_query = Band.alter().set_column_type(
196+
old_column=Band.name,
197+
new_column=Integer(),
198+
using_expression="name::integer",
199+
)
200+
alter_query.run_sync()
201+
202+
popularity = Band.select(Band.name).first().run_sync()["name"]
203+
self.assertEqual(popularity, 1)
204+
189205

190206
@postgres_only
191207
class TestSetNull(DBTestCase):

0 commit comments

Comments
 (0)