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.
- masonite_framework_orm-3.0.1.dist-info/METADATA +87 -0
- masonite_framework_orm-3.0.1.dist-info/RECORD +116 -0
- masonite_framework_orm-3.0.1.dist-info/WHEEL +5 -0
- masonite_framework_orm-3.0.1.dist-info/entry_points.txt +3 -0
- masonite_framework_orm-3.0.1.dist-info/licenses/LICENSE +21 -0
- masonite_framework_orm-3.0.1.dist-info/top_level.txt +1 -0
- masoniteorm/__init__.py +1 -0
- masoniteorm/collection/Collection.py +605 -0
- masoniteorm/collection/__init__.py +1 -0
- masoniteorm/commands/CanOverrideConfig.py +16 -0
- masoniteorm/commands/CanOverrideOptionsDefault.py +22 -0
- masoniteorm/commands/Command.py +6 -0
- masoniteorm/commands/Entry.py +43 -0
- masoniteorm/commands/MakeMigrationCommand.py +57 -0
- masoniteorm/commands/MakeModelCommand.py +78 -0
- masoniteorm/commands/MakeModelDocstringCommand.py +37 -0
- masoniteorm/commands/MakeObserverCommand.py +54 -0
- masoniteorm/commands/MakeSeedCommand.py +54 -0
- masoniteorm/commands/MigrateCommand.py +46 -0
- masoniteorm/commands/MigrateFreshCommand.py +41 -0
- masoniteorm/commands/MigrateRefreshCommand.py +41 -0
- masoniteorm/commands/MigrateResetCommand.py +25 -0
- masoniteorm/commands/MigrateRollbackCommand.py +26 -0
- masoniteorm/commands/MigrateStatusCommand.py +51 -0
- masoniteorm/commands/SeedRunCommand.py +35 -0
- masoniteorm/commands/ShellCommand.py +205 -0
- masoniteorm/commands/__init__.py +18 -0
- masoniteorm/commands/stubs/create_migration.stub +20 -0
- masoniteorm/commands/stubs/create_seed.stub +9 -0
- masoniteorm/commands/stubs/model.stub +9 -0
- masoniteorm/commands/stubs/observer.stub +101 -0
- masoniteorm/commands/stubs/table_migration.stub +19 -0
- masoniteorm/config.py +123 -0
- masoniteorm/connections/BaseConnection.py +101 -0
- masoniteorm/connections/ConnectionFactory.py +59 -0
- masoniteorm/connections/ConnectionResolver.py +132 -0
- masoniteorm/connections/MSSQLConnection.py +176 -0
- masoniteorm/connections/MySQLConnection.py +232 -0
- masoniteorm/connections/PostgresConnection.py +225 -0
- masoniteorm/connections/SQLiteConnection.py +179 -0
- masoniteorm/connections/__init__.py +6 -0
- masoniteorm/exceptions.py +38 -0
- masoniteorm/expressions/__init__.py +1 -0
- masoniteorm/expressions/expressions.py +288 -0
- masoniteorm/factories/Factory.py +112 -0
- masoniteorm/factories/__init__.py +1 -0
- masoniteorm/helpers/__init__.py +0 -0
- masoniteorm/helpers/misc.py +22 -0
- masoniteorm/migrations/Migration.py +330 -0
- masoniteorm/migrations/__init__.py +1 -0
- masoniteorm/models/MigrationModel.py +9 -0
- masoniteorm/models/Model.py +1209 -0
- masoniteorm/models/Model.pyi +1366 -0
- masoniteorm/models/Pivot.py +5 -0
- masoniteorm/models/__init__.py +1 -0
- masoniteorm/observers/ObservesEvents.py +27 -0
- masoniteorm/observers/__init__.py +1 -0
- masoniteorm/pagination/BasePaginator.py +10 -0
- masoniteorm/pagination/LengthAwarePaginator.py +34 -0
- masoniteorm/pagination/SimplePaginator.py +28 -0
- masoniteorm/pagination/__init__.py +2 -0
- masoniteorm/providers/ORMProvider.py +39 -0
- masoniteorm/providers/__init__.py +1 -0
- masoniteorm/query/EagerRelation.py +42 -0
- masoniteorm/query/QueryBuilder.py +2486 -0
- masoniteorm/query/__init__.py +1 -0
- masoniteorm/query/grammars/BaseGrammar.py +1027 -0
- masoniteorm/query/grammars/MSSQLGrammar.py +194 -0
- masoniteorm/query/grammars/MySQLGrammar.py +238 -0
- masoniteorm/query/grammars/PostgresGrammar.py +213 -0
- masoniteorm/query/grammars/SQLiteGrammar.py +228 -0
- masoniteorm/query/grammars/__init__.py +4 -0
- masoniteorm/query/processors/MSSQLPostProcessor.py +58 -0
- masoniteorm/query/processors/MySQLPostProcessor.py +48 -0
- masoniteorm/query/processors/PostgresPostProcessor.py +49 -0
- masoniteorm/query/processors/SQLitePostProcessor.py +49 -0
- masoniteorm/query/processors/__init__.py +4 -0
- masoniteorm/relationships/BaseRelationship.py +161 -0
- masoniteorm/relationships/BelongsTo.py +124 -0
- masoniteorm/relationships/BelongsToMany.py +604 -0
- masoniteorm/relationships/HasMany.py +66 -0
- masoniteorm/relationships/HasManyThrough.py +269 -0
- masoniteorm/relationships/HasOne.py +111 -0
- masoniteorm/relationships/HasOneThrough.py +275 -0
- masoniteorm/relationships/MorphMany.py +152 -0
- masoniteorm/relationships/MorphOne.py +156 -0
- masoniteorm/relationships/MorphTo.py +111 -0
- masoniteorm/relationships/MorphToMany.py +108 -0
- masoniteorm/relationships/__init__.py +10 -0
- masoniteorm/schema/Blueprint.py +1161 -0
- masoniteorm/schema/Column.py +144 -0
- masoniteorm/schema/ColumnDiff.py +0 -0
- masoniteorm/schema/Constraint.py +5 -0
- masoniteorm/schema/ForeignKeyConstraint.py +28 -0
- masoniteorm/schema/Index.py +5 -0
- masoniteorm/schema/Schema.py +359 -0
- masoniteorm/schema/Table.py +94 -0
- masoniteorm/schema/TableDiff.py +86 -0
- masoniteorm/schema/__init__.py +3 -0
- masoniteorm/schema/platforms/MSSQLPlatform.py +367 -0
- masoniteorm/schema/platforms/MySQLPlatform.py +513 -0
- masoniteorm/schema/platforms/Platform.py +97 -0
- masoniteorm/schema/platforms/PostgresPlatform.py +551 -0
- masoniteorm/schema/platforms/SQLitePlatform.py +481 -0
- masoniteorm/schema/platforms/__init__.py +4 -0
- masoniteorm/scopes/BaseScope.py +6 -0
- masoniteorm/scopes/SoftDeleteScope.py +56 -0
- masoniteorm/scopes/SoftDeletesMixin.py +13 -0
- masoniteorm/scopes/TimeStampsMixin.py +12 -0
- masoniteorm/scopes/TimeStampsScope.py +47 -0
- masoniteorm/scopes/UUIDPrimaryKeyMixin.py +8 -0
- masoniteorm/scopes/UUIDPrimaryKeyScope.py +51 -0
- masoniteorm/scopes/__init__.py +8 -0
- masoniteorm/scopes/scope.py +15 -0
- masoniteorm/seeds/Seeder.py +42 -0
- masoniteorm/seeds/__init__.py +1 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from .BaseGrammar import BaseGrammar
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SQLiteGrammar(BaseGrammar):
|
|
7
|
+
"""SQLite grammar class."""
|
|
8
|
+
|
|
9
|
+
aggregate_options = {
|
|
10
|
+
"SUM": "SUM",
|
|
11
|
+
"MAX": "MAX",
|
|
12
|
+
"MIN": "MIN",
|
|
13
|
+
"AVG": "AVG",
|
|
14
|
+
"COUNT": "COUNT",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
join_keywords = {
|
|
18
|
+
"inner": "INNER JOIN",
|
|
19
|
+
"join": "INNER JOIN",
|
|
20
|
+
"outer": "OUTER JOIN",
|
|
21
|
+
"left": "LEFT JOIN",
|
|
22
|
+
"right": "LEFT JOIN",
|
|
23
|
+
"left_inner": "LEFT INNER JOIN",
|
|
24
|
+
"right_inner": "LEFT INNER JOIN",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
column_strings = {
|
|
28
|
+
"select": '{table}."{column}"{alias}{separator}',
|
|
29
|
+
"select_all": "{table}.*{separator}",
|
|
30
|
+
"insert": '"{column}"{separator}',
|
|
31
|
+
"update": '"{column}"{separator}',
|
|
32
|
+
"delete": '"{column}"{separator}',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
locks = {"share": "", "update": ""}
|
|
36
|
+
|
|
37
|
+
def select_format(self):
|
|
38
|
+
return "SELECT {keyword} {columns} FROM {table} {joins} {wheres} {group_by} {having} {order_by} {limit} {offset} {lock}"
|
|
39
|
+
|
|
40
|
+
def select_no_table(self):
|
|
41
|
+
return "SELECT {columns} {lock}"
|
|
42
|
+
|
|
43
|
+
def update_format(self):
|
|
44
|
+
return "UPDATE {table} SET {key_equals} {wheres}"
|
|
45
|
+
|
|
46
|
+
def insert_format(self):
|
|
47
|
+
return "INSERT INTO {table} ({columns}) VALUES ({values})"
|
|
48
|
+
|
|
49
|
+
def bulk_insert_format(self):
|
|
50
|
+
return "INSERT INTO {table} ({columns}) VALUES {values}"
|
|
51
|
+
|
|
52
|
+
def delete_format(self):
|
|
53
|
+
return "DELETE FROM {table} {wheres}"
|
|
54
|
+
|
|
55
|
+
def aggregate_string_with_alias(self):
|
|
56
|
+
return "{aggregate_function}({column}) AS {alias}"
|
|
57
|
+
|
|
58
|
+
def aggregate_string_without_alias(self):
|
|
59
|
+
return "{aggregate_function}({column})"
|
|
60
|
+
|
|
61
|
+
def subquery_string(self):
|
|
62
|
+
return "({query})"
|
|
63
|
+
|
|
64
|
+
def default_string(self):
|
|
65
|
+
return " DEFAULT {default} "
|
|
66
|
+
|
|
67
|
+
def raw_query_string(self):
|
|
68
|
+
return "{keyword} {query}"
|
|
69
|
+
|
|
70
|
+
def where_group_string(self):
|
|
71
|
+
return "{keyword} {value}"
|
|
72
|
+
|
|
73
|
+
def between_string(self):
|
|
74
|
+
return "{keyword} {column} BETWEEN {low} AND {high}"
|
|
75
|
+
|
|
76
|
+
def not_between_string(self):
|
|
77
|
+
return "{keyword} {column} NOT BETWEEN {low} AND {high}"
|
|
78
|
+
|
|
79
|
+
def where_exists_string(self):
|
|
80
|
+
return "{keyword} EXISTS {value}"
|
|
81
|
+
|
|
82
|
+
def where_not_exists_string(self):
|
|
83
|
+
return "{keyword} NOT EXISTS {value}"
|
|
84
|
+
|
|
85
|
+
def where_like_string(self):
|
|
86
|
+
return "{keyword} {column} LIKE {value}"
|
|
87
|
+
|
|
88
|
+
def where_not_like_string(self):
|
|
89
|
+
return "{keyword} {column} NOT LIKE {value}"
|
|
90
|
+
|
|
91
|
+
def subquery_alias_string(self):
|
|
92
|
+
return "AS {alias}"
|
|
93
|
+
|
|
94
|
+
def key_value_string(self):
|
|
95
|
+
return "{column} = {value}{separator}"
|
|
96
|
+
|
|
97
|
+
def column_value_string(self):
|
|
98
|
+
return "{column} = {value}{separator}"
|
|
99
|
+
|
|
100
|
+
def increment_string(self):
|
|
101
|
+
return "{column} = {column} + {value}"
|
|
102
|
+
|
|
103
|
+
def decrement_string(self):
|
|
104
|
+
return "{column} = {column} - {value}"
|
|
105
|
+
|
|
106
|
+
def column_exists_string(self):
|
|
107
|
+
return "SELECT column_name FROM information_schema.columns WHERE table_name='{clean_table}' and column_name={value}"
|
|
108
|
+
|
|
109
|
+
def table_exists_string(self):
|
|
110
|
+
return "SELECT name FROM sqlite_master WHERE type='table' AND name='{clean_table}'"
|
|
111
|
+
|
|
112
|
+
def to_sql(self):
|
|
113
|
+
"""Cleans up the SQL string and returns the SQL
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
string
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
if self.queries and (not self._columns and not self._creates):
|
|
120
|
+
sql = ""
|
|
121
|
+
for query in self.queries:
|
|
122
|
+
query += "; "
|
|
123
|
+
sql += re.sub(" +", " ", query)
|
|
124
|
+
return sql.rstrip(" ")
|
|
125
|
+
else:
|
|
126
|
+
sql = re.sub(" +", " ", self._sql.strip().replace(",)", ")"))
|
|
127
|
+
for query in self.queries:
|
|
128
|
+
sql += "; "
|
|
129
|
+
sql += re.sub(" +", " ", query.strip())
|
|
130
|
+
|
|
131
|
+
return sql
|
|
132
|
+
|
|
133
|
+
def table_string(self):
|
|
134
|
+
return '"{table}"'
|
|
135
|
+
|
|
136
|
+
def order_by_format(self):
|
|
137
|
+
return "{column} {direction}"
|
|
138
|
+
|
|
139
|
+
def order_by_string(self):
|
|
140
|
+
return "ORDER BY {order_columns}"
|
|
141
|
+
|
|
142
|
+
def column_string(self):
|
|
143
|
+
return '"{column}"{separator}'
|
|
144
|
+
|
|
145
|
+
def value_string(self):
|
|
146
|
+
return "'{value}'{separator}"
|
|
147
|
+
|
|
148
|
+
def join_string(self):
|
|
149
|
+
return "{keyword} {foreign_table}{alias} {on}"
|
|
150
|
+
|
|
151
|
+
def limit_string(self, offset=False):
|
|
152
|
+
if offset:
|
|
153
|
+
return ""
|
|
154
|
+
return "LIMIT {limit}"
|
|
155
|
+
|
|
156
|
+
def offset_string(self):
|
|
157
|
+
return "LIMIT {limit} OFFSET {offset}"
|
|
158
|
+
|
|
159
|
+
def first_where_string(self):
|
|
160
|
+
return "WHERE"
|
|
161
|
+
|
|
162
|
+
def additional_where_string(self):
|
|
163
|
+
return "AND"
|
|
164
|
+
|
|
165
|
+
def or_where_string(self):
|
|
166
|
+
return "OR"
|
|
167
|
+
|
|
168
|
+
def where_in_string(self):
|
|
169
|
+
return "WHERE IN ({values})"
|
|
170
|
+
|
|
171
|
+
def where_string(self):
|
|
172
|
+
return " {keyword} {column} {equality} {value}"
|
|
173
|
+
|
|
174
|
+
def having_string(self):
|
|
175
|
+
return "HAVING {column}"
|
|
176
|
+
|
|
177
|
+
def having_equality_string(self):
|
|
178
|
+
return "HAVING {column} {equality} {value}"
|
|
179
|
+
|
|
180
|
+
def where_null_string(self):
|
|
181
|
+
return " {keyword} {column} IS NULL"
|
|
182
|
+
|
|
183
|
+
def where_date_string(self):
|
|
184
|
+
return "{keyword} DATE({column}) {equality} {value}"
|
|
185
|
+
|
|
186
|
+
def value_equal_string(self):
|
|
187
|
+
return "{keyword} {value1} = {value2}"
|
|
188
|
+
|
|
189
|
+
def where_not_null_string(self):
|
|
190
|
+
return " {keyword} {column} IS NOT NULL"
|
|
191
|
+
|
|
192
|
+
def enable_foreign_key_constraints(self):
|
|
193
|
+
return "PRAGMA foreign_keys = ON"
|
|
194
|
+
|
|
195
|
+
def disable_foreign_key_constraints(self):
|
|
196
|
+
return "PRAGMA foreign_keys = OFF"
|
|
197
|
+
|
|
198
|
+
def get_true_column_string(self):
|
|
199
|
+
return "{keyword} {column} = '1'"
|
|
200
|
+
|
|
201
|
+
def get_false_column_string(self):
|
|
202
|
+
return "{keyword} {column} = '0'"
|
|
203
|
+
|
|
204
|
+
def truncate_table(self, table, foreign_keys=False):
|
|
205
|
+
# SQLite do not have TRUNCATE TABLE command but we can
|
|
206
|
+
# use SQLite DELETE command to delete complete data from an existing table
|
|
207
|
+
if not foreign_keys:
|
|
208
|
+
return f"DELETE FROM {self.wrap_table(table)}"
|
|
209
|
+
|
|
210
|
+
return [
|
|
211
|
+
self.disable_foreign_key_constraints(),
|
|
212
|
+
f"DELETE FROM {self.wrap_table(table)}",
|
|
213
|
+
self.enable_foreign_key_constraints(),
|
|
214
|
+
]
|
|
215
|
+
|
|
216
|
+
def compile_random(self):
|
|
217
|
+
return "random()"
|
|
218
|
+
|
|
219
|
+
def process_offset(self):
|
|
220
|
+
"""Compiles the offset expression.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
self
|
|
224
|
+
"""
|
|
225
|
+
if not self._limit:
|
|
226
|
+
self._limit = int(-1)
|
|
227
|
+
|
|
228
|
+
return super().process_offset()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
class MSSQLPostProcessor:
|
|
2
|
+
"""Post processor classes are responsable for modifying the result after a query.
|
|
3
|
+
|
|
4
|
+
Post Processors are called after the connection calls the database in the
|
|
5
|
+
Query Builder but before the result is returned in that builder method.
|
|
6
|
+
|
|
7
|
+
We can use this oppurtunity to get things like the inserted ID.
|
|
8
|
+
|
|
9
|
+
For the Postgres Post Processor we have a RETURNING * string in the insert so the result
|
|
10
|
+
will already have the full inserted record in the results. Therefore, we can just return
|
|
11
|
+
the results
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def process_insert_get_id(self, builder, results, id_key):
|
|
15
|
+
"""Process the results from the query to the database.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
19
|
+
results (dict): The result from an insert query or the creates from the query builder.
|
|
20
|
+
This is usually a dictionary.
|
|
21
|
+
id_key (string): The key to set the primary key to. This is usually the primary key of the table.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
dictionary: Should return the modified dictionary.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
last_id = builder.new_connection().query(
|
|
28
|
+
"SELECT @@Identity as [id]", results=1
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
id = last_id["id"]
|
|
32
|
+
|
|
33
|
+
if str(id).isdigit():
|
|
34
|
+
id = int(id)
|
|
35
|
+
else:
|
|
36
|
+
id = str(id)
|
|
37
|
+
|
|
38
|
+
results.update({id_key: id})
|
|
39
|
+
return results
|
|
40
|
+
|
|
41
|
+
def get_column_value(self, builder, column, results, id_key, id_value):
|
|
42
|
+
"""Gets the specific column value from a table. Typically done after an update to
|
|
43
|
+
refetch the new value of a field.
|
|
44
|
+
|
|
45
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
46
|
+
column (string): The column to refetch the value for.
|
|
47
|
+
results (dict): The result from an update query from the query builder.
|
|
48
|
+
This is usually a dictionary.
|
|
49
|
+
id_key (string): The key to fetch the primary key for. This is usually the primary key of the table.
|
|
50
|
+
id_value (string): The value of the primary key to fetch
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
new_builder = builder.select(column)
|
|
54
|
+
if id_key and id_value:
|
|
55
|
+
new_builder.where(id_key, id_value)
|
|
56
|
+
return new_builder.first()[column]
|
|
57
|
+
|
|
58
|
+
return {}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class MySQLPostProcessor:
|
|
2
|
+
"""Post processor classes are responsable for modifying the result after a query.
|
|
3
|
+
|
|
4
|
+
Post Processors are called after the connection calls the database in the
|
|
5
|
+
Query Builder but before the result is returned in that builder method.
|
|
6
|
+
|
|
7
|
+
We can use this oppurtunity to get things like the inserted ID.
|
|
8
|
+
|
|
9
|
+
For the SQLite Post Processor we have an attribute on the connection class we can use to fetch the ID.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def process_insert_get_id(self, builder, results, id_key):
|
|
13
|
+
"""Process the results from the query to the database.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
17
|
+
results (dict): The result from an insert query or the creates from the query builder.
|
|
18
|
+
This is usually a dictionary.
|
|
19
|
+
id_key (string): The key to set the primary key to. This is usually the primary key of the table.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
dictionary: Should return the modified dictionary.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
if id_key not in results:
|
|
26
|
+
results.update(
|
|
27
|
+
{id_key: builder._connection.get_cursor().lastrowid}
|
|
28
|
+
)
|
|
29
|
+
return results
|
|
30
|
+
|
|
31
|
+
def get_column_value(self, builder, column, results, id_key, id_value):
|
|
32
|
+
"""Gets the specific column value from a table. Typically done after an update to
|
|
33
|
+
refetch the new value of a field.
|
|
34
|
+
|
|
35
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
36
|
+
column (string): The column to refetch the value for.
|
|
37
|
+
results (dict): The result from an update query from the query builder.
|
|
38
|
+
This is usually a dictionary.
|
|
39
|
+
id_key (string): The key to fetch the primary key for. This is usually the primary key of the table.
|
|
40
|
+
id_value (string): The value of the primary key to fetch
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
new_builder = builder.select(column)
|
|
44
|
+
if id_key and id_value:
|
|
45
|
+
new_builder.where(id_key, id_value)
|
|
46
|
+
return new_builder.first()[column]
|
|
47
|
+
|
|
48
|
+
return {}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class PostgresPostProcessor:
|
|
2
|
+
"""Post processor classes are responsable for modifying the result after a query.
|
|
3
|
+
|
|
4
|
+
Post Processors are called after the connection calls the database in the
|
|
5
|
+
Query Builder but before the result is returned in that builder method.
|
|
6
|
+
|
|
7
|
+
We can use this oppurtunity to get things like the inserted ID.
|
|
8
|
+
|
|
9
|
+
For the Postgres Post Processor we have a RETURNING * string in the insert so the result
|
|
10
|
+
will already have the full inserted record in the results. Therefore, we can just return
|
|
11
|
+
the results
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def process_insert_get_id(self, builder, results, id_key):
|
|
15
|
+
"""Process the results from the query to the database.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
19
|
+
results (dict): The result from an insert query or the creates from the query builder.
|
|
20
|
+
This is usually a dictionary.
|
|
21
|
+
id_key (string): The key to set the primary key to. This is usually the primary key of the table.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
dictionary: Should return the modified dictionary.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
return results
|
|
28
|
+
|
|
29
|
+
def get_column_value(self, builder, column, results, id_key, id_value):
|
|
30
|
+
"""Gets the specific column value from a table. Typically done after an update to
|
|
31
|
+
refetch the new value of a field.
|
|
32
|
+
|
|
33
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
34
|
+
column (string): The column to refetch the value for.
|
|
35
|
+
results (dict): The result from an update query from the query builder.
|
|
36
|
+
This is usually a dictionary.
|
|
37
|
+
id_key (string): The key to fetch the primary key for. This is usually the primary key of the table.
|
|
38
|
+
id_value (string): The value of the primary key to fetch
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
if column in results:
|
|
42
|
+
return results[column]
|
|
43
|
+
|
|
44
|
+
new_builder = builder.select(column)
|
|
45
|
+
if id_key and id_value:
|
|
46
|
+
new_builder.where(id_key, id_value)
|
|
47
|
+
return new_builder.first()[column]
|
|
48
|
+
|
|
49
|
+
return {}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class SQLitePostProcessor:
|
|
2
|
+
"""Post processor classes are responsable for modifying the result after a query.
|
|
3
|
+
|
|
4
|
+
Post Processors are called after the connection calls the database in the
|
|
5
|
+
Query Builder but before the result is returned in that builder method.
|
|
6
|
+
|
|
7
|
+
We can use this oppurtunity to get things like the inserted ID.
|
|
8
|
+
|
|
9
|
+
For the SQLite Post Processor we have an attribute on the connection class we can use to fetch the ID.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def process_insert_get_id(self, builder, results, id_key="id"):
|
|
13
|
+
"""Process the results from the query to the database.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
17
|
+
results (dict): The result from an insert query or the creates from the query builder.
|
|
18
|
+
This is usually a dictionary.
|
|
19
|
+
id_key (string): The key to set the primary key to. This is usually the primary key of the table.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
dictionary: Should return the modified dictionary.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
if id_key not in results:
|
|
26
|
+
results.update(
|
|
27
|
+
{id_key: builder.get_connection().get_cursor().lastrowid}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return results
|
|
31
|
+
|
|
32
|
+
def get_column_value(self, builder, column, results, id_key, id_value):
|
|
33
|
+
"""Gets the specific column value from a table. Typically done after an update to
|
|
34
|
+
refetch the new value of a field.
|
|
35
|
+
|
|
36
|
+
builder (masoniteorm.builder.QueryBuilder): The query builder class
|
|
37
|
+
column (string): The column to refetch the value for.
|
|
38
|
+
results (dict): The result from an update query from the query builder.
|
|
39
|
+
This is usually a dictionary.
|
|
40
|
+
id_key (string): The key to fetch the primary key for. This is usually the primary key of the table.
|
|
41
|
+
id_value (string): The value of the primary key to fetch
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
new_builder = builder.select(column)
|
|
45
|
+
if id_key and id_value:
|
|
46
|
+
new_builder.where(id_key, id_value)
|
|
47
|
+
return new_builder.first()[column]
|
|
48
|
+
|
|
49
|
+
return {}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
class BaseRelationship:
|
|
2
|
+
def __init__(self, fn, local_key=None, foreign_key=None):
|
|
3
|
+
if isinstance(fn, str):
|
|
4
|
+
self.fn = None
|
|
5
|
+
self.local_key = fn
|
|
6
|
+
self.foreign_key = local_key
|
|
7
|
+
else:
|
|
8
|
+
self.fn = fn
|
|
9
|
+
self.local_key = local_key
|
|
10
|
+
self.foreign_key = foreign_key
|
|
11
|
+
|
|
12
|
+
def __set_name__(self, cls, name):
|
|
13
|
+
"""This method is called right after the decorator is registered.
|
|
14
|
+
|
|
15
|
+
At this point we finally have access to the model cls
|
|
16
|
+
|
|
17
|
+
Arguments:
|
|
18
|
+
name {object} -- The model class.
|
|
19
|
+
"""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
def __call__(self, fn=None, *args, **kwargs):
|
|
23
|
+
"""This method is called when the decorator contains arguments.
|
|
24
|
+
|
|
25
|
+
When you do something like this:
|
|
26
|
+
|
|
27
|
+
@belongs_to('id', 'user_id').
|
|
28
|
+
|
|
29
|
+
In this case, the {fn} argument will be the callable.
|
|
30
|
+
"""
|
|
31
|
+
if callable(fn):
|
|
32
|
+
self.fn = fn
|
|
33
|
+
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def get_builder(self):
|
|
37
|
+
return self._related_builder
|
|
38
|
+
|
|
39
|
+
def __get__(self, instance, owner):
|
|
40
|
+
"""
|
|
41
|
+
This method is called when the decorated method is accessed.
|
|
42
|
+
|
|
43
|
+
Arguments:
|
|
44
|
+
instance {object|None} -- The instance we called.
|
|
45
|
+
If we didn't call the attribute and only accessed it then this will be None.
|
|
46
|
+
|
|
47
|
+
owner {object} -- The current model that the property was accessed on.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
object -- Either returns a builder or a hydrated model.
|
|
51
|
+
"""
|
|
52
|
+
attribute = self.fn.__name__
|
|
53
|
+
relationship = self.fn(instance)()
|
|
54
|
+
self.set_keys(instance, attribute)
|
|
55
|
+
self._related_builder = relationship.builder
|
|
56
|
+
|
|
57
|
+
if not instance.is_loaded():
|
|
58
|
+
return self
|
|
59
|
+
|
|
60
|
+
if attribute in instance._relationships:
|
|
61
|
+
return instance._relationships[attribute]
|
|
62
|
+
|
|
63
|
+
return self.apply_query(self._related_builder, instance)
|
|
64
|
+
|
|
65
|
+
def __getattr__(self, attribute):
|
|
66
|
+
relationship = self.fn(self)()
|
|
67
|
+
return getattr(relationship.builder, attribute)
|
|
68
|
+
|
|
69
|
+
def apply_query(self, foreign, owner):
|
|
70
|
+
"""Return a dictionary to hydrate the model with
|
|
71
|
+
|
|
72
|
+
Arguments:
|
|
73
|
+
foreign {oject} -- The relationship object
|
|
74
|
+
owner {object} -- The current model oject.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
dict -- A dictionary of data which will be hydrated.
|
|
78
|
+
"""
|
|
79
|
+
klass = self.__class__.__name__
|
|
80
|
+
raise NotImplementedError(
|
|
81
|
+
f"{klass} relationship does not implement the 'apply_query' method"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
def query_where_exists(self, builder, callback, method="where_exists"):
|
|
85
|
+
"""Adds a criteria clause to the query filter for existing related records"""
|
|
86
|
+
klass = self.__class__.__name__
|
|
87
|
+
raise NotImplementedError(
|
|
88
|
+
f"{klass} relationship does not implement the 'query_where_exists' method"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def joins(self, builder, clause=None):
|
|
92
|
+
"""Helper method for adding join clauses to a relationship"""
|
|
93
|
+
other_table = self.get_builder().get_table_name()
|
|
94
|
+
local_table = builder.get_table_name()
|
|
95
|
+
return builder.join(
|
|
96
|
+
other_table,
|
|
97
|
+
f"{local_table}.{self.local_key}",
|
|
98
|
+
"=",
|
|
99
|
+
f"{other_table}.{self.foreign_key}",
|
|
100
|
+
clause=clause,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def get_with_count_query(self, builder, callback):
|
|
104
|
+
"""Adds a clause to the query to get the record count of the relationship"""
|
|
105
|
+
klass = self.__class__.__name__
|
|
106
|
+
raise NotImplementedError(
|
|
107
|
+
f"{klass} relationship does not implement the 'get_with_count_query' method"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def attach(self, current_model, related_record):
|
|
111
|
+
"""Link a related model to the current model"""
|
|
112
|
+
klass = self.__class__.__name__
|
|
113
|
+
raise NotImplementedError(
|
|
114
|
+
f"{klass} relationship does not implement the 'attach' method"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def get_related(self, query, relation, eagers=None, callback=None):
|
|
118
|
+
klass = self.__class__.__name__
|
|
119
|
+
raise NotImplementedError(
|
|
120
|
+
f"{klass} relationship does not implement the 'get_related' method"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def relate(self, related_record):
|
|
124
|
+
klass = self.__class__.__name__
|
|
125
|
+
raise NotImplementedError(
|
|
126
|
+
f"{klass} relationship does not implement the 'relate' method"
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def detach(self, current_model, related_record):
|
|
130
|
+
"""Unlink a related model from the current model"""
|
|
131
|
+
klass = self.__class__.__name__
|
|
132
|
+
raise NotImplementedError(
|
|
133
|
+
f"{klass} relationship does not implement the 'detach' method"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
def attach_related(self, current_model, related_record):
|
|
137
|
+
"""Unlink a related model from the current model"""
|
|
138
|
+
klass = self.__class__.__name__
|
|
139
|
+
raise NotImplementedError(
|
|
140
|
+
f"{klass} relationship does not implement the 'attach_related' method"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def detach_related(self, current_model, related_record):
|
|
144
|
+
"""Unlink a related model from the current model"""
|
|
145
|
+
klass = self.__class__.__name__
|
|
146
|
+
raise NotImplementedError(
|
|
147
|
+
f"{klass} relationship does not implement the 'detach_related' method"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def query_has(self, current_query_builder, method="where_exists"):
|
|
151
|
+
"""Adds a clause to the query to chek if a rwlarion exists"""
|
|
152
|
+
klass = self.__class__.__name__
|
|
153
|
+
raise NotImplementedError(
|
|
154
|
+
f"{klass} relationship does not implement the 'query_has' method"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def map_related(self, related_result):
|
|
158
|
+
klass = self.__class__.__name__
|
|
159
|
+
raise NotImplementedError(
|
|
160
|
+
f"{klass} relationship does not implement the 'related_result' method"
|
|
161
|
+
)
|