@@ -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
283296class Entity (metaclass = EntityMeta ):
0 commit comments