diff --git a/playground.py b/playground.py index d1fe2c57..035820e1 100644 --- a/playground.py +++ b/playground.py @@ -6,115 +6,31 @@ class User(Model): @property def company(self): - related = Company() - - related.owner = self - return HasOne(related, "company_id", "company_id")(self) + return self.has_one(Company, "company_id", "company_id") class CreditCard(Model): __table__ = "company_credit_cards" __primary_key__ = "credit_card_id" - def __call__(self): - return self.__dict__['related'].apply_query(self.builder) - + @property def company(self): - related = Company() - related.owner = self - return HasOne(related, "company_id", "company_id")(self) + return self.has_one(Company, "company_id", "company_id") class Company(Model): __table__ = "tbl_companies" __primary_key__ = "company_id" - def __call__(self): - return self.__dict__['related'].apply_query(self.builder) @property def cards(self): - related = CreditCard() - related.owner = self - return HasMany(related, "company_id", "company_id")(self) - -class BaseRelationship: - def init(self, model_class, local_key=None, foreign_key=None): - self.model_class = model_class - self.local_key = local_key - self.foreign_key = foreign_key - - def __call__(self, owner): - """Create and return the relationship query.""" - # self.set_keys(owner) - related_model = self.model_class() - return self.apply_query(related_model.builder, owner) - -class HasOne(BaseRelationship): - """Belongs To Relationship Class.""" - - def __init__(self, model_class, foreign_key=None, local_key=None): - self.model_class = model_class - self.foreign_key = foreign_key - self.local_key = local_key - self.owner = None - - def apply_query(self, builder): - owner = self.owner - foreign_key_value = owner.__attributes__.get(self.foreign_key) - builder = builder.where(self.local_key, foreign_key_value) - return builder - - - def __call__(self, owner): - """Fetch the related record when invoked.""" - related_model = self.model_class - # print("related model", related_model) - related_model.owner = self - foreign_key_value = owner.__attributes__.get(self.foreign_key) - if not foreign_key_value: - return None - builder = related_model.builder.where(self.local_key, foreign_key_value) - result = builder.first() - self.owner = owner - result.__dict__['related'] = self - return result - - -class HasMany(BaseRelationship): - """Belongs To Relationship Class.""" - - def __init__(self, model_class, foreign_key=None, local_key=None): - self.model_class = model_class - self.foreign_key = foreign_key - self.local_key = local_key - self.owner = None - - def apply_query(self, builder): - owner = self.owner - foreign_key_value = owner.__attributes__.get(self.foreign_key) - builder = builder.where(self.local_key, foreign_key_value) - return builder - - - def __call__(self, owner): - """Fetch the related record when invoked.""" - related_model = self.model_class - # print("related model", related_model) - related_model.owner = self - foreign_key_value = owner.__attributes__.get(self.foreign_key) - if not foreign_key_value: - return None - builder = related_model.builder.where(self.local_key, foreign_key_value) - result = builder.first() - self.owner = owner - result.__dict__['related'] = self - return result - + return self.has_many(CreditCard, "company_id", "company_id") # Usage has one user = User.find(667) # fetches record on related company record -print(user.company.cards) # Output: Company name +for card in user.company.cards: + print(card.company.company_name) # user.company() part returns a query builder so we can fetch related queries on the fly -# print(user.company().limit(1).to_sql()) # Output: select * from tbl_companies where tbl_companies.company_id = 373849 \ No newline at end of file +print(user.company().limit(1).to_sql()) # Output: select * from tbl_companies where tbl_companies.company_id = 373849 \ No newline at end of file diff --git a/src/masoniteorm/models/Model.py b/src/masoniteorm/models/Model.py index 35967eeb..bd9ff68a 100644 --- a/src/masoniteorm/models/Model.py +++ b/src/masoniteorm/models/Model.py @@ -16,6 +16,7 @@ from ..observers import ObservesEvents from ..query import QueryBuilder from ..scopes import TimeStampsMixin +from .relationships.new import HasOne, HasMany """This is a magic class that will help using models like User.first() instead of having to instatiate a class like User().first() @@ -1175,3 +1176,23 @@ def filter_guarded(cls, dictionary: Dict[str, Any]) -> Dict[str, Any]: # If all fields are guarded, all data should be filtered return {} return {f: dictionary[f] for f in dictionary if f not in cls.__guarded__} + + def __call__(self): + return self.__dict__['related'].apply_query(self.builder) + + +# Move this to a relayion class + def has_one(self, related_model_class, foreign_key=None, local_key=None): + if not local_key: + local_key = f"{related_model_class.get_table_name()}{related_model_class.get_primary_key()}" + if not foreign_key: + foreign_key = related_model_class.get_primary_key() + return HasOne(related_model_class, foreign_key, local_key)(self) + + def has_many(self, related_model_class, foreign_key=None, local_key=None): + if not local_key: + local_key = f"{related_model_class.get_table_name()}{related_model_class.get_primary_key()}" + if not foreign_key: + foreign_key = related_model_class.get_primary_key() + return HasMany(related_model_class, foreign_key, local_key)(self) + diff --git a/src/masoniteorm/models/relationships/new/BaseRelationship.py b/src/masoniteorm/models/relationships/new/BaseRelationship.py new file mode 100644 index 00000000..8a9fb2cb --- /dev/null +++ b/src/masoniteorm/models/relationships/new/BaseRelationship.py @@ -0,0 +1,10 @@ +class BaseRelationship: + def init(self, model_class, local_key=None, foreign_key=None): + self.model_class = model_class + self.local_key = local_key + self.foreign_key = foreign_key + + def __call__(self, owner): + """Create and return the relationship query.""" + related_model = self.model_class() + return self.apply_query(related_model.builder, owner) diff --git a/src/masoniteorm/models/relationships/new/HasMany.py b/src/masoniteorm/models/relationships/new/HasMany.py new file mode 100644 index 00000000..81c3d10d --- /dev/null +++ b/src/masoniteorm/models/relationships/new/HasMany.py @@ -0,0 +1,34 @@ +from .BaseRelationship import BaseRelationship + +class HasMany(BaseRelationship): + """Belongs To Relationship Class.""" + + def __init__(self, model_class, foreign_key=None, local_key=None): + self.model_class = model_class + self.foreign_key = foreign_key + self.local_key = local_key + self.owner = None + + def apply_query(self, builder): + owner = self.owner + foreign_key_value = owner.__attributes__.get(self.foreign_key) + return builder.where(self.local_key, foreign_key_value) + + + def __call__(self, owner): + """Fetch the related record when invoked.""" + related_model = self.model_class + # print("related model", related_model) + related_model.owner = self + self.owner = owner + foreign_key_value = owner.__attributes__.get(self.foreign_key) + if not foreign_key_value: + return None + # builder = related_model.builder.where(self.local_key, foreign_key_value) + builder = self.apply_query(related_model.builder) + result = builder.get() + for item in result: + item.__dict__['related'] = self + self.owner = owner + return result + diff --git a/src/masoniteorm/models/relationships/new/HasOne.py b/src/masoniteorm/models/relationships/new/HasOne.py new file mode 100644 index 00000000..c343c7b3 --- /dev/null +++ b/src/masoniteorm/models/relationships/new/HasOne.py @@ -0,0 +1,33 @@ +from .BaseRelationship import BaseRelationship +class HasOne(BaseRelationship): + """Belongs To Relationship Class.""" + + def __init__(self, model_class, foreign_key=None, local_key=None): + self.model_class = model_class + self.foreign_key = foreign_key + self.local_key = local_key + self.owner = None + + def apply_query(self, builder): + owner = self.owner + foreign_key_value = owner.__attributes__.get(self.foreign_key) + builder = builder.where(self.local_key, foreign_key_value) + return builder + + + def __call__(self, owner): + """Fetch the related record when invoked.""" + related_model = self.model_class + # print("related model", related_model) + related_model.owner = self + self.owner = owner + foreign_key_value = owner.__attributes__.get(self.foreign_key) + if not foreign_key_value: + return None + # builder = related_model.builder.where(self.local_key, foreign_key_value) + builder = self.apply_query(related_model.builder) + result = builder.first() + self.owner = owner + result.__dict__['related'] = self + return result + diff --git a/src/masoniteorm/models/relationships/new/__init__.py b/src/masoniteorm/models/relationships/new/__init__.py new file mode 100644 index 00000000..be2d8e8c --- /dev/null +++ b/src/masoniteorm/models/relationships/new/__init__.py @@ -0,0 +1,3 @@ +from .BaseRelationship import BaseRelationship +from .HasOne import HasOne +from .HasMany import HasMany \ No newline at end of file