Skip to content

Commit fbdd3e2

Browse files
authored
Merge pull request #44 from FloatingGhost/master
Fix #43: Rescan any fields that have not been converted
2 parents 91046ab + ea5fc25 commit fbdd3e2

File tree

7 files changed

+161
-3
lines changed

7 files changed

+161
-3
lines changed

graphene_mongo/converter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ def dynamic_type():
8989
_type = registry.get_type_for_model(model)
9090
if not _type:
9191
return None
92-
9392
return Field(_type)
9493

9594
return Dynamic(dynamic_type)

graphene_mongo/registry.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ def register(self, cls):
1111
assert cls._meta.registry == self, 'Registry for a Model have to match.'
1212
self._registry[cls._meta.model] = cls
1313

14+
# Rescan all fields
15+
for model, cls in self._registry.items():
16+
cls.rescan_fields()
17+
1418
def get_type_for_model(self, model):
1519
return self._registry.get(model)
1620

graphene_mongo/tests/models.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,25 @@ class ProfessorVector(Document):
9898
meta = {'collection': 'test_professor_vector'}
9999
vec = ListField(FloatField())
100100
metadata = EmbeddedDocumentField(ProfessorMetadata)
101+
102+
103+
class ParentWithRelationship(Document):
104+
105+
meta = {'collection': 'test_parent_reference'}
106+
before_child = ListField(ReferenceField("ChildRegisteredBefore"))
107+
after_child = ListField(ReferenceField("ChildRegisteredAfter"))
108+
name = StringField()
109+
110+
111+
class ChildRegisteredBefore(Document):
112+
113+
meta = {'collection': 'test_child_before_reference'}
114+
parent = ReferenceField(ParentWithRelationship)
115+
name = StringField()
116+
117+
118+
class ChildRegisteredAfter(Document):
119+
120+
meta = {'collection': 'test_child_after_reference'}
121+
parent = ReferenceField(ParentWithRelationship)
122+
name = StringField()

graphene_mongo/tests/setup.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from .models import (
33
Article, Editor, EmbeddedArticle, Player,
44
Reporter, Child, ProfessorMetadata, ProfessorVector,
5+
ChildRegisteredBefore, ChildRegisteredAfter,
6+
ParentWithRelationship
57
)
68

79

@@ -105,3 +107,27 @@ def fixtures():
105107
metadata=professor_metadata
106108
)
107109
professor_vector.save()
110+
111+
ParentWithRelationship.drop_collection()
112+
ChildRegisteredAfter.drop_collection()
113+
ChildRegisteredBefore.drop_collection()
114+
115+
# This is one messed up family
116+
117+
# She'd better have presence this time
118+
child3 = ChildRegisteredBefore(name="Akari")
119+
child4 = ChildRegisteredAfter(name="Kyouko")
120+
child3.save()
121+
child4.save()
122+
123+
parent = ParentWithRelationship(
124+
name="Yui",
125+
before_child=[child3],
126+
after_child=[child4]
127+
)
128+
129+
parent.save()
130+
131+
child3.parent = child4.parent = parent
132+
child3.save()
133+
child4.save()

graphene_mongo/tests/test_relay_query.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
EditorNode,
1111
PlayerNode,
1212
ReporterNode,
13-
ChildNode,)
13+
ChildNode,
14+
ParentWithRelationshipNode)
1415
from ..fields import MongoengineConnectionField
1516

1617

