Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ALTER COLUMN NOT NULL directive fails because of inappropriate syntax #124

Merged
merged 4 commits into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 35 additions & 2 deletions google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py
Expand Up @@ -15,10 +15,17 @@
import pkg_resources
import re

from sqlalchemy import types, ForeignKeyConstraint
from alembic.ddl.base import (
ColumnNullable,
ColumnType,
alter_column,
alter_table,
format_type,
)
from sqlalchemy import ForeignKeyConstraint, types, util
from sqlalchemy.engine.base import Engine
from sqlalchemy.engine.default import DefaultDialect
from sqlalchemy import util
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.compiler import (
selectable,
DDLCompiler,
Expand All @@ -27,6 +34,7 @@
SQLCompiler,
RESERVED_WORDS,
)

from google.cloud import spanner_dbapi
from google.cloud.sqlalchemy_spanner._opentelemetry_tracing import trace_call

Expand Down Expand Up @@ -864,3 +872,28 @@ def do_execute_no_params(self, cursor, statement, context=None):
}
with trace_call("SpannerSqlAlchemy.ExecuteNoParams", trace_attributes):
cursor.execute(statement)


# Alembic ALTER operation override
@compiles(ColumnNullable, "spanner")
def visit_column_nullable(
element: "ColumnNullable", compiler: "SpannerDDLCompiler", **kw
) -> str:
return "%s %s %s %s" % (
alter_table(compiler, element.table_name, element.schema),
alter_column(compiler, element.column_name),
format_type(compiler, element.existing_type),
"" if element.nullable else "NOT NULL",
)


# Alembic ALTER operation override
@compiles(ColumnType, "spanner")
def visit_column_type(
element: "ColumnType", compiler: "SpannerDDLCompiler", **kw
) -> str:
return "%s %s %s" % (
alter_table(compiler, element.table_name, element.schema),
alter_column(compiler, element.column_name),
"%s" % format_type(compiler, element.type_),
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two syntax diverges:
Spanner supports NULL/NOT NULL statement without the DROP word in front of it for constraints dropping
Spanner doesn't use TYPE word for column type mentions

These two overrides covers both items.

8 changes: 4 additions & 4 deletions migration_test_cleanup.py
Expand Up @@ -27,11 +27,11 @@
config.read("setup.cfg")
db_url = config.get("db", "default")

project = re.findall(r'projects(.*?)instances', db_url)
instance_id = re.findall(r'instances(.*?)databases', db_url)
project = re.findall(r"projects(.*?)instances", db_url)
instance_id = re.findall(r"instances(.*?)databases", db_url)

client = spanner.Client(project="".join(project).replace('/', ''))
instance = client.instance(instance_id="".join(instance_id).replace('/', ''))
client = spanner.Client(project="".join(project).replace("/", ""))
instance = client.instance(instance_id="".join(instance_id).replace("/", ""))
database = instance.database("compliance-test")

database.update_ddl(["DROP TABLE account", "DROP TABLE alembic_version"]).result(120)
6 changes: 6 additions & 0 deletions noxfile.py
Expand Up @@ -60,6 +60,12 @@ class = StreamHandler
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('name', sa.String(50), nullable=False),
sa.Column('description', sa.Unicode(200)),
)
op.alter_column(
'account',
'name',
existing_type=sa.String(50),
nullable=True,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the issue case into the migration test (the original error could be repeated this way before these changes)

)"""


Expand Down
6 changes: 5 additions & 1 deletion setup.py
Expand Up @@ -19,7 +19,11 @@

name = "sqlalchemy-spanner"
description = "SQLAlchemy dialect integrated into Cloud Spanner database"
dependencies = ["sqlalchemy>=1.1.13, <=1.3.23", "google-cloud-spanner>=3.3.0"]
dependencies = [
"sqlalchemy>=1.1.13, <=1.3.23",
"google-cloud-spanner>=3.3.0",
"alembic",
]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we're now describing some alembic overrides, it should be mentioned in dependencies

extras = {
"tracing": [
"opentelemetry-api >= 1.1.0",
Expand Down