Skip to content

Commit 5bcac7d

Browse files
author
Matt Sokoloff
committed
cache validation
1 parent ea3531c commit 5bcac7d

File tree

2 files changed

+37
-24
lines changed

2 files changed

+37
-24
lines changed

labelbox/orm/model.py

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -239,45 +239,58 @@ class EntityMeta(type):
239239
of the Entity class object so they can be referenced for example like:
240240
Entity.Project.
241241
"""
242+
mappings = {}
242243

243244
def __init__(cls, clsname, superclasses, attributedict):
244245
super().__init__(clsname, superclasses, attributedict)
245246
cls.validate_cached_relationships()
246247
if clsname != "Entity":
247248
setattr(Entity, clsname, cls)
248-
if not hasattr(Entity, 'entities'):
249-
setattr(Entity, 'entities', [])
250-
Entity.entities.append(cls)
249+
EntityMeta.mappings[utils.snake_case(
250+
cls.__name__)] = cls.relationships()
251+
252+
@staticmethod
253+
def raise_for_nested_cache(first: str, middle: str, last: str):
254+
raise TypeError(
255+
"Cannot cache a relationship to an Entity with its own cached relationship(s). "
256+
f"`{first}` caches `{middle}` which caches `{last}`")
251257

252258
def validate_cached_relationships(cls):
253259
"""
254260
Graphql doesn't allow for infinite nesting in queries.
255261
This function checks that cached relationships result in valid queries.
256-
- A cached object and not have its own cached relationships.
257-
"""
262+
* It does this by making sure that a cached relationship do not
263+
reference any entity with its own cached relationships.
258264
265+
This check is performed by looking to see if this entity caches
266+
any entities that have their own cached fields. If this entity
267+
that we are checking has any cached fields then we also check
268+
all currently defined entities to see if they cache this entity.
269+
270+
A two way check is necessary because checks are performed as classes are being defined.
271+
As opposed to after all objects have been created.
272+
"""
259273
cached_rels = [r for r in cls.relationships() if r.cache]
260-
# Check if any cached classes have their own cached fields
274+
# Check if any cached entities have their own cached fields
261275
for rel in cached_rels:
262-
child_name = utils.title_case(rel.name)
263-
if hasattr(Entity, child_name):
264-
for sub_rel in getattr(Entity, child_name).relationships():
265-
if sub_rel.cache:
266-
raise TypeError(
267-
"Cannot cache a relationship to an Entity with its own cached relationship(s). "
268-
f"`{utils.snake_case(cls.__name__)}` caches `{rel.name}` which caches `{sub_rel}`"
269-
)
270-
271-
# If this cls has cached fields check if any existing object caches this cls.
276+
cached_entities = EntityMeta.mappings.get(rel.name, [])
277+
nested = [entity.name for entity in cached_entities if entity.cache]
278+
if nested:
279+
cls.raise_for_nested_cache(utils.snake_case(cls.__name__),
280+
rel.name, nested)
281+
282+
# If this entity caches any other entity
283+
# then check if any entity caches this entity
272284
if cached_rels:
273-
for entity in Entity.entities:
274-
attr = {rel.name: rel for rel in entity.relationships()
285+
for entity_name, entity_relationships in EntityMeta.mappings.items(
286+
):
287+
attr = {rel.name: rel for rel in entity_relationships
275288
}.get(utils.snake_case(cls.__name__))
276289
if attr and attr.cache:
277-
raise TypeError(
278-
"Cannot cache a relationship to an Entity with its own cached relationship(s). "
279-
f"`{utils.snake_case(entity.__name__)}` caches `{utils.snake_case(cls.__name__)}` which caches `{cached_rels}`"
280-
)
290+
cls.raise_for_nested_cache(
291+
utils.snake_case(entity_name),
292+
utils.snake_case(cls.__name__),
293+
[entity.name for entity in cached_rels])
281294

282295

283296
class Entity(metaclass=EntityMeta):

tests/test_entity_meta.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class TestEntityB(DbObject):
1616

1717
assert str(exc_info.value) == \
1818
"Cannot cache a relationship to an Entity with its own cached relationship(s)." \
19-
" `test_entity_a` caches `test_entity_b` which caches `[<Relationship: 'another_entity'>]`"
19+
" `test_entity_a` caches `test_entity_b` which caches `['another_entity']`"
2020

2121

2222
def test_illegal_cache_cond2():
@@ -31,4 +31,4 @@ class TestEntityC(DbObject):
3131

3232
assert str(exc_info.value) == \
3333
"Cannot cache a relationship to an Entity with its own cached relationship(s)." \
34-
" `test_entity_c` caches `test_entity_d` which caches `another_entity`"
34+
" `test_entity_c` caches `test_entity_d` which caches `['another_entity']`"

0 commit comments

Comments
 (0)