Skip to content

Commit eea93a9

Browse files
authored
SNOW-640136: Revert breaking changes in snowflake-sqlalchemy v1.4.0 (#336)
1 parent e0ade9c commit eea93a9

File tree

7 files changed

+34
-68
lines changed

7 files changed

+34
-68
lines changed

DESCRIPTION.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ Source code is also available at:
1313

1414
- snowflake-sqlalchemy is now SQLAlchemy 2.0 compatible.
1515
- Fixed a bug that `DATE` should not be removed from `SnowflakeDialect.ischema_names`.
16-
- Fixed a breaking change introduced in release 1.4.0 that changed the behavior of processing numeric values returned from service.
16+
- Fixed breaking changes introduced in release 1.4.0 that:
17+
- changed the behavior of processing numeric, datetime and timestamp values returned from service.
18+
- changed the sequence order of primary/foreign keys in list returned by `inspect.get_foreign_keys` and `inspect.get_pk_constraint`.
1719

1820
- v1.4.0(July 20, 2022)
1921

src/snowflake/sqlalchemy/custom_types.py

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#
22
# Copyright (c) 2012-2022 Snowflake Computing Inc. All rights reserved.
33
#
4-
import datetime
5-
import re
64

75
import sqlalchemy.types as sqltypes
86
import sqlalchemy.util as util
@@ -71,20 +69,6 @@ def process(value):
7169

7270
return process
7371

74-
_reg = re.compile(r"(\d+)-(\d+)-(\d+)")
75-
76-
def result_processor(self, dialect, coltype):
77-
def process(value):
78-
if isinstance(value, str):
79-
m = self._reg.match(value)
80-
if not m:
81-
raise ValueError(f"could not parse {value!r} as a date value")
82-
return datetime.date(*[int(x or 0) for x in m.groups()])
83-
else:
84-
return value
85-
86-
return process
87-
8872

8973
class _CUSTOM_DateTime(SnowflakeType, sqltypes.DateTime):
9074
def literal_processor(self, dialect):
@@ -95,20 +79,6 @@ def process(value):
9579

9680
return process
9781

98-
_reg = re.compile(r"(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)(?:\.(\d{0,6}))?")
99-
100-
def result_processor(self, dialect, coltype):
101-
def process(value):
102-
if isinstance(value, str):
103-
m = self._reg.match(value)
104-
if not m:
105-
raise ValueError(f"could not parse {value!r} as a datetime value")
106-
return datetime.datetime(*[int(x or 0) for x in m.groups()])
107-
else:
108-
return value
109-
110-
return process
111-
11282

11383
class _CUSTOM_Time(SnowflakeType, sqltypes.Time):
11484
def literal_processor(self, dialect):
@@ -119,20 +89,6 @@ def process(value):
11989

12090
return process
12191

122-
_reg = re.compile(r"(\d+):(\d+):(\d+)(?:\.(\d{0,6}))?")
123-
124-
def result_processor(self, dialect, coltype):
125-
def process(value):
126-
if isinstance(value, str):
127-
m = self._reg.match(value)
128-
if not m:
129-
raise ValueError(f"could not parse {value!r} as a time value")
130-
return datetime.time(*[int(x or 0) for x in m.groups()])
131-
else:
132-
return value
133-
134-
return process
135-
13692

13793
class _CUSTOM_Float(SnowflakeType, sqltypes.Float):
13894
def bind_processor(self, dialect):

src/snowflake/sqlalchemy/requirements.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,17 @@ def implicit_decimal_binds(self):
281281
# parameters in string forms of decimal values.
282282
# Check https://snowflakecomputing.atlassian.net/browse/SNOW-640134 for details on breaking changes discussion.
283283
return exclusions.closed()
284+
285+
@property
286+
def datetime_implicit_bound(self):
287+
# Supporting this would require behavior breaking change to implicitly convert str to datetime when binding
288+
# parameters in string forms of datetime values.
289+
# Check https://snowflakecomputing.atlassian.net/browse/SNOW-640134 for details on breaking changes discussion.
290+
return exclusions.closed()
291+
292+
@property
293+
def timestamp_microseconds_implicit_bound(self):
294+
# Supporting this would require behavior breaking change to implicitly convert str to timestamp when binding
295+
# parameters in string forms of timestamp values.
296+
# Check https://snowflakecomputing.atlassian.net/browse/SNOW-640134 for details on breaking changes discussion.
297+
return exclusions.closed()

src/snowflake/sqlalchemy/snowdialect.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
_CUSTOM_Float,
6262
_CUSTOM_Time,
6363
)
64-
from .util import _sort_columns_by_sequences
6564