@@ -648,3 +649,69 @@ class Query(graphene.ObjectType):
648649
assert not result.errors
649650
assert json.dumps(result.data, sort_keys=True) == json.dumps(
650651
expected, sort_keys=True)
652+
653+
654+
def test_should_lazy_reference(fixtures):
655+
656+
class Query(graphene.ObjectType):
657+
node = Node.Field()
658+
parents = MongoengineConnectionField(ParentWithRelationshipNode)
659+
660+
schema = graphene.Schema(query=Query)
661+
662+
query = """
663+
query {
664+
parents {
665+
edges {
666+
node {
667+
beforeChild {
668+
edges {
669+
node {
670+
name,
671+
parent { name }
672+
}
673+
}
674+
},
675+
afterChild {
676+
edges {
677+
node {
678+
name,
679+
parent { name }
680+
}
681+
}
682+
}
683+
}
684+
}
685+
}
686+
}
687+
"""
688+
689+
expected = {
690+
"parents": {
691+
"edges": [
692+
{"node": {
693+
"beforeChild": {
694+
"edges": [
695+
{"node": {
696+
"name": "Akari",
697+
"parent": {"name": "Yui"}
698+
}}
699+
]
700+
},
701+
"afterChild": {
702+
"edges": [
703+
{"node": {
704+
"name": "Kyouko",
705+
"parent": {"name": "Yui"}
706+
}}
707+
]
708+
}
709+
}}
710+
]
711+
}
712+
}
713+
714+
result = schema.execute(query)
715+
assert not result.errors
716+
assert json.dumps(result.data, sort_keys=True) == json.dumps(
717+
expected, sort_keys=True)

graphene_mongo/tests/types.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from .models import (
55
Article, Editor, EmbeddedArticle, Player, Reporter,
66
Parent, Child, ProfessorMetadata, ProfessorVector,
7+
ParentWithRelationship, ChildRegisteredBefore,
8+
ChildRegisteredAfter
79
)
810

911

@@ -107,3 +109,21 @@ class ChildNode(MongoengineObjectType):
107109
class Meta:
108110
model = Child
109111
interfaces = (Node,)
112+
113+
114+
class ChildRegisteredBeforeNode(MongoengineObjectType):
115+
class Meta:
116+
model = ChildRegisteredBefore
117+
interfaces = (Node, )
118+
119+
120+
class ParentWithRelationshipNode(MongoengineObjectType):
121+
class Meta:
122+
model = ParentWithRelationship
123+
interfaces = (Node, )
124+
125+
126+
class ChildRegisteredAfterNode(MongoengineObjectType):
127+
class Meta:
128+
model = ChildRegisteredAfter
129+
interfaces = (Node, )

graphene_mongo/types.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=Fa
8080
model, registry, only_fields, exclude_fields
8181
)
8282
mongoengine_fields = yank_fields_from_attrs(converted_fields, _as=Field)
83-
8483
if use_connection is None and interfaces:
8584
use_connection = any((issubclass(interface, Node) for interface in interfaces))
8685

@@ -103,6 +102,9 @@ def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=Fa
103102
_meta.fields = mongoengine_fields
104103
_meta.filter_fields = filter_fields
105104
_meta.connection = connection
105+
# Save them for later
106+
_meta.only_fields = only_fields
107+
_meta.exclude_fields = exclude_fields
106108

107109
super(MongoengineObjectType, cls).__init_subclass_with_meta__(
108110
_meta=_meta, interfaces=interfaces, **options
@@ -117,6 +119,24 @@ def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=Fa
117119
cls._meta.fields.update(mongoengine_fields)
118120
registry.register(cls)
119121

122+
@classmethod
123+
def rescan_fields(cls):
124+
"""Attempts to rescan fields and will insert any not converted initially"""
125+
126+
converted_fields, self_referenced = construct_fields(
127+
cls._meta.model, cls._meta.registry,
128+
cls._meta.only_fields, cls._meta.exclude_fields
129+
)
130+
131+
mongoengine_fields = yank_fields_from_attrs(converted_fields, _as=Field)
132+
133+
# The initial scan should take precidence
134+
for field in mongoengine_fields:
135+
if field not in cls._meta.fields:
136+
cls._meta.fields.update({field: mongoengine_fields[field]})
137+
# Self-referenced fields can't change between scans!
138+
139+
120140
# noqa
121141
@classmethod
122142
def is_type_of(cls, root, info):

0 commit comments

Comments
 (0)