11from fastapi_startkit .masoniteorm .models import registry
2- from .BaseRelationship import BaseRelationship
32from ..collection import Collection
3+ from .BaseRelationship import BaseRelationship
44
55
66class MorphOne (BaseRelationship ):
@@ -22,69 +22,110 @@ def set_keys(self, owner, attribute):
2222 self .morph_key = self .morph_key or "record_type"
2323 return self
2424
25- def _related_model (self ):
26- """Resolve the related model class from the relationship factory (``self.fn``)."""
27- return self .fn (self )
25+ def __get__ (self , instance , owner ):
26+ """This method is called when the decorated method is accessed.
2827
29- def _related_query (self ):
30- return self ._related_model ().query ()
28+ Arguments:
29+ instance {object|None} -- The instance we called.
30+ If we didn't call the attribute and only accessed it then this will be None.
3131
32- def __get__ (self , instance , owner ):
32+ owner {object} -- The current model that the property was accessed on.
33+
34+ Returns:
35+ object -- Either returns a builder or a hydrated model.
36+ """
3337 if instance is None :
3438 return self
3539
40+ attribute = self .fn .__name__
3641 self ._related_builder = instance .get_builder ()
37- self .polymorphic_builder = self ._related_query ()
38- self .set_keys (owner , self .attribute )
42+ self .polymorphic_builder = self .fn ( self ) ()
43+ self .set_keys (owner , self .fn )
3944
4045 if not instance .is_loaded ():
4146 return self
4247
43- if self . attribute in instance ._relationships :
44- return instance ._relationships [self . attribute ]
48+ if attribute in instance ._relationships :
49+ return instance ._relationships [attribute ]
4550
4651 return self .apply_query (self ._related_builder , instance )
4752
4853 def __getattr__ (self , attribute ):
49- if attribute .startswith ("_" ):
50- raise AttributeError (attribute )
51- builder = self .__dict__ .get ("_related_builder" )
52- if builder is None :
53- raise AttributeError (attribute )
54- return getattr (builder , attribute )
54+ relationship = self .fn (self )()
55+ return getattr (relationship .builder , attribute )
5556
5657 def apply_query (self , builder , instance ):
58+ """Apply the query and return a dictionary to be hydrated
59+
60+ Arguments:
61+ builder {oject} -- The relationship object
62+ instance {object} -- The current model oject.
63+
64+ Returns:
65+ dict -- A dictionary of data which will be hydrated.
66+ """
5767 polymorphic_key = self .get_record_key_lookup (instance )
68+ polymorphic_builder = self .polymorphic_builder
69+
5870 return (
59- self . polymorphic_builder .where (self .morph_key , polymorphic_key )
71+ polymorphic_builder .where (self .morph_key , polymorphic_key )
6072 .where (self .morph_id , instance .get_attribute (instance .__primary_key__ ))
6173 .first ()
6274 )
6375
64- async def get_related (self , query , relation , eagers = None , callback = None ):
76+ def get_related (self , query , relation , eagers = None , callback = None ):
77+ """Gets the relation needed between the relation and the related builder. If the relation is a collection
78+ then will need to pluck out all the keys from the collection and fetch from the related builder. If
79+ relation is just a Model then we can just call the model based on the value of the related
80+ builders primary key.
81+
82+ Args:
83+ relation (Model|Collection):
84+
85+ Returns:
86+ Model|Collection
87+ """
88+ self .polymorphic_builder = self .fn (self )()
89+
6590 if isinstance (relation , Collection ):
6691 record_type = self .get_record_key_lookup (relation .first ())
67- builder = (
68- self ._related_query ()
69- .where (self .morph_key , record_type )
92+ if callback :
93+ return callback (
94+ self .polymorphic_builder .where (
95+ f"{ self .polymorphic_builder .get_table_name ()} .{ self .morph_key } " ,
96+ record_type ,
97+ ).where_in (
98+ self .morph_id ,
99+ relation .pluck (relation .first ().__primary_key__ , keep_nulls = False ).unique (),
100+ )
101+ ).get ()
102+
103+ return (
104+ self .polymorphic_builder .where (
105+ f"{ self .polymorphic_builder .get_table_name ()} .{ self .morph_key } " ,
106+ record_type ,
107+ )
70108 .where_in (
71109 self .morph_id ,
72110 relation .pluck (relation .first ().__primary_key__ , keep_nulls = False ).unique (),
73111 )
112+ .get ()
74113 )
114+
115+ else :
116+ record_type = self .get_record_key_lookup (relation )
75117 if callback :
76- builder = callback (builder )
77- return await builder .get ()
78-
79- record_type = self .get_record_key_lookup (relation )
80- builder = (
81- self ._related_query ()
82- .where (self .morph_key , record_type )
83- .where (self .morph_id , relation .get_attribute (relation .__primary_key__ ))
84- )
85- if callback :
86- builder = callback (builder )
87- return await builder .first ()
118+ return callback (
119+ self .polymorphic_builder .where (self .morph_key , record_type ).where (
120+ self .morph_id , relation .get_attribute (relation .__primary_key__ )
121+ )
122+ ).first ()
123+
124+ return (
125+ self .polymorphic_builder .where (self .morph_key , record_type )
126+ .where (self .morph_id , relation .get_attribute (relation .__primary_key__ ))
127+ .first ()
128+ )
88129
89130 def register_related (self , key , model , collection ):
90131 record_type = self .get_record_key_lookup (model )
@@ -93,6 +134,7 @@ def register_related(self, key, model, collection):
93134 .where (self .morph_id , model .get_attribute (model .__primary_key__ ))
94135 .first ()
95136 )
137+
96138 model .add_relation ({key : related })
97139
98140 def map_related (self , related_result ):
@@ -102,7 +144,7 @@ def morph_map(self):
102144 return registry .Registry .get_morph_map ()
103145
104146 def get_record_key_lookup (self , relation ):
105- morph_name = registry .Registry ._reverse_map . get (relation .__class__ )
106- if morph_name is None or morph_name == relation .__class__ .__name__ :
147+ record_type = registry .Registry .get_morph_name (relation .__class__ )
148+ if record_type == relation .__class__ .__name__ :
107149 raise ValueError (f"Could not find the record type key for the { relation } class" )
108- return morph_name
150+ return record_type
0 commit comments