mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-01 00:17:26 +03:00 
			
		
		
		
	Merge branch 'next' of github.com:graphql-python/graphene into next
This commit is contained in:
		
						commit
						5da0fef083
					
				|  | @ -9,11 +9,14 @@ from graphene.types.json import JSONString | |||
| from .fields import SQLAlchemyConnectionField | ||||
| 
 | ||||
| try: | ||||
|     from sqlalchemy_utils.types.choice import ChoiceType | ||||
|     from sqlalchemy_utils import ChoiceType, ScalarListType | ||||
| except ImportError: | ||||
|     class ChoiceType(object): | ||||
|         pass | ||||
| 
 | ||||
|     class ScalarListType(object): | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| def convert_sqlalchemy_relationship(relationship, registry): | ||||
|     direction = relationship.direction | ||||
|  | @ -34,6 +37,33 @@ def convert_sqlalchemy_relationship(relationship, registry): | |||
|     return Dynamic(dynamic_type) | ||||
| 
 | ||||
| 
 | ||||
| def convert_sqlalchemy_composite(composite, registry): | ||||
|     converter = registry.get_converter_for_composite(composite.composite_class) | ||||
|     if not converter: | ||||
|         try: | ||||
|             raise Exception( | ||||
|                 "Don't know how to convert the composite field %s (%s)" % | ||||
|                 (composite, composite.composite_class)) | ||||
|         except AttributeError: | ||||
|             # handle fields that are not attached to a class yet (don't have a parent) | ||||
|             raise Exception( | ||||
|                 "Don't know how to convert the composite field %r (%s)" % | ||||
|                 (composite, composite.composite_class)) | ||||
|     return converter(composite, registry) | ||||
| 
 | ||||
| 
 | ||||
| def _register_composite_class(cls, registry=None): | ||||
|     if registry is None: | ||||
|         from .registry import get_global_registry | ||||
|         registry = get_global_registry() | ||||
| 
 | ||||
|     def inner(fn): | ||||
|         registry.register_composite_converter(cls, fn) | ||||
|     return inner | ||||
| 
 | ||||
| convert_sqlalchemy_composite.register = _register_composite_class | ||||
| 
 | ||||
| 
 | ||||
| def convert_sqlalchemy_column(column, registry=None): | ||||
|     return convert_sqlalchemy_type(getattr(column, 'type', None), column, registry) | ||||
| 
 | ||||
|  | @ -85,6 +115,11 @@ def convert_column_to_enum(type, column, registry=None): | |||
|     return Enum(name, type.choices, description=column.doc) | ||||
| 
 | ||||
| 
 | ||||
| @convert_sqlalchemy_type.register(ScalarListType) | ||||
| def convert_scalar_list_to_list(type, column, registry=None): | ||||
|     return List(String, description=column.doc) | ||||
| 
 | ||||
| 
 | ||||
| @convert_sqlalchemy_type.register(postgresql.ARRAY) | ||||
| def convert_postgres_array_to_list(type, column, registry=None): | ||||
|     graphene_type = convert_sqlalchemy_type(column.type.item_type, column) | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ class Registry(object): | |||
|     def __init__(self): | ||||
|         self._registry = {} | ||||
|         self._registry_models = {} | ||||
|         self._registry_composites = {} | ||||
| 
 | ||||
|     def register(self, cls): | ||||
|         from .types import SQLAlchemyObjectType | ||||
|  | @ -16,6 +17,12 @@ class Registry(object): | |||
|     def get_type_for_model(self, model): | ||||
|         return self._registry.get(model) | ||||
| 
 | ||||
|     def register_composite_converter(self, composite, converter): | ||||
|         self._registry_composites[composite] = converter | ||||
| 
 | ||||
|     def get_converter_for_composite(self, composite): | ||||
|         return self._registry_composites.get(composite) | ||||
| 
 | ||||
| 
 | ||||
| registry = None | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,13 +1,15 @@ | |||
| from py.test import raises | ||||
| from sqlalchemy import Column, Table, types | ||||
| from sqlalchemy.orm import composite | ||||
| from sqlalchemy.ext.declarative import declarative_base | ||||
| from sqlalchemy_utils.types.choice import ChoiceType | ||||
| from sqlalchemy_utils import ChoiceType, ScalarListType | ||||
| from sqlalchemy.dialects import postgresql | ||||
| 
 | ||||
| import graphene | ||||
| from graphene.relay import Node | ||||
| from graphene.types.json import JSONString | ||||
| from ..converter import (convert_sqlalchemy_column, | ||||
|                          convert_sqlalchemy_composite, | ||||
|                          convert_sqlalchemy_relationship) | ||||
| from ..fields import SQLAlchemyConnectionField | ||||
| from ..types import SQLAlchemyObjectType | ||||
|  | @ -25,6 +27,19 @@ def assert_column_conversion(sqlalchemy_type, graphene_field, **kwargs): | |||
|     return field | ||||
| 
 | ||||
