Skip to content

Commit af3b97b

Browse files
author
Ilya Gurov
authored
fix: array columns reflection (#119)
Fixes #118
1 parent 7632864 commit af3b97b

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"STRING": types.String,
4343
"TIME": types.TIME,
4444
"TIMESTAMP": types.TIMESTAMP,
45+
"ARRAY": types.ARRAY,
4546
}
4647

4748
_type_map_inv = {
@@ -476,28 +477,43 @@ def get_columns(self, connection, table_name, schema=None, **kw):
476477
columns = snap.execute_sql(sql)
477478

478479
for col in columns:
479-
if col[1].startswith("STRING"):
480-
end = col[1].index(")")
481-
size = int_from_size(col[1][7:end])
482-
type_ = _type_map["STRING"](length=size)
483-
# add test creating a table with bytes
484-
elif col[1].startswith("BYTES"):
485-
end = col[1].index(")")
486-
size = int_from_size(col[1][6:end])
487-
type_ = _type_map["BYTES"](length=size)
488-
else:
489-
type_ = _type_map[col[1]]
490-
491480
cols_desc.append(
492481
{
493482
"name": col[0],
494-
"type": type_,
483+
"type": self._designate_type(col[1]),
495484
"nullable": col[2] == "YES",
496485
"default": None,
497486
}
498487
)
499488
return cols_desc
500489

490+
def _designate_type(self, str_repr):
491+
"""
492+
Designate an SQLAlchemy data type from a Spanner
493+
string representation.
494+
495+
Args:
496+
str_repr (str): String representation of a type.
497+
498+
Returns:
499+
An SQLAlchemy data type.
500+
"""
501+
if str_repr.startswith("STRING"):
502+
end = str_repr.index(")")
503+
size = int_from_size(str_repr[7:end])
504+
return _type_map["STRING"](length=size)
505+
# add test creating a table with bytes
506+
elif str_repr.startswith("BYTES"):
507+
end = str_repr.index(")")
508+
size = int_from_size(str_repr[6:end])
509+
return _type_map["BYTES"](length=size)
510+
elif str_repr.startswith("ARRAY"):
511+
inner_type_str = str_repr[6:-1]
512+
inner_type = self._designate_type(inner_type_str)
513+
return _type_map["ARRAY"](inner_type)
514+
else:
515+
return _type_map[str_repr]
516+
501517
@engine_to_connection
502518
def get_indexes(self, connection, table_name, schema=None, **kw):
503519
"""Get the table indexes.

test/test_suite.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
from sqlalchemy.ext.declarative import declarative_base
5050
from sqlalchemy.orm import relation
5151
from sqlalchemy.orm import Session
52+
from sqlalchemy.types import ARRAY
5253
from sqlalchemy.types import Integer
5354
from sqlalchemy.types import Numeric
5455
from sqlalchemy.types import Text
@@ -901,6 +902,33 @@ def test_binary_reflection(self):
901902
assert isinstance(typ, LargeBinary)
902903
eq_(typ.length, 20)
903904

905+
@testing.requires.table_reflection
906+
def test_array_reflection(self):
907+
"""Check array columns reflection."""
908+
orig_meta = self.metadata
909+
910+
str_array = ARRAY(String(16))
911+
int_array = ARRAY(Integer)
912+
Table(
913+
"arrays_test",
914+
orig_meta,
915+
Column("id", Integer, primary_key=True),
916+
Column("str_array", str_array),
917+
Column("int_array", int_array),
918+
)
919+
orig_meta.create_all()
920+
921+
# autoload the table and check its columns reflection
922+
tab = Table("arrays_test", orig_meta, autoload=True)
923+
col_types = [col.type for col in tab.columns]
924+
for type_ in (
925+
str_array,
926+
int_array,
927+
):
928+
assert type_ in col_types
929+
930+
tab.drop()
931+
904932

905933
class CompositeKeyReflectionTest(_CompositeKeyReflectionTest):
906934
@testing.requires.foreign_key_constraint_reflection

0 commit comments

Comments
 (0)