6665
colspecs = {
6766
Date: _CUSTOM_Date,
@@ -326,10 +325,8 @@ def _get_schema_primary_keys(self, connection, schema, **kw):
326325
)
327326
)
328327
ans = {}
329-
key_sequence_order_map = defaultdict(list)
330328
for row in result:
331329
table_name = self.normalize_name(row._mapping["table_name"])
332-
key_sequence_order_map[table_name].append(row._mapping["key_sequence"])
333330
if table_name not in ans:
334331
ans[table_name] = {
335332
"constrained_columns": [],
@@ -338,12 +335,6 @@ def _get_schema_primary_keys(self, connection, schema, **kw):
338335
ans[table_name]["constrained_columns"].append(
339336
self.normalize_name(row._mapping["column_name"])
340337
)
341-
342-
for k, v in ans.items():
343-
v["constrained_columns"] = _sort_columns_by_sequences(
344-
key_sequence_order_map[k], v["constrained_columns"]
345-
)
346-
347338
return ans
348339

349340
def get_pk_constraint(self, connection, table_name, schema=None, **kw):
@@ -406,10 +397,8 @@ def _get_schema_foreign_keys(self, connection, schema, **kw):
406397
)
407398
)
408399
foreign_key_map = {}
409-
key_sequence_order_map = defaultdict(list)
410400
for row in result:
411401
name = self.normalize_name(row._mapping["fk_name"])
412-
key_sequence_order_map[name].append(row._mapping["key_sequence"])
413402
if name not in foreign_key_map:
414403
referred_schema = self.normalize_name(row._mapping["pk_schema_name"])
415404
foreign_key_map[name] = {
@@ -453,13 +442,7 @@ def _get_schema_foreign_keys(self, connection, schema, **kw):
453442

454443
ans = {}
455444

456-
for k, v in foreign_key_map.items():
457-
v["constrained_columns"] = _sort_columns_by_sequences(
458-
key_sequence_order_map[k], v["constrained_columns"]
459-
)
460-
v["referred_columns"] = _sort_columns_by_sequences(
461-
key_sequence_order_map[k], v["referred_columns"]
462-
)
445+
for _, v in foreign_key_map.items():
463446
if v["table_name"] not in ans:
464447
ans[v["table_name"]] = []
465448
ans[v["table_name"]].append(

src/snowflake/sqlalchemy/util.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,3 @@ def sep(is_first_parameter):
6363
ret += sep(is_first_parameter) + p + "=" + encoded_value
6464
is_first_parameter = False
6565
return ret
66-
67-
68-
def _sort_columns_by_sequences(columns_sequences, columns):
69-
return [col for _, col in sorted(zip(columns_sequences, columns))]

tests/sqlalchemy_test_suite/test_suite.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
from sqlalchemy.schema import Column, Sequence, Table
77
from sqlalchemy.testing import config
88
from sqlalchemy.testing.assertions import eq_
9+
from sqlalchemy.testing.suite import (
10+
CompositeKeyReflectionTest as _CompositeKeyReflectionTest,
11+
)
912
from sqlalchemy.testing.suite import FetchLimitOffsetTest as _FetchLimitOffsetTest
1013
from sqlalchemy.testing.suite import HasSequenceTest as _HasSequenceTest
1114
from sqlalchemy.testing.suite import InsertBehaviorTest as _InsertBehaviorTest
@@ -134,3 +137,15 @@ def test_delete(self, connection):
134137
connection.execute(t.select().order_by(t.c.id)).fetchall(),
135138
[(1, "d1"), (3, "d3")],
136139
)
140+
141+
142+
class CompositeKeyReflectionTest(_CompositeKeyReflectionTest):
143+
@pytest.mark.xfail(reason="Fixing this would require behavior breaking change.")
144+
def test_fk_column_order(self):
145+
# Check https://snowflakecomputing.atlassian.net/browse/SNOW-640134 for details on breaking changes discussion.
146+
super().test_fk_column_order()
147+
148+
@pytest.mark.xfail(reason="Fixing this would require behavior breaking change.")
149+
def test_pk_column_order(self):
150+
# Check https://snowflakecomputing.atlassian.net/browse/SNOW-640134 for details on breaking changes discussion.
151+
super().test_pk_column_order()

tests/test_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ def test_get_multile_column_primary_key(engine_testaccount):
617617
assert columns_in_mytable[1]["primary_key"], "primary key"
618618

619619
primary_keys = inspector.get_pk_constraint("mytable")
620-
assert primary_keys["constrained_columns"] == ["id", "gid"]
620+
assert primary_keys["constrained_columns"] == ["gid", "id"]
621621

622622
finally:
623623
mytable.drop(engine_testaccount)

0 commit comments

Comments
 (0)