| 
 | ||||
| def assert_composite_conversion(composite_class, composite_columns, graphene_field, | ||||
|                                 registry, **kwargs): | ||||
|     composite_column = composite(composite_class, *composite_columns, | ||||
|                                  doc='Custom Help Text', **kwargs) | ||||
|     graphene_type = convert_sqlalchemy_composite(composite_column, registry) | ||||
|     assert isinstance(graphene_type, graphene_field) | ||||
|     field = graphene_type.Field() | ||||
|     # SQLAlchemy currently does not persist the doc onto the column, even though | ||||
|     # the documentation says it does.... | ||||
|     # assert field.description == 'Custom Help Text' | ||||
|     return field | ||||
| 
 | ||||
| 
 | ||||
| def test_should_unknown_sqlalchemy_field_raise_exception(): | ||||
|     with raises(Exception) as excinfo: | ||||
|         convert_sqlalchemy_column(None) | ||||
|  | @ -108,6 +123,10 @@ def test_should_choice_convert_enum(): | |||
|     assert graphene_type._meta.enum.__members__['en'].value == 'English' | ||||
| 
 | ||||
| 
 | ||||
| def test_should_scalar_list_convert_list(): | ||||
|     assert_column_conversion(ScalarListType(), graphene.List) | ||||
| 
 | ||||
| 
 | ||||
| def test_should_manytomany_convert_connectionorlist(): | ||||
|     registry = Registry() | ||||
|     dynamic_field = convert_sqlalchemy_relationship(Reporter.pets.property, registry) | ||||
|  | @ -206,3 +225,42 @@ def test_should_postgresql_jsonb_convert(): | |||
| 
 | ||||
| def test_should_postgresql_hstore_convert(): | ||||
|     assert_column_conversion(postgresql.HSTORE(), JSONString) | ||||
| 
 | ||||
| 
 | ||||
| def test_should_composite_convert(): | ||||
| 
 | ||||
|     class CompositeClass(object): | ||||
|         def __init__(self, col1, col2): | ||||
|             self.col1 = col1 | ||||
|             self.col2 = col2 | ||||
| 
 | ||||
|     registry = Registry() | ||||
| 
 | ||||
|     @convert_sqlalchemy_composite.register(CompositeClass, registry) | ||||
|     def convert_composite_class(composite, registry): | ||||
|         return graphene.String(description=composite.doc) | ||||
| 
 | ||||
|     assert_composite_conversion(CompositeClass, | ||||
|                                 (Column(types.Unicode(50)), | ||||
|                                  Column(types.Unicode(50))), | ||||
|                                 graphene.String, | ||||
|                                 registry) | ||||
| 
 | ||||
| 
 | ||||
| def test_should_unknown_sqlalchemy_composite_raise_exception(): | ||||
|     registry = Registry() | ||||
| 
 | ||||
|     with raises(Exception) as excinfo: | ||||
| 
 | ||||
|         class CompositeClass(object): | ||||
|             def __init__(self, col1, col2): | ||||
|                 self.col1 = col1 | ||||
|                 self.col2 = col2 | ||||
| 
 | ||||
|         assert_composite_conversion(CompositeClass, | ||||
|                                     (Column(types.Unicode(50)), | ||||
|                                      Column(types.Unicode(50))), | ||||
|                                     graphene.String, | ||||
|                                     registry) | ||||
| 
 | ||||
|     assert 'Don\'t know how to convert the composite field' in str(excinfo.value) | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ from sqlalchemy.orm.exc import NoResultFound | |||
| from graphene import ObjectType, Field | ||||
| from graphene.relay import is_node | ||||
| from .converter import (convert_sqlalchemy_column, | ||||
|                         convert_sqlalchemy_composite, | ||||
|                         convert_sqlalchemy_relationship) | ||||
| from .utils import is_mapped | ||||
| 
 | ||||
|  | @ -35,6 +36,17 @@ def construct_fields(options): | |||
|         converted_column = convert_sqlalchemy_column(column, options.registry) | ||||
|         fields[name] = converted_column | ||||
| 
 | ||||
|     for name, composite in inspected_model.composites.items(): | ||||
|         is_not_in_only = only_fields and name not in only_fields | ||||
|         is_already_created = name in options.fields | ||||
|         is_excluded = name in exclude_fields or is_already_created | ||||
|         if is_not_in_only or is_excluded: | ||||
|             # We skip this field if we specify only_fields and is not | ||||
|             # in there. Or when we excldue this field in exclude_fields | ||||
|             continue | ||||
|         converted_composite = convert_sqlalchemy_composite(composite, options.registry) | ||||
|         fields[name] = converted_composite | ||||
| 
 | ||||
|     # Get all the columns for the relationships on the model | ||||
|     for relationship in inspected_model.relationships: | ||||
|         is_not_in_only = only_fields and relationship.key not in only_fields | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user