Skip to content

Commit 9f7f78b

Browse files
LinchinJacobHayes
andauthored
fix: alembic column rename (#1141)
* fix: alembic column rename * fix system test * correct system test to test visit_column_name() and visit_column_type() * add unit tests * add unit tests --------- Co-authored-by: Jacob Hayes <jacob.r.hayes@gmail.com>
1 parent 413cd24 commit 9f7f78b

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

sqlalchemy_bigquery/base.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,18 +1388,36 @@ def __init__(self, *args, **kwargs):
13881388
pass
13891389
else:
13901390
from alembic.ddl import impl
1391-
from alembic.ddl.base import ColumnType, format_type, alter_table, alter_column
1391+
from alembic.ddl.base import (
1392+
ColumnName,
1393+
ColumnType,
1394+
format_column_name,
1395+
format_type,
1396+
alter_table,
1397+
alter_column,
1398+
)
13921399

13931400
class SqlalchemyBigqueryImpl(impl.DefaultImpl):
13941401
__dialect__ = "bigquery"
13951402

1403+
@compiles(ColumnName, "bigquery")
1404+
def visit_column_name(element: ColumnName, compiler: DDLCompiler, **kw) -> str:
1405+
"""Replaces the visit_column_name() function in alembic/alembic/ddl/base.py.
1406+
See https://github.com/googleapis/python-bigquery-sqlalchemy/issues/1097"""
1407+
1408+
return "%s RENAME COLUMN %s TO %s" % (
1409+
alter_table(compiler, element.table_name, element.schema),
1410+
format_column_name(compiler, element.column_name),
1411+
format_column_name(compiler, element.newname),
1412+
)
1413+
13961414
@compiles(ColumnType, "bigquery")
13971415
def visit_column_type(element: ColumnType, compiler: DDLCompiler, **kw) -> str:
13981416
"""Replaces the visit_column_type() function in alembic/alembic/ddl/base.py.
13991417
The alembic version ends in TYPE <element type>, but bigquery requires this syntax:
14001418
SET DATA TYPE <element type>"""
14011419

1402-
return "%s %s %s" % ( # pragma: NO COVER
1420+
return "%s %s %s" % (
14031421
alter_table(compiler, element.table_name, element.schema),
14041422
alter_column(compiler, element.column_name),
14051423
"SET DATA TYPE %s" % format_type(compiler, element.type_),

tests/system/test_alembic.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ def test_alembic_scenario(alembic_table):
6666
table mods within a short time.
6767
"""
6868
from alembic import op
69+
from sqlalchemy_bigquery.base import SqlalchemyBigqueryImpl
70+
71+
# Register the BigQuery Implementation to test the customized methods.
72+
op.implementation_for(SqlalchemyBigqueryImpl)
6973

7074
assert alembic_table("account") is None
7175

@@ -100,9 +104,11 @@ def test_alembic_scenario(alembic_table):
100104
"account", Column("last_transaction_date", DateTime, comment="when updated")
101105
)
102106

107+
# Tests customized visit_column_name()
108+
op.alter_column("account", "name", new_column_name="friendly_name")
103109
assert alembic_table("account", "schema") == [
104110
SchemaField("id", "INTEGER", "REQUIRED"),
105-
SchemaField("name", "STRING(50)", "REQUIRED", description="The name"),
111+
SchemaField("friendly_name", "STRING(50)", "REQUIRED", description="The name"),
106112
SchemaField("description", "STRING(200)"),
107113
SchemaField("last_transaction_date", "DATETIME", description="when updated"),
108114
]
@@ -131,7 +137,7 @@ def test_alembic_scenario(alembic_table):
131137
assert alembic_table("account") is None
132138
assert alembic_table("accounts", "schema") == [
133139
SchemaField("id", "INTEGER", "REQUIRED"),
134-
SchemaField("name", "STRING(50)", "REQUIRED", description="The name"),
140+
SchemaField("friendly_name", "STRING(50)", "REQUIRED", description="The name"),
135141
SchemaField("description", "STRING(200)"),
136142
SchemaField("last_transaction_date", "DATETIME", description="when updated"),
137143
]
@@ -162,6 +168,7 @@ def test_alembic_scenario(alembic_table):
162168
# if allowed by BigQuery's type coercion rules
163169
op.create_table("identifiers", Column("id", Integer))
164170

171+
# Tests customized visit_column_type()
165172
op.alter_column("identifiers", "id", type_=Numeric)
166173
assert alembic_table("identifiers", "schema") == [SchemaField("id", "NUMERIC")]
167174

tests/unit/test_alembic.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) 2021 The sqlalchemy-bigquery Authors
2+
#
3+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
# this software and associated documentation files (the "Software"), to deal in
5+
# the Software without restriction, including without limitation the rights to
6+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+
# the Software, and to permit persons to whom the Software is furnished to do so,
8+
# subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in all
11+
# copies or substantial portions of the Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19+
20+
from alembic.ddl.base import ColumnName, ColumnType
21+
from sqlalchemy import Integer
22+
23+
24+
def test_alter_table_rename_column_bigquery(ddl_compiler):
25+
from sqlalchemy_bigquery.base import visit_column_name
26+
27+
column = ColumnName(name="t", column_name="a", newname="b")
28+
res = visit_column_name(element=column, compiler=ddl_compiler)
29+
assert res == "ALTER TABLE `t` RENAME COLUMN `a` TO `b`"
30+
31+
32+
def test_alter_column_new_type_bigquery(ddl_compiler):
33+
from sqlalchemy_bigquery.base import visit_column_type
34+
35+
column = ColumnType(name="t", column_name="a", type_=Integer())
36+
res = visit_column_type(element=column, compiler=ddl_compiler)
37+
assert res == "ALTER TABLE `t` ALTER COLUMN `a` SET DATA TYPE INT64"

0 commit comments

Comments
 (0)