Skip to content

Commit 5d54f4c

Browse files
author
James Robinson
authored
Handle unnamed primary keys encountered within \introspect. (#75)
* Handle unnamed primary keys encountered within \introspect. * Language
1 parent e17a8a6 commit 5d54f4c

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

noteable_magics/sql/meta_commands.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,9 @@ def introspect_primary_key(
760760
"""
761761
primary_index_dict = inspector.get_pk_constraint(relation_name, schema_name)
762762

763-
pkey_name = primary_index_dict.get('name', '(unnamed primary key)')
763+
# MySQL at least can have unnamed primary keys. The returned dict will have 'name' -> None.
764+
# Sigh.
765+
pkey_name = primary_index_dict.get('name') or '(unnamed primary key)'
764766

765767
if primary_index_dict['constrained_columns']:
766768
return pkey_name, primary_index_dict['constrained_columns']

tests/test_sql_magic_meta_commands.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,60 @@ def test_full_introspection(self, sql_magic, capsys, patched_requests_mock):
724724
assert had_check_constraints
725725
assert had_foreign_keys
726726

727+
@pytest.fixture()
728+
def patch_make_all_pks_unnamed(self, mocker):
729+
"""Monkeypatch SchemaStrippingInspector.get_pk_constraint to describe all primary keys as
730+
name = None, as MySQL might have"""
731+
732+
orig_implementation = SchemaStrippingInspector.get_pk_constraint
733+
734+
def get_pk_constaint_all_anonymous(
735+
self, table_name: str, schema: Optional[str] = None
736+
) -> dict:
737+
"""Make all primary keys smell unnamed, like some MySQL and/or SingleStore tables may smell"""
738+
orig_dict = orig_implementation(self, table_name, schema)
739+
orig_dict['name'] = None
740+
741+
return orig_dict
742+
743+
SchemaStrippingInspector.get_pk_constraint = get_pk_constaint_all_anonymous
744+
745+
try:
746+
yield
747+
748+
finally:
749+
# Repair the class.
750+
SchemaStrippingInspector.get_pk_constraint = orig_implementation
751+
752+
def test_introspection_vs_unnamed_primary_keys(
753+
self, sql_magic, capsys, patched_requests_mock, patch_make_all_pks_unnamed
754+
):
755+
756+
"""Ensure that no problems happen if primary keys are unnamed. We should inject '(unnamed primary key)' in
757+
as the name. ENG-5416."""
758+
759+
# Introspect the whole DB after having made the PKs have no name via fixture patch_make_all_pks_unnamed().
760+
sql_magic.execute(rf'{COCKROACH_HANDLE} \introspect')
761+
762+
out, err = capsys.readouterr()
763+
764+
# Look ma, no exceptions in this case anymore!
765+
assert 'Exception' not in out
766+
767+
primary_key_names = set()
768+
769+
for req in patched_requests_mock.request_history:
770+
if req.method == 'POST' and req.url.endswith('/schema/relations'):
771+
dict_list = req.json()
772+
for member_dict in dict_list:
773+
from_json = RelationStructureDescription(**member_dict)
774+
775+
if from_json.primary_key_name and from_json.primary_key_columns:
776+
primary_key_names.add(from_json.primary_key_name)
777+
778+
# In this test, all pk names will be described as unnamed due to the monkeypatching.
779+
assert primary_key_names == set(('(unnamed primary key)',))
780+
727781
@pytest.mark.usefixtures("populated_sqlite_database")
728782
def test_cannot_introspect_legacy_datasource(self, sql_magic, capsys):
729783
r"""Only datasource-uuid-based connections should be \introspect fodder"""

0 commit comments

Comments
 (0)