Skip to content
This repository was archived by the owner on May 18, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 89 additions & 18 deletions graphene_pynamodb/converter.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import inspect
import json
from collections import OrderedDict

from graphene import Dynamic, Field, Float
from graphene import ID, Boolean, List, String
from graphene.types.json import JSONString
from pynamodb import attributes
from singledispatch import singledispatch

from graphene import ID, Boolean, Dynamic, Field, Float, Int, List, String
from graphene.types import ObjectType
from graphene.types.json import JSONString
from graphene.types.resolver import default_resolver
from graphene_pynamodb import relationships
from graphene_pynamodb.fields import PynamoConnectionField
from graphene_pynamodb.relationships import OneToOne, OneToMany
from graphene_pynamodb.registry import Registry
from graphene_pynamodb.relationships import OneToMany, OneToOne


@singledispatch
def convert_pynamo_attribute(type, attribute, registry=None):
raise Exception(
"Don't know how to convert the PynamoDB attribute %s (%s)" % (attribute, attribute.__class__))
"Don't know how to convert the PynamoDB attribute %s (%s)"
% (attribute, attribute.__class__)
)


@convert_pynamo_attribute.register(attributes.BinaryAttribute)
Expand All @@ -23,14 +29,18 @@ def convert_column_to_string(type, attribute, registry=None):
if attribute.is_hash_key:
return ID(description=attribute.attr_name, required=not attribute.null)

return String(description=getattr(attribute, 'attr_name'),
required=not (getattr(attribute, 'null', True)))
return String(
description=getattr(attribute, "attr_name"),
required=not (getattr(attribute, "null", True)),
)


@convert_pynamo_attribute.register(attributes.UTCDateTimeAttribute)
def convert_date_to_string(type, attribute, registry=None):
return String(description=getattr(attribute, 'attr_name'),
required=not (getattr(attribute, 'null', True)))
return String(
description=getattr(attribute, "attr_name"),
required=not (getattr(attribute, "null", True)),
)


@convert_pynamo_attribute.register(relationships.Relationship)
Expand Down Expand Up @@ -77,7 +87,7 @@ def convert_json_to_string(type, attribute, registry=None):


class MapToJSONString(JSONString):
'''JSON String Converter for MapAttribute'''
"""JSON String Converter for MapAttribute"""

@staticmethod
def serialize(dt):
Expand All @@ -98,25 +108,86 @@ def serialize(dt):
return dt


def map_attribute_to_object_type(attribute, registry: Registry):
if not hasattr(registry, "map_attr_types"):
registry.map_attr_types = {}
if attribute in registry.map_attr_types:
return registry.map_attr_types[attribute]

fields = OrderedDict()
for name, attr in attribute.get_attributes().items():
fields[name] = convert_pynamo_attribute(attr, attr, registry)

map_attribute_type = type(
f"MapAttribute_{attribute.__name__}", (ObjectType,), fields,
)

registry.map_attr_types[attribute] = map_attribute_type
return map_attribute_type


@convert_pynamo_attribute.register(attributes.MapAttribute)
def convert_map_to_json(type, attribute, registry=None):
def convert_map_to_object_type(attribute, _, registry=None):
try:
name = attribute.attr_name
except (KeyError, AttributeError):
name = "MapAttribute"
required = not attribute.null if hasattr(attribute, 'null') else False
return MapToJSONString(description=name, required=required)
required = not attribute.null if hasattr(attribute, "null") else False
return map_attribute_to_object_type(attribute, registry)(
description=name, required=required
)


def list_resolver(
parent,
info,
index: int = None,
start_index: int = None,
end_index: int = None,
**kwargs,
):
data = default_resolver(
attname=info.field_name, default_value=None, root=parent, info=info, **kwargs
)
if index is not None:
return [data[index]]
if (start_index is not None) and (end_index is not None):
return data[start_index:end_index]
if start_index is not None:
return data[start_index:]
if end_index is not None:
return data[:end_index]
return data


@convert_pynamo_attribute.register(attributes.ListAttribute)
def convert_list_to_list(type, attribute, registry=None):
if attribute.element_type:
kwargs = dict(
resolver=list_resolver,
index=Int(description="Return element at the position"),
start_index=Int(description="Start of the slice of the list"),
end_index=Int(
description="End of the slice of the list. Negative numbers can be given to access from the end."
),
)

if attribute.element_type and inspect.isclass(attribute.element_type):
try:
name = attribute.attr_name
except KeyError:
name = "MapAttribute"
name = attribute.element_type.__name__

required = not attribute.null if hasattr(attribute, "null") else False

if issubclass(attribute.element_type, attributes.MapAttribute):
cls = map_attribute_to_object_type(attribute.element_type, registry)
elif issubclass(attribute.element_type, attributes.NumberAttribute):
cls = Int
elif issubclass(attribute.element_type, attributes.BooleanAttribute):
cls = Boolean
else:
cls = String

required = not attribute.null if hasattr(attribute, 'null') else False
return ListOfMapToObject(description=name, required=required)
return List(cls, description=name, required=required, **kwargs,)
else:
return List(String, description=attribute.attr_name)
return List(String, description=attribute.attr_name, **kwargs)
8 changes: 3 additions & 5 deletions graphene_pynamodb/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ def get_model_fields(model, excluding=None):
if excluding is None:
excluding = []
attributes = dict()
for attr_name in vars(model):

for attr_name, attr in model.get_attributes().items():
if attr_name in excluding:
continue
attr = getattr(model, attr_name)
if isinstance(attr, Attribute):
attributes[attr_name] = attr

attributes[attr_name] = attr
return OrderedDict(sorted(attributes.items(), key=lambda t: t[0]))


Expand Down
3 changes: 1 addition & 2 deletions graphene_pynamodb/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ def get_key_name(model):
if model in MODEL_KEY_REGISTRY:
return MODEL_KEY_REGISTRY[model]

for attr in vars(model):
attr = getattr(model, attr)
for attr in model.get_attributes().values():
if isinstance(attr, Attribute) and attr.is_hash_key:
MODEL_KEY_REGISTRY[model] = attr.attr_name
return attr.attr_name
Expand Down