From 41b08d8f294bc85a5e061a4ce532ad13116da92b Mon Sep 17 00:00:00 2001 From: Erik Wrede Date: Mon, 4 Dec 2023 21:41:47 +0100 Subject: [PATCH] fix: keep converting tuples to strings for composite primary keys in relay ID field --- graphene_sqlalchemy/tests/models.py | 7 ++++ graphene_sqlalchemy/tests/test_types.py | 51 +++++++++++++++++++++++++ graphene_sqlalchemy/types.py | 2 +- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/graphene_sqlalchemy/tests/models.py b/graphene_sqlalchemy/tests/models.py index 8911b0a..e1ee985 100644 --- a/graphene_sqlalchemy/tests/models.py +++ b/graphene_sqlalchemy/tests/models.py @@ -436,3 +436,10 @@ class CustomColumnModel(Base): id = Column(Integer(), primary_key=True) custom_col = Column(CustomIntegerColumn) + + +class CompositePrimaryKeyTestModel(Base): + __tablename__ = "compositekeytestmodel" + + first_name = Column(String(30), primary_key=True) + last_name = Column(String(30), primary_key=True) diff --git a/graphene_sqlalchemy/tests/test_types.py b/graphene_sqlalchemy/tests/test_types.py index e5b154c..f25b0dc 100644 --- a/graphene_sqlalchemy/tests/test_types.py +++ b/graphene_sqlalchemy/tests/test_types.py @@ -9,6 +9,7 @@ from graphene import ( Boolean, + DefaultGlobalIDType, Dynamic, Field, Float, @@ -42,6 +43,7 @@ from .models import ( Article, CompositeFullName, + CompositePrimaryKeyTestModel, Employee, NonAbstractPerson, Person, @@ -513,6 +515,55 @@ async def resolve_reporter(self, _info): # Test Custom SQLAlchemyObjectType Implementation +@pytest.mark.asyncio +async def test_composite_id_resolver(session): + """Test that the correct resolver functions are called""" + + composite_reporter = CompositePrimaryKeyTestModel( + first_name="graphql", last_name="foundation" + ) + + session.add(composite_reporter) + await eventually_await_session(session, "commit") + + class CompositePrimaryKeyTestModelType(SQLAlchemyObjectType): + class Meta: + model = CompositePrimaryKeyTestModel + interfaces = (Node,) + + class Query(ObjectType): + composite_reporter = Field(CompositePrimaryKeyTestModelType) + + async def resolve_composite_reporter(self, _info): + session = utils.get_session(_info.context) + if SQL_VERSION_HIGHER_EQUAL_THAN_1_4 and isinstance(session, AsyncSession): + return ( + (await session.scalars(select(CompositePrimaryKeyTestModel))) + .unique() + .first() + ) + return session.query(CompositePrimaryKeyTestModel).first() + + schema = Schema(query=Query) + result = await schema.execute_async( + """ + query { + compositeReporter { + id + firstName + lastName + } + } + """, + context_value={"session": session}, + ) + + assert not result.errors + assert result.data["compositeReporter"]["id"] == DefaultGlobalIDType.to_global_id( + CompositePrimaryKeyTestModelType, str(("graphql", "foundation")) + ) + + def test_custom_objecttype_registered(): class CustomSQLAlchemyObjectType(SQLAlchemyObjectType): class Meta: diff --git a/graphene_sqlalchemy/types.py b/graphene_sqlalchemy/types.py index 18d06ee..7053988 100644 --- a/graphene_sqlalchemy/types.py +++ b/graphene_sqlalchemy/types.py @@ -577,7 +577,7 @@ async def get_result() -> Any: def resolve_id(self, info): # graphene_type = info.parent_type.graphene_type keys = self.__mapper__.primary_key_from_instance(self) - return tuple(keys) if len(keys) > 1 else keys[0] + return str(tuple(keys)) if len(keys) > 1 else keys[0] @classmethod def enum_for_field(cls, field_name):