masonite-framework-orm 3.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. masonite_framework_orm-3.0.1.dist-info/METADATA +87 -0
  2. masonite_framework_orm-3.0.1.dist-info/RECORD +116 -0
  3. masonite_framework_orm-3.0.1.dist-info/WHEEL +5 -0
  4. masonite_framework_orm-3.0.1.dist-info/entry_points.txt +3 -0
  5. masonite_framework_orm-3.0.1.dist-info/licenses/LICENSE +21 -0
  6. masonite_framework_orm-3.0.1.dist-info/top_level.txt +1 -0
  7. masoniteorm/__init__.py +1 -0
  8. masoniteorm/collection/Collection.py +605 -0
  9. masoniteorm/collection/__init__.py +1 -0
  10. masoniteorm/commands/CanOverrideConfig.py +16 -0
  11. masoniteorm/commands/CanOverrideOptionsDefault.py +22 -0
  12. masoniteorm/commands/Command.py +6 -0
  13. masoniteorm/commands/Entry.py +43 -0
  14. masoniteorm/commands/MakeMigrationCommand.py +57 -0
  15. masoniteorm/commands/MakeModelCommand.py +78 -0
  16. masoniteorm/commands/MakeModelDocstringCommand.py +37 -0
  17. masoniteorm/commands/MakeObserverCommand.py +54 -0
  18. masoniteorm/commands/MakeSeedCommand.py +54 -0
  19. masoniteorm/commands/MigrateCommand.py +46 -0
  20. masoniteorm/commands/MigrateFreshCommand.py +41 -0
  21. masoniteorm/commands/MigrateRefreshCommand.py +41 -0
  22. masoniteorm/commands/MigrateResetCommand.py +25 -0
  23. masoniteorm/commands/MigrateRollbackCommand.py +26 -0
  24. masoniteorm/commands/MigrateStatusCommand.py +51 -0
  25. masoniteorm/commands/SeedRunCommand.py +35 -0
  26. masoniteorm/commands/ShellCommand.py +205 -0
  27. masoniteorm/commands/__init__.py +18 -0
  28. masoniteorm/commands/stubs/create_migration.stub +20 -0
  29. masoniteorm/commands/stubs/create_seed.stub +9 -0
  30. masoniteorm/commands/stubs/model.stub +9 -0
  31. masoniteorm/commands/stubs/observer.stub +101 -0
  32. masoniteorm/commands/stubs/table_migration.stub +19 -0
  33. masoniteorm/config.py +123 -0
  34. masoniteorm/connections/BaseConnection.py +101 -0
  35. masoniteorm/connections/ConnectionFactory.py +59 -0
  36. masoniteorm/connections/ConnectionResolver.py +132 -0
  37. masoniteorm/connections/MSSQLConnection.py +176 -0
  38. masoniteorm/connections/MySQLConnection.py +232 -0
  39. masoniteorm/connections/PostgresConnection.py +225 -0
  40. masoniteorm/connections/SQLiteConnection.py +179 -0
  41. masoniteorm/connections/__init__.py +6 -0
  42. masoniteorm/exceptions.py +38 -0
  43. masoniteorm/expressions/__init__.py +1 -0
  44. masoniteorm/expressions/expressions.py +288 -0
  45. masoniteorm/factories/Factory.py +112 -0
  46. masoniteorm/factories/__init__.py +1 -0
  47. masoniteorm/helpers/__init__.py +0 -0
  48. masoniteorm/helpers/misc.py +22 -0
  49. masoniteorm/migrations/Migration.py +330 -0
  50. masoniteorm/migrations/__init__.py +1 -0
  51. masoniteorm/models/MigrationModel.py +9 -0
  52. masoniteorm/models/Model.py +1209 -0
  53. masoniteorm/models/Model.pyi +1366 -0
  54. masoniteorm/models/Pivot.py +5 -0
  55. masoniteorm/models/__init__.py +1 -0
  56. masoniteorm/observers/ObservesEvents.py +27 -0
  57. masoniteorm/observers/__init__.py +1 -0
  58. masoniteorm/pagination/BasePaginator.py +10 -0
  59. masoniteorm/pagination/LengthAwarePaginator.py +34 -0
  60. masoniteorm/pagination/SimplePaginator.py +28 -0
  61. masoniteorm/pagination/__init__.py +2 -0
  62. masoniteorm/providers/ORMProvider.py +39 -0
  63. masoniteorm/providers/__init__.py +1 -0
  64. masoniteorm/query/EagerRelation.py +42 -0
  65. masoniteorm/query/QueryBuilder.py +2486 -0
  66. masoniteorm/query/__init__.py +1 -0
  67. masoniteorm/query/grammars/BaseGrammar.py +1027 -0
  68. masoniteorm/query/grammars/MSSQLGrammar.py +194 -0
  69. masoniteorm/query/grammars/MySQLGrammar.py +238 -0
  70. masoniteorm/query/grammars/PostgresGrammar.py +213 -0
  71. masoniteorm/query/grammars/SQLiteGrammar.py +228 -0
  72. masoniteorm/query/grammars/__init__.py +4 -0
  73. masoniteorm/query/processors/MSSQLPostProcessor.py +58 -0
  74. masoniteorm/query/processors/MySQLPostProcessor.py +48 -0
  75. masoniteorm/query/processors/PostgresPostProcessor.py +49 -0
  76. masoniteorm/query/processors/SQLitePostProcessor.py +49 -0
  77. masoniteorm/query/processors/__init__.py +4 -0
  78. masoniteorm/relationships/BaseRelationship.py +161 -0
  79. masoniteorm/relationships/BelongsTo.py +124 -0
  80. masoniteorm/relationships/BelongsToMany.py +604 -0
  81. masoniteorm/relationships/HasMany.py +66 -0
  82. masoniteorm/relationships/HasManyThrough.py +269 -0
  83. masoniteorm/relationships/HasOne.py +111 -0
  84. masoniteorm/relationships/HasOneThrough.py +275 -0
  85. masoniteorm/relationships/MorphMany.py +152 -0
  86. masoniteorm/relationships/MorphOne.py +156 -0
  87. masoniteorm/relationships/MorphTo.py +111 -0
  88. masoniteorm/relationships/MorphToMany.py +108 -0
  89. masoniteorm/relationships/__init__.py +10 -0
  90. masoniteorm/schema/Blueprint.py +1161 -0
  91. masoniteorm/schema/Column.py +144 -0
  92. masoniteorm/schema/ColumnDiff.py +0 -0
  93. masoniteorm/schema/Constraint.py +5 -0
  94. masoniteorm/schema/ForeignKeyConstraint.py +28 -0
  95. masoniteorm/schema/Index.py +5 -0
  96. masoniteorm/schema/Schema.py +359 -0
  97. masoniteorm/schema/Table.py +94 -0
  98. masoniteorm/schema/TableDiff.py +86 -0
  99. masoniteorm/schema/__init__.py +3 -0
  100. masoniteorm/schema/platforms/MSSQLPlatform.py +367 -0
  101. masoniteorm/schema/platforms/MySQLPlatform.py +513 -0
  102. masoniteorm/schema/platforms/Platform.py +97 -0
  103. masoniteorm/schema/platforms/PostgresPlatform.py +551 -0
  104. masoniteorm/schema/platforms/SQLitePlatform.py +481 -0
  105. masoniteorm/schema/platforms/__init__.py +4 -0
  106. masoniteorm/scopes/BaseScope.py +6 -0
  107. masoniteorm/scopes/SoftDeleteScope.py +56 -0
  108. masoniteorm/scopes/SoftDeletesMixin.py +13 -0
  109. masoniteorm/scopes/TimeStampsMixin.py +12 -0
  110. masoniteorm/scopes/TimeStampsScope.py +47 -0
  111. masoniteorm/scopes/UUIDPrimaryKeyMixin.py +8 -0
  112. masoniteorm/scopes/UUIDPrimaryKeyScope.py +51 -0
  113. masoniteorm/scopes/__init__.py +8 -0
  114. masoniteorm/scopes/scope.py +15 -0
  115. masoniteorm/seeds/Seeder.py +42 -0
  116. masoniteorm/seeds/__init__.py +1 -0
