From dccbe227b1e5a0118061de5840dde81154771e5a Mon Sep 17 00:00:00 2001 From: Erik Wrede Date: Thu, 9 Jun 2022 17:31:54 +0200 Subject: [PATCH] BREAKING: Sort Enums & ChoiceType enums are now generated from Column.key instead of Column.name, see #330 Signed-off-by: Erik Wrede --- graphene_sqlalchemy/converter.py | 6 +++--- graphene_sqlalchemy/enums.py | 4 ++-- graphene_sqlalchemy/tests/models.py | 9 +++++++-- graphene_sqlalchemy/tests/test_converter.py | 16 ++++++++++++++++ graphene_sqlalchemy/tests/test_sort_enums.py | 20 +++++++++++++++++++- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/graphene_sqlalchemy/converter.py b/graphene_sqlalchemy/converter.py index 5c880272..476de029 100644 --- a/graphene_sqlalchemy/converter.py +++ b/graphene_sqlalchemy/converter.py @@ -9,8 +9,8 @@ from sqlalchemy.dialects import postgresql from sqlalchemy.orm import interfaces, strategies -from graphene import (ID, Boolean, Date, Time, DateTime, Dynamic, Enum, Field, Float, - Int, List, String, Time, UUID) +from graphene import (ID, UUID, Boolean, Date, DateTime, Dynamic, Enum, Field, + Float, Int, List, String, Time) from graphene.types.json import JSONString from .batching import get_batch_resolver @@ -253,7 +253,7 @@ def convert_enum_to_enum(type, column, registry=None): # TODO Make ChoiceType conversion consistent with other enums @convert_sqlalchemy_type.register(ChoiceType) def convert_choice_to_enum(type, column, registry=None): - name = "{}_{}".format(column.table.name, column.name).upper() + name = "{}_{}".format(column.table.name, column.key).upper() if isinstance(type.type_impl, EnumTypeImpl): # type.choices may be Enum/IntEnum, in ChoiceType both presented as EnumMeta # do not use from_enum here because we can have more than one enum column in table diff --git a/graphene_sqlalchemy/enums.py b/graphene_sqlalchemy/enums.py index f100be19..a2ed17ad 100644 --- a/graphene_sqlalchemy/enums.py +++ b/graphene_sqlalchemy/enums.py @@ -144,9 +144,9 @@ def sort_enum_for_object_type( column = orm_field.columns[0] if only_indexed and not (column.primary_key or column.index): continue - asc_name = get_name(column.name, True) + asc_name = get_name(column.key, True) asc_value = EnumValue(asc_name, column.asc()) - desc_name = get_name(column.name, False) + desc_name = get_name(column.key, False) desc_value = EnumValue(desc_name, column.desc()) if column.primary_key: default.append(asc_value) diff --git a/graphene_sqlalchemy/tests/models.py b/graphene_sqlalchemy/tests/models.py index e41adb51..7a178210 100644 --- a/graphene_sqlalchemy/tests/models.py +++ b/graphene_sqlalchemy/tests/models.py @@ -5,8 +5,8 @@ from decimal import Decimal from typing import List, Optional, Tuple -from sqlalchemy import (Column, Date, Enum, ForeignKey, Integer, String, Table, - func, select) +from sqlalchemy import (Column, Date, Enum, ForeignKey, Integer, Numeric, + String, Table, func, select) from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import column_property, composite, mapper, relationship @@ -228,3 +228,8 @@ def hybrid_prop_self_referential_list(self) -> List['ShoppingCart']: @hybrid_property def hybrid_prop_optional_self_referential(self) -> Optional['ShoppingCart']: return None + +class KeyedModel(Base): + __tablename__ = "test330" + id = Column(Integer(), primary_key=True) + reporter_number = Column("% reporter_number", Numeric, key="reporter_number") diff --git a/graphene_sqlalchemy/tests/test_converter.py b/graphene_sqlalchemy/tests/test_converter.py index 13551285..225294e8 100644 --- a/graphene_sqlalchemy/tests/test_converter.py +++ b/graphene_sqlalchemy/tests/test_converter.py @@ -163,6 +163,22 @@ class TestEnum(enum.Enum): assert graphene_type._meta.enum.__members__["en"].value == "English" +def test_choice_enum_column_key_name_issue_301(): + 'Support column.key instead of column.name for enum naming' + class TestEnum(enum.Enum): + es = u"Spanish" + en = u"English" + + testChoice = Column("% descuento1", ChoiceType(TestEnum, impl=types.String()), key="descuento1") + field = get_field_from_column(testChoice) + + graphene_type = field.type + assert issubclass(graphene_type, graphene.Enum) + assert graphene_type._meta.name == "MODEL_DESCUENTO1" + assert graphene_type._meta.enum.__members__["es"].value == "Spanish" + assert graphene_type._meta.enum.__members__["en"].value == "English" + + def test_should_intenum_choice_convert_enum(): class TestEnum(enum.IntEnum): one = 1 diff --git a/graphene_sqlalchemy/tests/test_sort_enums.py b/graphene_sqlalchemy/tests/test_sort_enums.py index 6291d4f8..56286837 100644 --- a/graphene_sqlalchemy/tests/test_sort_enums.py +++ b/graphene_sqlalchemy/tests/test_sort_enums.py @@ -7,7 +7,7 @@ from ..fields import SQLAlchemyConnectionField from ..types import SQLAlchemyObjectType from ..utils import to_type_name -from .models import Base, HairKind, Pet +from .models import Base, HairKind, KeyedModel, Pet from .test_query import to_std_dicts @@ -383,3 +383,21 @@ def makeNodes(nodeList): assert [node["node"]["name"] for node in result.data["noSort"]["edges"]] == [ node["node"]["name"] for node in result.data["noDefaultSort"]["edges"] ] + + +def test_sort_enum_from_key_issue_330(): + class KeyedType(SQLAlchemyObjectType): + class Meta: + model = KeyedModel + + sort_enum = KeyedType.sort_enum() + assert isinstance(sort_enum, type(Enum)) + assert sort_enum._meta.name == "KeyedTypeSortEnum" + assert list(sort_enum._meta.enum.__members__) == [ + "ID_ASC", + "ID_DESC", + "REPORTER_NUMBER_ASC", + "REPORTER_NUMBER_DESC", + ] + assert str(sort_enum.REPORTER_NUMBER_ASC.value.value) == 'test330."% reporter_number" ASC' + assert str(sort_enum.REPORTER_NUMBER_DESC.value.value) == 'test330."% reporter_number" DESC'