Added automatic snake casing to camel casing conversion in field names

This commit is contained in:
Syrus Akbary 2015-10-02 22:45:13 -07:00
parent 176696c1ac
commit 701c49db26
7 changed files with 46 additions and 29 deletions

View File

@ -41,7 +41,7 @@ class ConnectionOrListField(LazyField):
field = DjangoConnectionField(model_field)
else:
field = ListField(model_field)
field.contribute_to_class(self.object_type, self.field_name)
field.contribute_to_class(self.object_type, self.name)
return field

View File

@ -10,23 +10,26 @@ from graphql.core.type import (
GraphQLArgument,
GraphQLFloat,
)
from graphene.utils import cached_property, memoize
from graphene.utils import memoize, to_camel_case
from graphene.core.types import BaseObjectType
class Field(object):
def __init__(self, field_type, resolve=None, null=True, args=None, description='', **extra_args):
def __init__(self, field_type, name=None, resolve=None, null=True, args=None, description='', **extra_args):
self.field_type = field_type
self.resolve_fn = resolve
self.null = null
self.args = args or {}
self.extra_args = extra_args
self._type = None
self.name = name
self.description = description or self.__doc__
self.object_type = None
def contribute_to_class(self, cls, name):
if not self.name:
self.name = to_camel_case(name)
self.field_name = name
self.object_type = cls
if isinstance(self.field_type, Field) and not self.field_type.object_type:
@ -94,7 +97,7 @@ class Field(object):
raise TypeError("Field %s.%s initiated with invalid args: %s" % (
self.object_type,
self.field_name,
','.join(meta_attrs.keys())
','.join(extra_args.keys())
))
internal_type = self.internal_type(schema)
@ -107,7 +110,7 @@ class Field(object):
)
def __str__(self):
""" Return "object_type.field_name". """
""" Return "object_type.name". """
return '%s.%s' % (self.object_type, self.field_name)
def __repr__(self):

View File

@ -71,3 +71,7 @@ class Options(object):
@cached_property
def fields_map(self):
return {f.field_name: f for f in self.fields}
@cached_property
def internal_fields_map(self):
return {f.name: f for f in self.fields}

View File

@ -49,7 +49,7 @@ class ObjectTypeMeta(type):
new_class.add_extra_fields()
new_fields = new_class._meta.local_fields
field_names = {f.field_name for f in new_fields}
field_names = {f.name for f in new_fields}
for base in parents:
original_base = base
@ -65,12 +65,12 @@ class ObjectTypeMeta(type):
# on the base classes (we cannot handle shadowed fields at the
# moment).
for field in parent_fields:
if field.field_name in field_names:
if field.name in field_names:
raise Exception(
'Local field %r in class %r clashes '
'with field of similar name from '
'base class %r' % (
field.field_name, name, base.__name__)
field.name, name, base.__name__)
)
new_class._meta.parents.append(base)
if base._meta.interface:
@ -99,7 +99,7 @@ class BaseObjectType(object):
def __new__(cls, instance=None, *args, **kwargs):
if cls._meta.interface:
raise Exception("An interface cannot be initialized")
if instance == None:
if instance is None:
return None
return super(BaseObjectType, cls).__new__(cls, instance, *args, **kwargs)
@ -137,7 +137,7 @@ class BaseObjectType(object):
@memoize
@register_internal_type
def internal_type(cls, schema):
fields_map = cls._meta.fields_map
fields_map = cls._meta.internal_fields_map
fields = lambda: {
name: field.internal_field(schema)
for name, field in fields_map.items()

View File

@ -32,3 +32,12 @@ def memoize(fun):
return ret
cache = {}
return wrapper
# From this response in Stackoverflow
# http://stackoverflow.com/a/19053800/1072990
def to_camel_case(snake_str):
components = snake_str.split('_')
# We capitalize the first letter of each component except the first one
# with the 'title' method and join them together.
return components[0] + "".join(x.title() for x in components[1:])

View File

@ -71,16 +71,16 @@ def test_should_map_fields():
query = '''
query ReporterQuery {
reporter {
first_name,
last_name,
firstName,
lastName,
email
}
}
'''
expected = {
'reporter': {
'first_name': 'ABA',
'last_name': 'X',
'firstName': 'ABA',
'lastName': 'X',
'email': ''
}
}
@ -133,7 +133,7 @@ def test_should_node():
query ReporterQuery {
reporter {
id,
first_name,
firstName,
articles {
edges {
node {
@ -141,13 +141,13 @@ def test_should_node():
}
}
}
last_name,
lastName,
email
}
my_article: node(id:"QXJ0aWNsZU5vZGVUeXBlOjE=") {
myArticle: node(id:"QXJ0aWNsZU5vZGVUeXBlOjE=") {
id
... on ReporterNodeType {
first_name
firstName
}
... on ArticleNodeType {
headline
@ -158,8 +158,8 @@ def test_should_node():
expected = {
'reporter': {
'id': 'UmVwb3J0ZXJOb2RlVHlwZTox',
'first_name': 'ABA',
'last_name': 'X',
'firstName': 'ABA',
'lastName': 'X',
'email': '',
'articles': {
'edges': [{
@ -169,7 +169,7 @@ def test_should_node():
}]
},
},
'my_article': {
'myArticle': {
'id': 'QXJ0aWNsZU5vZGVUeXBlOjE=',
'headline': 'Article node'
}

View File

@ -40,16 +40,16 @@ schema = Schema()
def test_django_interface():
assert DjangoNode._meta.interface == True
assert DjangoNode._meta.interface is True
def test_pseudo_interface():
object_type = Character.internal_type(schema)
assert Character._meta.interface == True
assert Character._meta.interface is True
assert isinstance(object_type, GraphQLInterfaceType)
assert Character._meta.model == Reporter
assert object_type.get_fields().keys() == [
'articles', 'first_name', 'last_name', 'id', 'email']
'lastName', 'email', 'id', 'firstName', 'articles']
def test_interface_resolve_type():
@ -59,12 +59,13 @@ def test_interface_resolve_type():
def test_object_type():
object_type = Human.internal_type(schema)
assert Human._meta.interface == False
internal_fields_map = Human._meta.internal_fields_map
assert Human._meta.interface is False
assert isinstance(object_type, GraphQLObjectType)
assert object_type.get_fields() == {
'headline': Human._meta.fields_map['headline'].internal_field(schema),
'id': Human._meta.fields_map['id'].internal_field(schema),
'reporter': Human._meta.fields_map['reporter'].internal_field(schema),
'pub_date': Human._meta.fields_map['pub_date'].internal_field(schema),
'headline': internal_fields_map['headline'].internal_field(schema),
'id': internal_fields_map['id'].internal_field(schema),
'reporter': internal_fields_map['reporter'].internal_field(schema),
'pubDate': internal_fields_map['pubDate'].internal_field(schema),
}
assert object_type.get_interfaces() == [DjangoNode.internal_type(schema)]