@@ -0,0 +1,152 @@
1
+ from ..collection import Collection
2
+ from ..config import load_config
3
+ from .BaseRelationship import BaseRelationship
4
+
5
+
6
+ class MorphMany(BaseRelationship):
7
+ def __init__(self, fn, morph_key="record_type", morph_id="record_id"):
8
+ if isinstance(fn, str):
9
+ self.fn = None
10
+ self.morph_key = fn
11
+ self.morph_id = morph_key
12
+ else:
13
+ self.fn = fn
14
+ self.morph_id = morph_id
15
+ self.morph_key = morph_key
16
+
17
+ def get_builder(self):
18
+ return self._related_builder
19
+
20
+ def set_keys(self, owner, attribute):
21
+ self.morph_id = self.morph_id or "record_id"
22
+ self.morph_key = self.morph_key or "record_type"
23
+ return self
24
+
25
+ def __get__(self, instance, owner):
26
+ """This method is called when the decorated method is accessed.
27
+
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.
31
+
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
+ """
37
+ attribute = self.fn.__name__
38
+ self._related_builder = instance.builder
39
+ self.polymorphic_builder = self.fn(self)()
40
+ self.set_keys(owner, self.fn)
41
+
42
+ if not instance.is_loaded():
43
+ return self
44
+
45
+ if attribute in instance._relationships:
46
+ return instance._relationships[attribute]
47
+
48
+ return self.apply_query(self._related_builder, instance)
49
+
50
+ def __getattr__(self, attribute):
51
+ relationship = self.fn(self)()
52
+ return getattr(relationship.builder, attribute)
53
+
54
+ def apply_query(self, builder, instance):
55
+ """Apply the query and return a dictionary to be hydrated
56
+
57
+ Arguments:
58
+ builder {oject} -- The relationship object
59
+ instance {object} -- The current model oject.
60
+
61
+ Returns:
62
+ dict -- A dictionary of data which will be hydrated.
63
+ """
64
+ polymorphic_key = self.get_record_key_lookup(builder._model)
65
+ polymorphic_builder = self.polymorphic_builder
66
+ return (
67
+ polymorphic_builder.where(self.morph_key, polymorphic_key)
68
+ .where(self.morph_id, instance.get_primary_key_value())
69
+ .get()
70
+ )
71
+
72
+ def get_related(self, query, relation, eagers=None, callback=None):
73
+ """Gets the relation needed between the relation and the related builder. If the relation is a collection
74
+ then will need to pluck out all the keys from the collection and fetch from the related builder. If
75
+ relation is just a Model then we can just call the model based on the value of the related
76
+ builders primary key.
77
+
78
+ Args:
79
+ relation (Model|Collection):
80
+
81
+ Returns:
82
+ Model|Collection
83
+ """
84
+
85
+ if isinstance(relation, Collection):
86
+ record_type = self.get_record_key_lookup(relation.first())
87
+ if callback:
88
+ return callback(
89
+ self.polymorphic_builder.where(
90
+ f"{self.polymorphic_builder.get_table_name()}.{self.morph_key}",
91
+ record_type,
92
+ ).where_in(
93
+ self.morph_id,
94
+ relation.pluck(
95
+ relation.first().get_primary_key(),
96
+ keep_nulls=False,
97
+ ).unique(),
98
+ )
99
+ ).get()
100
+ return (
101
+ self.polymorphic_builder.where(
102
+ f"{self.polymorphic_builder.get_table_name()}.{self.morph_key}",
103
+ record_type,
104
+ )
105
+ .where_in(
106
+ self.morph_id,
107
+ relation.pluck(
108
+ relation.first().get_primary_key(), keep_nulls=False
109
+ ).unique(),
110
+ )
111
+ .get()
112
+ )
113
+
114
+ else:
115
+ record_type = self.get_record_key_lookup(relation)
116
+
117
+ if callback:
118
+ return callback(
119
+ self.polymorphic_builder.where(
120
+ self.morph_key, record_type
121
+ ).where(self.morph_id, relation.get_primary_key_value())
122
+ ).get()
123
+ return (
124
+ self.polymorphic_builder.where(self.morph_key, record_type)
125
+ .where(self.morph_id, relation.get_primary_key_value())
126
+ .get()
127
+ )
128
+
129
+ def register_related(self, key, model, collection):
130
+ record_type = self.get_record_key_lookup(model)
131
+ related = collection.where(self.morph_key, record_type).where(
132
+ self.morph_id, model.get_primary_key_value()
133
+ )
134
+
135
+ model.add_relation({key: related})
136
+
137
+ def morph_map(self):
138
+ return load_config().DB._morph_map
139
+
140
+ def get_record_key_lookup(self, relation):
141
+ record_type = None
142
+ for record_type_loop, model in self.morph_map().items():
143
+ if model == relation.__class__:
144
+ record_type = record_type_loop
145
+ break
146
+
147
+ if not record_type:
148
+ raise ValueError(
149
+ f"Could not find the record type key for the {relation} class"
150
+ )
151
+
152
+ return record_type
@@ -0,0 +1,156 @@
1
+ from ..collection import Collection
2
+ from ..config import load_config
3
+ from .BaseRelationship import BaseRelationship
4
+
5
+
6
+ class MorphOne(BaseRelationship):
7
+ def __init__(self, fn, morph_key="record_type", morph_id="record_id"):
8
+ if isinstance(fn, str):
9
+ self.fn = None
10
+ self.morph_key = fn
11
+ self.morph_id = morph_key
12
+ else:
13
+ self.fn = fn
14
+ self.morph_id = morph_id
15
+ self.morph_key = morph_key
16
+
17
+ def get_builder(self):
18
+ return self._related_builder
19
+
20
+ def set_keys(self, owner, attribute):
21
+ self.morph_id = self.morph_id or "record_id"
22
+ self.morph_key = self.morph_key or "record_type"
23
+ return self
24
+
25
+ def __get__(self, instance, owner):
26
+ """This method is called when the decorated method is accessed.
27
+
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.
31
+
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
+ """
37
+ attribute = self.fn.__name__
38
+ self._related_builder = instance.builder
39
+ self.polymorphic_builder = self.fn(self)()
40
+ self.set_keys(owner, self.fn)
41
+
42
+ if not instance.is_loaded():
43
+ return self
44
+
45
+ if attribute in instance._relationships:
46
+ return instance._relationships[attribute]
47
+
48
+ return self.apply_query(self._related_builder, instance)
49
+
50
+ def __getattr__(self, attribute):
51
+ relationship = self.fn(self)()
52
+ return getattr(relationship.builder, attribute)
53
+
54
+ def apply_query(self, builder, instance):
55
+ """Apply the query and return a dictionary to be hydrated
56
+
57
+ Arguments:
58
+ builder {oject} -- The relationship object
59
+ instance {object} -- The current model oject.
60
+
61
+ Returns:
62
+ dict -- A dictionary of data which will be hydrated.
63
+ """
64
+ polymorphic_key = self.get_record_key_lookup(builder._model)
65
+ polymorphic_builder = self.polymorphic_builder
66
+
67
+ return (
68
+ polymorphic_builder.where(self.morph_key, polymorphic_key)
69
+ .where(self.morph_id, instance.get_primary_key_value())
70
+ .first()
71
+ )
72
+
73
+ def get_related(self, query, relation, eagers=None, callback=None):
74
+ """Gets the relation needed between the relation and the related builder. If the relation is a collection
75
+ then will need to pluck out all the keys from the collection and fetch from the related builder. If
76
+ relation is just a Model then we can just call the model based on the value of the related
77
+ builders primary key.
78
+
79
+ Args:
80
+ relation (Model|Collection):
81
+
82
+ Returns:
83
+ Model|Collection
84
+ """
85
+
86
+ if isinstance(relation, Collection):
87
+ record_type = self.get_record_key_lookup(relation.first())
88
+ if callback:
89
+ return callback(
90
+ self.polymorphic_builder.where(
91
+ f"{self.polymorphic_builder.get_table_name()}.{self.morph_key}",
92
+ record_type,
93
+ ).where_in(
94
+ self.morph_id,
95
+ relation.pluck(
96
+ relation.first().get_primary_key(),
97
+ keep_nulls=False,
98
+ ).unique(),
99
+ )
100
+ ).get()
101
+
102
+ return (
103
+ self.polymorphic_builder.where(
104
+ f"{self.polymorphic_builder.get_table_name()}.{self.morph_key}",
105
+ record_type,
106
+ )
107
+ .where_in(
108
+ self.morph_id,
109
+ relation.pluck(
110
+ relation.first().get_primary_key(), keep_nulls=False
111
+ ).unique(),
112
+ )
113
+ .get()
114
+ )
115
+
116
+ else:
117
+ record_type = self.get_record_key_lookup(relation)
118
+ if callback:
119
+ return callback(
120
+ self.polymorphic_builder.where(
121
+ self.morph_key, record_type
122
+ ).where(self.morph_id, relation.get_primary_key_value())
123
+ ).first()
124
+
125
+ return (
126
+ self.polymorphic_builder.where(self.morph_key, record_type)
127
+ .where(self.morph_id, relation.get_primary_key_value())
128
+ .first()
129
+ )
130
+
131
+ def register_related(self, key, model, collection):
132
+ record_type = self.get_record_key_lookup(model)
133
+ related = (
134
+ collection.where(self.morph_key, record_type)
135
+ .where(self.morph_id, model.get_primary_key_value())
136
+ .first()
137
+ )
138
+
139
+ model.add_relation({key: related})
140
+
141
+ def morph_map(self):
142
+ return load_config().DB._morph_map
143
+
144
+ def get_record_key_lookup(self, relation):
145
+ record_type = None
146
+ for record_type_loop, model in self.morph_map().items():
147
+ if model == relation.__class__:
148
+ record_type = record_type_loop
149
+ break
150
+
151
+ if not record_type:
152
+ raise ValueError(
153
+ f"Could not find the record type key for the {relation} class"
154
+ )
155
+
156
+ return record_type
@@ -0,0 +1,111 @@
1
+ from ..collection import Collection
2
+ from ..config import load_config
3
+ from .BaseRelationship import BaseRelationship
4
+
5
+
6
+ class MorphTo(BaseRelationship):
7
+ def __init__(self, fn, morph_key="record_type", morph_id="record_id"):
8
+ if isinstance(fn, str):
9
+ self.fn = None
10
+ self.morph_key = fn
11
+ self.morph_id = morph_key
12
+ else:
13
+ self.fn = fn
14
+ self.morph_id = morph_id
15
+ self.morph_key = morph_key
16
+
17
+ def get_builder(self):
18
+ return self._related_builder
19
+
20
+ def set_keys(self, owner, attribute):
21
+ self.morph_id = self.morph_id or "record_id"
22
+ self.morph_key = self.morph_key or "record_type"
23
+ return self
24
+
25
+ def __get__(self, instance, owner):
26
+ """This method is called when the decorated method is accessed.
27
+
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.
31
+
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
+ """
37
+ attribute = self.fn.__name__
38
+ self._related_builder = instance.builder
39
+ self.set_keys(owner, self.fn)
40
+
41
+ if not instance.is_loaded():
42
+ return self
43
+
44
+ if attribute in instance._relationships:
45
+ return instance._relationships[attribute]
46
+
47
+ return self.apply_query(self._related_builder, instance)
48
+
49
+ def __getattr__(self, attribute):
50
+ relationship = self.fn(self)()
51
+ return getattr(relationship._related_builder, attribute)
52
+
53
+ def apply_query(self, builder, instance):
54
+ """Apply the query and return a dictionary to be hydrated
55
+
56
+ Arguments:
57
+ builder {oject} -- The relationship object
58
+ instance {object} -- The current model oject.
59
+
60
+ Returns:
61
+ dict -- A dictionary of data which will be hydrated.
62
+ """
63
+ model = self.morph_map().get(instance.__attributes__[self.morph_key])
64
+ record = instance.__attributes__[self.morph_id]
65
+
66
+ return model.where(model.get_primary_key(), record).first()
67
+
68
+ def get_related(self, query, relation, eagers=None, callback=None):
69
+ """Gets the relation needed between the relation and the related builder. If the relation is a collection
70
+ then will need to pluck out all the keys from the collection and fetch from the related builder. If
71
+ relation is just a Model then we can just call the model based on the value of the related
72
+ builders primary key.
73
+
74
+ Args:
75
+ relation (Model|Collection):
76
+
77
+ Returns:
78
+ Model|Collection
79
+ """
80
+ if isinstance(relation, Collection):
81
+ relations = Collection()
82
+ for group, items in relation.group_by(self.morph_key).items():
83
+ morphed_model = self.morph_map().get(group)
84
+ relations.merge(
85
+ morphed_model.where_in(
86
+ f"{morphed_model.get_table_name()}.{morphed_model.get_primary_key()}",
87
+ Collection(items)
88
+ .pluck(self.morph_id, keep_nulls=False)
89
+ .unique(),
90
+ ).get()
91
+ )
92
+ return relations
93
+ else:
94
+ model = self.morph_map().get(getattr(relation, self.morph_key))
95
+ if model:
96
+ return model.find(getattr(relation, self.morph_id))
97
+
98
+ def register_related(self, key, model, collection):
99
+ morphed_model = self.morph_map().get(getattr(model, self.morph_key))
100
+
101
+ related = collection.where(
102
+ morphed_model.get_primary_key(), getattr(model, self.morph_id)
103
+ ).first()
104
+
105
+ model.add_relation({key: related})
106
+
107
+ def morph_map(self):
108
+ return load_config().DB._morph_map
109
+
110
+ def map_related(self, related_result):
111
+ return related_result
@@ -0,0 +1,108 @@
1
+ from ..collection import Collection
2
+ from ..config import load_config
3
+ from .BaseRelationship import BaseRelationship
4
+
5
+
6
+ class MorphToMany(BaseRelationship):
7
+ def __init__(self, fn, morph_key="record_type", morph_id="record_id"):
8
+ if isinstance(fn, str):
9
+ self.fn = None
10
+ self.morph_key = fn
11
+ self.morph_id = morph_key
12
+ else:
13
+ self.fn = fn
14
+ self.morph_id = morph_id
15
+ self.morph_key = morph_key
16
+
17
+ def get_builder(self):
18
+ return self._related_builder
19
+
20
+ def set_keys(self, owner, attribute):
21
+ self.morph_id = self.morph_id or "record_id"
22
+ self.morph_key = self.morph_key or "record_type"
23
+ return self
24
+
25
+ def __get__(self, instance, owner):
26
+ """This method is called when the decorated method is accessed.
27
+
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.
31
+
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
+ """
37
+ attribute = self.fn.__name__
38
+ self._related_builder = instance.builder
39
+ self.set_keys(owner, self.fn)
40
+
41
+ if not instance.is_loaded():
42
+ return self
43
+
44
+ if attribute in instance._relationships:
45
+ return instance._relationships[attribute]
46
+
47
+ return self.apply_query(self._related_builder, instance)
48
+
49
+ def __getattr__(self, attribute):
50
+ relationship = self.fn(self)()
51
+ return getattr(relationship.builder, attribute)
52
+
53
+ def apply_query(self, builder, instance):
54
+ """Apply the query and return a dictionary to be hydrated
55
+
56
+ Arguments:
57
+ builder {oject} -- The relationship object
58
+ instance {object} -- The current model oject.
59
+
60
+ Returns:
61
+ dict -- A dictionary of data which will be hydrated.
62
+ """
63
+ model = self.morph_map().get(instance.__attributes__[self.morph_key])
64
+ record = instance.__attributes__[self.morph_id]
65
+
66
+ return model.where(model.get_primary_key(), record).first()
67
+
68
+ def get_related(self, query, relation, eagers=None, callback=None):
69
+ """Gets the relation needed between the relation and the related builder. If the relation is a collection
70
+ then will need to pluck out all the keys from the collection and fetch from the related builder. If
71
+ relation is just a Model then we can just call the model based on the value of the related
72
+ builders primary key.
73
+
74
+ Args:
75
+ relation (Model|Collection):
76
+
77
+ Returns:
78
+ Model|Collection
79
+ """
80
+ if isinstance(relation, Collection):
81
+ relations = Collection()
82
+ for group, items in relation.group_by(self.morph_key).items():
83
+ morphed_model = self.morph_map().get(group)
84
+ relations.merge(
85
+ morphed_model.where_in(
86
+ f"{morphed_model.get_table_name()}.{morphed_model.get_primary_key()}",
87
+ Collection(items)
88
+ .pluck(self.morph_id, keep_nulls=False)
89
+ .unique(),
90
+ ).get()
91
+ )
92
+ return relations
93
+ else:
94
+ model = self.morph_map().get(getattr(relation, self.morph_key))
95
+ if model:
96
+ return model.find([getattr(relation, self.morph_id)])
97
+
98
+ def register_related(self, key, model, collection):
99
+ morphed_model = self.morph_map().get(getattr(model, self.morph_key))
100
+
101
+ related = collection.where(
102
+ morphed_model.get_primary_key(), getattr(model, self.morph_id)
103
+ )
104
+
105
+ model.add_relation({key: related})
106
+
107
+ def morph_map(self):
108
+ return load_config().DB._morph_map
@@ -0,0 +1,10 @@
1
+ from .BelongsTo import BelongsTo as belongs_to
2
+ from .BelongsToMany import BelongsToMany as belongs_to_many
3
+ from .HasMany import HasMany as has_many
4
+ from .HasManyThrough import HasManyThrough as has_many_through
5
+ from .HasOne import HasOne as has_one
6
+ from .HasOneThrough import HasOneThrough as has_one_through
7
+ from .MorphMany import MorphMany as morph_many
8
+ from .MorphOne import MorphOne as morph_one
9
+ from .MorphTo import MorphTo as morph_to
10
+ from .MorphToMany import MorphToMany as morph_to_many