From 1ebde362fcf0040279f9b88c615054ce84c1f34f Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Mon, 26 Nov 2018 11:16:47 +0100 Subject: [PATCH 1/7] Add tests for aliased_fields meta option --- graphene_sqlalchemy/tests/test_types.py | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/graphene_sqlalchemy/tests/test_types.py b/graphene_sqlalchemy/tests/test_types.py index c11ec351..15ba1f8e 100644 --- a/graphene_sqlalchemy/tests/test_types.py +++ b/graphene_sqlalchemy/tests/test_types.py @@ -181,3 +181,36 @@ class Meta: resolver, TestConnection, ReporterWithCustomOptions, None, None ) assert result is not None + + +class HumanWithFieldAliased(SQLAlchemyObjectType): + + publication_timestamp = Int() + + class Meta: + model = Article + registry = registry + interfaces = (Node,) + aliased_fields = { + "id": "article_id", + "headline": "title", + "pub_date": "publication_timestamp", + "reporter_id": "journalist_id", + "reporter": "journalist", + } + + +def test_objecttype_with_aliased_fields(): + assert issubclass(HumanWithFieldAliased, ObjectType) + assert HumanWithFieldAliased._meta.model == Article + assert list(HumanWithFieldAliased._meta.fields.keys()) == [ + "article_id", + "title", + "publication_timestamp", + "journalist_id", + "journalist", + "id", # Graphene Node ID + ] + replaced_field = HumanWithFieldAliased._meta.fields["publication_timestamp"] + assert isinstance(replaced_field, Field) + assert replaced_field.type == Int From f97a8807b5e91f0004d6b25bed17a94a23b8f062 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Mon, 26 Nov 2018 11:16:59 +0100 Subject: [PATCH 2/7] Add implementation for aliased_fields meta option --- graphene_sqlalchemy/types.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/graphene_sqlalchemy/types.py b/graphene_sqlalchemy/types.py index e8a05c8f..89916278 100644 --- a/graphene_sqlalchemy/types.py +++ b/graphene_sqlalchemy/types.py @@ -19,8 +19,10 @@ from .utils import get_query, is_mapped_class, is_mapped_instance -def construct_fields(model, registry, only_fields, exclude_fields): +def construct_fields(model, registry, only_fields, exclude_fields, aliased_fields): inspected_model = sqlalchemyinspect(model) + if aliased_fields is None: + aliased_fields = {} fields = OrderedDict() @@ -33,7 +35,8 @@ def construct_fields(model, registry, only_fields, exclude_fields): # in there. Or when we exclude this field in exclude_fields continue converted_column = convert_sqlalchemy_column(column, registry) - fields[name] = converted_column + alias = aliased_fields.get(name, name) + fields[alias] = converted_column for name, composite in inspected_model.composites.items(): is_not_in_only = only_fields and name not in only_fields @@ -44,7 +47,8 @@ def construct_fields(model, registry, only_fields, exclude_fields): # in there. Or when we exclude this field in exclude_fields continue converted_composite = convert_sqlalchemy_composite(composite, registry) - fields[name] = converted_composite + alias = aliased_fields.get(name, name) + fields[alias] = converted_composite for hybrid_item in inspected_model.all_orm_descriptors: @@ -61,7 +65,8 @@ def construct_fields(model, registry, only_fields, exclude_fields): continue converted_hybrid_property = convert_sqlalchemy_hybrid_method(hybrid_item) - fields[name] = converted_hybrid_property + alias = aliased_fields.get(name, name) + fields[alias] = converted_hybrid_property # Get all the columns for the relationships on the model for relationship in inspected_model.relationships: @@ -74,7 +79,8 @@ def construct_fields(model, registry, only_fields, exclude_fields): continue converted_relationship = convert_sqlalchemy_relationship(relationship, registry) name = relationship.key - fields[name] = converted_relationship + alias = aliased_fields.get(name, name) + fields[alias] = converted_relationship return fields @@ -95,6 +101,7 @@ def __init_subclass_with_meta__( skip_registry=False, only_fields=(), exclude_fields=(), + aliased_fields=None, connection=None, connection_class=None, use_connection=None, @@ -116,7 +123,7 @@ def __init_subclass_with_meta__( ).format(cls.__name__, registry) sqla_fields = yank_fields_from_attrs( - construct_fields(model, registry, only_fields, exclude_fields), _as=Field + construct_fields(model, registry, only_fields, exclude_fields, aliased_fields), _as=Field ) if use_connection is None and interfaces: From 09178d99898b50f1add3703b88c3194979dd8561 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Mon, 26 Nov 2018 12:17:57 +0100 Subject: [PATCH 3/7] Add aliased_fields example in README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 91a5349f..ba3bd554 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ class User(SQLAlchemyObjectType): only_fields = ("name",) # exclude specified fields exclude_fields = ("last_name",) + # alias specified fields + aliased_fields = {'name': 'first_name'} class Query(graphene.ObjectType): users = graphene.List(User) From 53a61aba0be7b79b87d01019cd3712318faebe43 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Thu, 28 Mar 2019 20:00:42 +0100 Subject: [PATCH 4/7] Change aliased_fields to rename_fields for consistency --- README.md | 4 ++-- graphene_sqlalchemy/tests/test_types.py | 15 +++++++------- graphene_sqlalchemy/types.py | 26 ++++++++++++------------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ba3bd554..38a70cfb 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ class User(SQLAlchemyObjectType): only_fields = ("name",) # exclude specified fields exclude_fields = ("last_name",) - # alias specified fields - aliased_fields = {'name': 'first_name'} + # Rename specified fields + rename_fields = {'name': 'first_name'} class Query(graphene.ObjectType): users = graphene.List(User) diff --git a/graphene_sqlalchemy/tests/test_types.py b/graphene_sqlalchemy/tests/test_types.py index 15ba1f8e..f8668e36 100644 --- a/graphene_sqlalchemy/tests/test_types.py +++ b/graphene_sqlalchemy/tests/test_types.py @@ -183,7 +183,7 @@ class Meta: assert result is not None -class HumanWithFieldAliased(SQLAlchemyObjectType): +class HumanWithFieldRenamed(SQLAlchemyObjectType): publication_timestamp = Int() @@ -191,7 +191,7 @@ class Meta: model = Article registry = registry interfaces = (Node,) - aliased_fields = { + rename_fields = { "id": "article_id", "headline": "title", "pub_date": "publication_timestamp", @@ -200,17 +200,18 @@ class Meta: } -def test_objecttype_with_aliased_fields(): - assert issubclass(HumanWithFieldAliased, ObjectType) - assert HumanWithFieldAliased._meta.model == Article - assert list(HumanWithFieldAliased._meta.fields.keys()) == [ +def test_objecttype_with_rename_fields(): + assert issubclass(HumanWithFieldRenamed, ObjectType) + assert HumanWithFieldRenamed._meta.model == Article + assert list(HumanWithFieldRenamed._meta.fields) == [ "article_id", "title", + "description", "publication_timestamp", "journalist_id", "journalist", "id", # Graphene Node ID ] - replaced_field = HumanWithFieldAliased._meta.fields["publication_timestamp"] + replaced_field = HumanWithFieldRenamed._meta.fields["publication_timestamp"] assert isinstance(replaced_field, Field) assert replaced_field.type == Int diff --git a/graphene_sqlalchemy/types.py b/graphene_sqlalchemy/types.py index 89916278..c256b44b 100644 --- a/graphene_sqlalchemy/types.py +++ b/graphene_sqlalchemy/types.py @@ -19,10 +19,10 @@ from .utils import get_query, is_mapped_class, is_mapped_instance -def construct_fields(model, registry, only_fields, exclude_fields, aliased_fields): +def construct_fields(model, registry, only_fields, exclude_fields, rename_fields): inspected_model = sqlalchemyinspect(model) - if aliased_fields is None: - aliased_fields = {} + if rename_fields is None: + rename_fields = {} fields = OrderedDict() @@ -35,8 +35,8 @@ def construct_fields(model, registry, only_fields, exclude_fields, aliased_field # in there. Or when we exclude this field in exclude_fields continue converted_column = convert_sqlalchemy_column(column, registry) - alias = aliased_fields.get(name, name) - fields[alias] = converted_column + field_name = rename_fields.get(name, name) + fields[field_name] = converted_column for name, composite in inspected_model.composites.items(): is_not_in_only = only_fields and name not in only_fields @@ -47,8 +47,8 @@ def construct_fields(model, registry, only_fields, exclude_fields, aliased_field # in there. Or when we exclude this field in exclude_fields continue converted_composite = convert_sqlalchemy_composite(composite, registry) - alias = aliased_fields.get(name, name) - fields[alias] = converted_composite + field_name = rename_fields.get(name, name) + fields[field_name] = converted_composite for hybrid_item in inspected_model.all_orm_descriptors: @@ -65,8 +65,8 @@ def construct_fields(model, registry, only_fields, exclude_fields, aliased_field continue converted_hybrid_property = convert_sqlalchemy_hybrid_method(hybrid_item) - alias = aliased_fields.get(name, name) - fields[alias] = converted_hybrid_property + field_name = rename_fields.get(name, name) + fields[field_name] = converted_hybrid_property # Get all the columns for the relationships on the model for relationship in inspected_model.relationships: @@ -79,8 +79,8 @@ def construct_fields(model, registry, only_fields, exclude_fields, aliased_field continue converted_relationship = convert_sqlalchemy_relationship(relationship, registry) name = relationship.key - alias = aliased_fields.get(name, name) - fields[alias] = converted_relationship + field_name = rename_fields.get(name, name) + fields[field_name] = converted_relationship return fields @@ -101,7 +101,7 @@ def __init_subclass_with_meta__( skip_registry=False, only_fields=(), exclude_fields=(), - aliased_fields=None, + rename_fields=None, connection=None, connection_class=None, use_connection=None, @@ -123,7 +123,7 @@ def __init_subclass_with_meta__( ).format(cls.__name__, registry) sqla_fields = yank_fields_from_attrs( - construct_fields(model, registry, only_fields, exclude_fields, aliased_fields), _as=Field + construct_fields(model, registry, only_fields, exclude_fields, rename_fields), _as=Field ) if use_connection is None and interfaces: From 60202acee85faeb74011d75f46af42f73bf9b54e Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Thu, 28 Mar 2019 20:29:11 +0100 Subject: [PATCH 5/7] Remove useless .keys() for fields comparison in tests --- graphene_sqlalchemy/tests/test_reflected.py | 2 +- graphene_sqlalchemy/tests/test_types.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/graphene_sqlalchemy/tests/test_reflected.py b/graphene_sqlalchemy/tests/test_reflected.py index c8a1a70f..6d2b39d4 100644 --- a/graphene_sqlalchemy/tests/test_reflected.py +++ b/graphene_sqlalchemy/tests/test_reflected.py @@ -17,5 +17,5 @@ class Meta: def test_objecttype_registered(): assert issubclass(Reflected, ObjectType) assert Reflected._meta.model == ReflectedEditor - assert list(Reflected._meta.fields.keys()) == ["editor_id", "name"] + assert list(Reflected._meta.fields) == ["editor_id", "name"] diff --git a/graphene_sqlalchemy/tests/test_types.py b/graphene_sqlalchemy/tests/test_types.py index f8668e36..89ac932d 100644 --- a/graphene_sqlalchemy/tests/test_types.py +++ b/graphene_sqlalchemy/tests/test_types.py @@ -47,7 +47,7 @@ def test_sqlalchemy_interface(): def test_objecttype_registered(): assert issubclass(Character, ObjectType) assert Character._meta.model == Reporter - assert list(Character._meta.fields.keys()) == [ + assert list(Character._meta.fields) == [ "id", "first_name", "last_name", @@ -87,7 +87,7 @@ class Meta: interfaces = (Node,) assert issubclass(Human, ObjectType) - assert list(Human._meta.fields.keys()) == [ + assert list(Human._meta.fields) == [ "id", "headline", "pub_date", @@ -114,7 +114,7 @@ class Meta: def test_custom_objecttype_registered(): assert issubclass(CustomCharacter, ObjectType) assert CustomCharacter._meta.model == Reporter - assert list(CustomCharacter._meta.fields.keys()) == [ + assert list(CustomCharacter._meta.fields) == [ "id", "first_name", "last_name", @@ -157,7 +157,7 @@ class Meta: def test_objecttype_with_custom_options(): assert issubclass(ReporterWithCustomOptions, ObjectType) assert ReporterWithCustomOptions._meta.model == Reporter - assert list(ReporterWithCustomOptions._meta.fields.keys()) == [ + assert list(ReporterWithCustomOptions._meta.fields) == [ "custom_field", "id", "first_name", From e66a0a5b026b37415e40e52f63b58a0085124ea4 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Thu, 28 Mar 2019 20:31:09 +0100 Subject: [PATCH 6/7] Add a rename_fields example with Reflected model --- graphene_sqlalchemy/tests/test_reflected.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/graphene_sqlalchemy/tests/test_reflected.py b/graphene_sqlalchemy/tests/test_reflected.py index 6d2b39d4..5f20e12e 100644 --- a/graphene_sqlalchemy/tests/test_reflected.py +++ b/graphene_sqlalchemy/tests/test_reflected.py @@ -19,3 +19,15 @@ def test_objecttype_registered(): assert Reflected._meta.model == ReflectedEditor assert list(Reflected._meta.fields) == ["editor_id", "name"] + +class ReflectedWithFieldRenamed(SQLAlchemyObjectType): + class Meta: + model = ReflectedEditor + registry = registry + rename_fields = { + "name": "editor_name", + } + + +def test_objecttype_registered_with_rename_fields(): + assert list(ReflectedWithFieldRenamed._meta.fields) == ["editor_id", "editor_name"] From ec8afb56befa113a941b279b1ffb65ce504af71c Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Thu, 28 Mar 2019 20:31:21 +0100 Subject: [PATCH 7/7] Add a non-renamed field in tests --- graphene_sqlalchemy/tests/models.py | 1 + graphene_sqlalchemy/tests/test_types.py | 1 + 2 files changed, 2 insertions(+) diff --git a/graphene_sqlalchemy/tests/models.py b/graphene_sqlalchemy/tests/models.py index 3ba23a8a..9582be6d 100644 --- a/graphene_sqlalchemy/tests/models.py +++ b/graphene_sqlalchemy/tests/models.py @@ -58,6 +58,7 @@ class Article(Base): __tablename__ = "articles" id = Column(Integer(), primary_key=True) headline = Column(String(100)) + description = Column(String(100)) pub_date = Column(Date()) reporter_id = Column(Integer(), ForeignKey("reporters.id")) diff --git a/graphene_sqlalchemy/tests/test_types.py b/graphene_sqlalchemy/tests/test_types.py index 89ac932d..88289ccb 100644 --- a/graphene_sqlalchemy/tests/test_types.py +++ b/graphene_sqlalchemy/tests/test_types.py @@ -90,6 +90,7 @@ class Meta: assert list(Human._meta.fields) == [ "id", "headline", + "description", "pub_date", "reporter_id", "reporter",