Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,13 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw):
ctu.table_name,
ctu.table_schema,
ARRAY_AGG(DISTINCT ccu.column_name),
ARRAY_AGG(kcu.column_name)
ARRAY_AGG(
DISTINCT CONCAT(
CAST(kcu.ordinal_position AS STRING),
'_____',
kcu.column_name
)
)
FROM information_schema.table_constraints AS tc
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
Expand All @@ -811,6 +817,21 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw):
rows = snap.execute_sql(sql)

for row in rows:
# Due to Spanner limitations, arrays order is not guaranteed during
# aggregation. Still, for constraints it's vital to keep the order
# of the referred columns, otherwise SQLAlchemy and Alembic may start
# to occasionally drop and recreate constraints. To avoid this, the
# method uses prefixes with the `key_column_usage.ordinal_position`
# values to ensure the columns are aggregated into an array in the
# correct order. Prefixes are only used under the hood. For more details
# see the issue:
# https://github.com/googleapis/python-spanner-sqlalchemy/issues/271
#
# The solution seem a bit clumsy, and should be improved as soon as a
# better approach found.
for index, value in enumerate(sorted(row[4])):
row[4][index] = value.split("_____")[1]

keys.append(
{
"name": row[0],
Expand All @@ -820,6 +841,7 @@ def get_foreign_keys(self, connection, table_name, schema=None, **kw):
"constrained_columns": row[4],
}
)

return keys

@engine_to_connection
Expand Down