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,132 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConnectionResolver:
|
|
5
|
+
_connections = {}
|
|
6
|
+
_morph_map = {}
|
|
7
|
+
|
|
8
|
+
def __init__(self, config_path=None, connection_details=None):
|
|
9
|
+
from ..connections import (
|
|
10
|
+
ConnectionFactory,
|
|
11
|
+
MSSQLConnection,
|
|
12
|
+
MySQLConnection,
|
|
13
|
+
PostgresConnection,
|
|
14
|
+
SQLiteConnection,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
self.config_path = config_path
|
|
18
|
+
self._connection_details = connection_details or {}
|
|
19
|
+
|
|
20
|
+
self.connection_factory = ConnectionFactory(
|
|
21
|
+
config_path=config_path, resolver=self
|
|
22
|
+
)
|
|
23
|
+
self.register(SQLiteConnection)
|
|
24
|
+
self.register(PostgresConnection)
|
|
25
|
+
self.register(MySQLConnection)
|
|
26
|
+
self.register(MSSQLConnection)
|
|
27
|
+
|
|
28
|
+
def morph_map(self, map):
|
|
29
|
+
self._morph_map = map
|
|
30
|
+
return self
|
|
31
|
+
|
|
32
|
+
def set_connection_details(self, connection_details):
|
|
33
|
+
self._connection_details = connection_details
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
def get_connection_details(self):
|
|
37
|
+
return self._connection_details
|
|
38
|
+
|
|
39
|
+
def set_connection_option(self, connection: str, options: dict):
|
|
40
|
+
self._connection_details.get(connection).update(options)
|
|
41
|
+
return self
|
|
42
|
+
|
|
43
|
+
def get_global_connections(self):
|
|
44
|
+
return self._connections
|
|
45
|
+
|
|
46
|
+
def remove_global_connection(self, name=None):
|
|
47
|
+
self._connections.pop(name)
|
|
48
|
+
|
|
49
|
+
def register(self, connection):
|
|
50
|
+
self.connection_factory.register(connection.name, connection)
|
|
51
|
+
|
|
52
|
+
def begin_transaction(self, name=None):
|
|
53
|
+
if name is None:
|
|
54
|
+
name = self.get_connection_details()["default"]
|
|
55
|
+
|
|
56
|
+
driver = self.get_connection_details()[name].get("driver")
|
|
57
|
+
|
|
58
|
+
connection = (
|
|
59
|
+
self.connection_factory.make(driver)(
|
|
60
|
+
**self.get_connection_information(name)
|
|
61
|
+
)
|
|
62
|
+
.make_connection()
|
|
63
|
+
.begin()
|
|
64
|
+
)
|
|
65
|
+
self.__class__._connections.update({name: connection})
|
|
66
|
+
|
|
67
|
+
return connection
|
|
68
|
+
|
|
69
|
+
def commit(self, name=None):
|
|
70
|
+
if name is None:
|
|
71
|
+
name = self.get_connection_details()["default"]
|
|
72
|
+
connection = self.get_global_connections()[name]
|
|
73
|
+
self.remove_global_connection(name)
|
|
74
|
+
connection.commit()
|
|
75
|
+
|
|
76
|
+
def rollback(self, name=None):
|
|
77
|
+
if name is None:
|
|
78
|
+
name = self.get_connection_details()["default"]
|
|
79
|
+
|
|
80
|
+
connection = self.get_global_connections()[name]
|
|
81
|
+
self.remove_global_connection(name)
|
|
82
|
+
connection.rollback()
|
|
83
|
+
|
|
84
|
+
@contextmanager
|
|
85
|
+
def transaction(self, name=None):
|
|
86
|
+
self.begin_transaction(name)
|
|
87
|
+
try:
|
|
88
|
+
yield self
|
|
89
|
+
except Exception:
|
|
90
|
+
self.rollback(name)
|
|
91
|
+
raise
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
self.commit(name)
|
|
95
|
+
except Exception:
|
|
96
|
+
self.rollback(name)
|
|
97
|
+
raise
|
|
98
|
+
|
|
99
|
+
def get_connection_information(self, name):
|
|
100
|
+
details = self.get_connection_details()
|
|
101
|
+
return {
|
|
102
|
+
"host": details.get(name, {}).get("host"),
|
|
103
|
+
"database": details.get(name, {}).get("database"),
|
|
104
|
+
"user": details.get(name, {}).get("user"),
|
|
105
|
+
"port": details.get(name, {}).get("port"),
|
|
106
|
+
"password": details.get(name, {}).get("password"),
|
|
107
|
+
"prefix": details.get(name, {}).get("prefix"),
|
|
108
|
+
"options": details.get(name, {}).get("options", {}),
|
|
109
|
+
"full_details": details.get(name, {}),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
def get_schema_builder(self, connection="default", schema=None):
|
|
113
|
+
from ..schema import Schema
|
|
114
|
+
|
|
115
|
+
return Schema(
|
|
116
|
+
connection=connection,
|
|
117
|
+
connection_details=self.get_connection_details(),
|
|
118
|
+
schema=schema,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def get_query_builder(self, connection="default"):
|
|
122
|
+
from ..query import QueryBuilder
|
|
123
|
+
|
|
124
|
+
return QueryBuilder(
|
|
125
|
+
connection=connection,
|
|
126
|
+
connection_details=self.get_connection_details(),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def statement(self, query, bindings=(), connection="default"):
|
|
130
|
+
return (
|
|
131
|
+
self.get_query_builder().on(connection).statement(query, bindings)
|
|
132
|
+
)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
from ..exceptions import DriverNotFound, QueryException
|
|
2
|
+
from ..query.grammars import MSSQLGrammar
|
|
3
|
+
from ..query.processors import MSSQLPostProcessor
|
|
4
|
+
from ..schema.platforms import MSSQLPlatform
|
|
5
|
+
from .BaseConnection import BaseConnection
|
|
6
|
+
|
|
7
|
+
CONNECTION_POOL = []
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MSSQLConnection(BaseConnection):
|
|
11
|
+
"""MSSQL Connection class."""
|
|
12
|
+
|
|
13
|
+
name = "mssql"
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
host=None,
|
|
18
|
+
database=None,
|
|
19
|
+
user=None,
|
|
20
|
+
port=None,
|
|
21
|
+
password=None,
|
|
22
|
+
prefix=None,
|
|
23
|
+
options=None,
|
|
24
|
+
full_details=None,
|
|
25
|
+
name=None,
|
|
26
|
+
):
|
|
27
|
+
self.host = host
|
|
28
|
+
if port:
|
|
29
|
+
self.port = int(port)
|
|
30
|
+
else:
|
|
31
|
+
self.port = port
|
|
32
|
+
self.database = database
|
|
33
|
+
self.user = user
|
|
34
|
+
self.password = password
|
|
35
|
+
self.prefix = prefix
|
|
36
|
+
self.full_details = full_details or {}
|
|
37
|
+
self.options = options or {}
|
|
38
|
+
self._cursor = None
|
|
39
|
+
self.transaction_level = 0
|
|
40
|
+
self.open = 0
|
|
41
|
+
if name:
|
|
42
|
+
self.name = name
|
|
43
|
+
|
|
44
|
+
def make_connection(self):
|
|
45
|
+
"""This sets the connection on the connection class"""
|
|
46
|
+
try:
|
|
47
|
+
import pyodbc
|
|
48
|
+
except ModuleNotFoundError:
|
|
49
|
+
raise DriverNotFound(
|
|
50
|
+
"You must have the 'pyodbc' package installed to make a connection to Microsoft SQL Server. Please install it using 'pip install pyodbc'"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if self.has_global_connection():
|
|
54
|
+
return self.get_global_connection()
|
|
55
|
+
|
|
56
|
+
driver = self.options.get("driver", "ODBC Driver 17 for SQL Server")
|
|
57
|
+
integrated_security = self.options.get("integrated_security")
|
|
58
|
+
connection_timeout = str(self.options.get("connection_timeout", "30"))
|
|
59
|
+
authentication = self.options.get("authentication")
|
|
60
|
+
instance = self.options.get("instance", "")
|
|
61
|
+
trusted_connection = self.options.get("trusted_connection")
|
|
62
|
+
|
|
63
|
+
if instance:
|
|
64
|
+
instance = "\\" + instance
|
|
65
|
+
|
|
66
|
+
self._connection = pyodbc.connect(
|
|
67
|
+
f"DRIVER={driver};SERVER={self.host}{instance if instance else ''},{self.port};Connection Timeout={connection_timeout};DATABASE={self.database}{f';Integrated Security={integrated_security}' if integrated_security else ''};UID={self.user};PWD={self.password}{f';Trusted_Connection={trusted_connection}' if trusted_connection else ''}{f';Authentication={authentication}' if authentication else ''}",
|
|
68
|
+
autocommit=True,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
self.enable_disable_foreign_keys()
|
|
72
|
+
|
|
73
|
+
self.open = 1
|
|
74
|
+
return self
|
|
75
|
+
|
|
76
|
+
def get_database_name(self):
|
|
77
|
+
return self.database
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def get_default_query_grammar(cls):
|
|
81
|
+
return MSSQLGrammar
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def get_default_platform(cls):
|
|
85
|
+
return MSSQLPlatform
|
|
86
|
+
|
|
87
|
+
@classmethod
|
|
88
|
+
def get_default_post_processor(cls):
|
|
89
|
+
return MSSQLPostProcessor
|
|
90
|
+
|
|
91
|
+
def reconnect(self):
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
def commit(self):
|
|
95
|
+
"""Transaction"""
|
|
96
|
+
if self.get_transaction_level() == 1:
|
|
97
|
+
self._connection.commit()
|
|
98
|
+
self._connection.autocommit = True
|
|
99
|
+
|
|
100
|
+
self.transaction_level -= 1
|
|
101
|
+
|
|
102
|
+
def begin(self):
|
|
103
|
+
"""MSSQL Transaction"""
|
|
104
|
+
self._connection.autocommit = False
|
|
105
|
+
self.transaction_level += 1
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
def rollback(self):
|
|
109
|
+
"""Transaction"""
|
|
110
|
+
if self.get_transaction_level() == 1:
|
|
111
|
+
self._connection.rollback()
|
|
112
|
+
self._connection.autocommit = True
|
|
113
|
+
|
|
114
|
+
self.transaction_level -= 1
|
|
115
|
+
|
|
116
|
+
def get_transaction_level(self):
|
|
117
|
+
"""Transaction"""
|
|
118
|
+
return self.transaction_level
|
|
119
|
+
|
|
120
|
+
def get_cursor(self):
|
|
121
|
+
return self._cursor
|
|
122
|
+
|
|
123
|
+
def query(self, query, bindings=(), results="*"):
|
|
124
|
+
"""Make the actual query that will reach the database and come back with a result.
|
|
125
|
+
|
|
126
|
+
Arguments:
|
|
127
|
+
query {string} -- A string query. This could be a qmarked string or a regular query.
|
|
128
|
+
bindings {tuple} -- A tuple of bindings
|
|
129
|
+
|
|
130
|
+
Keyword Arguments:
|
|
131
|
+
results {str|1} -- If the results is equal to an asterisks it will call 'fetchAll'
|
|
132
|
+
else it will return 'fetchOne' and return a single record. (default: {"*"})
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
dict|None -- Returns a dictionary of results or None
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
if not self.open:
|
|
140
|
+
self.make_connection()
|
|
141
|
+
self._cursor = self._connection.cursor()
|
|
142
|
+
with self._cursor as cursor:
|
|
143
|
+
if isinstance(query, list) and not self._dry:
|
|
144
|
+
for q in query:
|
|
145
|
+
self.statement(q, ())
|
|
146
|
+
return
|
|
147
|
+
self.statement(query, bindings)
|
|
148
|
+
if results == 1:
|
|
149
|
+
if not cursor.description:
|
|
150
|
+
return {}
|
|
151
|
+
columnNames = [column[0] for column in cursor.description]
|
|
152
|
+
result = cursor.fetchone()
|
|
153
|
+
return (
|
|
154
|
+
dict(zip(columnNames, result))
|
|
155
|
+
if result is not None
|
|
156
|
+
else {}
|
|
157
|
+
)
|
|
158
|
+
else:
|
|
159
|
+
if not cursor.description:
|
|
160
|
+
return {}
|
|
161
|
+
return self.format_cursor_results(cursor.fetchall())
|
|
162
|
+
|
|
163
|
+
return {}
|
|
164
|
+
except Exception as e:
|
|
165
|
+
raise QueryException(str(e)) from e
|
|
166
|
+
finally:
|
|
167
|
+
if self.get_transaction_level() <= 0:
|
|
168
|
+
self._connection.close()
|
|
169
|
+
|
|
170
|
+
def format_cursor_results(self, cursor_result):
|
|
171
|
+
columnNames = [column[0] for column in self.get_cursor().description]
|
|
172
|
+
results = []
|
|
173
|
+
for record in cursor_result:
|
|
174
|
+
results.append(dict(zip(columnNames, record)))
|
|
175
|
+
|
|
176
|
+
return results
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
from ..exceptions import DriverNotFound, QueryException
|
|
2
|
+
from ..query.grammars import MySQLGrammar
|
|
3
|
+
from ..query.processors import MySQLPostProcessor
|
|
4
|
+
from ..schema.platforms import MySQLPlatform
|
|
5
|
+
from .BaseConnection import BaseConnection
|
|
6
|
+
|
|
7
|
+
CONNECTION_POOL = []
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MySQLConnection(BaseConnection):
|
|
11
|
+
"""MYSQL Connection class."""
|
|
12
|
+
|
|
13
|
+
name = "mysql"
|
|
14
|
+
_dry = False
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
host=None,
|
|
19
|
+
database=None,
|
|
20
|
+
user=None,
|
|
21
|
+
port=None,
|
|
22
|
+
password=None,
|
|
23
|
+
prefix=None,
|
|
24
|
+
options=None,
|
|
25
|
+
full_details=None,
|
|
26
|
+
name=None,
|
|
27
|
+
):
|
|
28
|
+
self.host = host
|
|
29
|
+
self.port = port
|
|
30
|
+
if str(port).isdigit():
|
|
31
|
+
self.port = int(self.port)
|
|
32
|
+
self.database = database
|
|
33
|
+
|
|
34
|
+
self.user = user
|
|
35
|
+
self.password = password
|
|
36
|
+
self.prefix = prefix
|
|
37
|
+
self.full_details = full_details or {}
|
|
38
|
+
self.connection_pool_size = full_details.get(
|
|
39
|
+
"connection_pooling_max_size", 100
|
|
40
|
+
)
|
|
41
|
+
self.options = options or {}
|
|
42
|
+
self._cursor = None
|
|
43
|
+
self.open = 0
|
|
44
|
+
self.transaction_level = 0
|
|
45
|
+
if name:
|
|
46
|
+
self.name = name
|
|
47
|
+
|
|
48
|
+
def make_connection(self):
|
|
49
|
+
"""This sets the connection on the connection class"""
|
|
50
|
+
|
|
51
|
+
if self._dry:
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
if self.has_global_connection():
|
|
55
|
+
return self.get_global_connection()
|
|
56
|
+
|
|
57
|
+
# Check if there is an available connection in the pool
|
|
58
|
+
self._connection = self.create_connection()
|
|
59
|
+
self.enable_disable_foreign_keys()
|
|
60
|
+
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def close_connection(self):
|
|
64
|
+
if (
|
|
65
|
+
self.full_details.get("connection_pooling_enabled")
|
|
66
|
+
and len(CONNECTION_POOL) < self.connection_pool_size
|
|
67
|
+
):
|
|
68
|
+
CONNECTION_POOL.append(self._connection)
|
|
69
|
+
self.open = 0
|
|
70
|
+
self._connection = None
|
|
71
|
+
|
|
72
|
+
def create_connection(self, autocommit=True):
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
import pymysql
|
|
76
|
+
except ModuleNotFoundError:
|
|
77
|
+
raise DriverNotFound(
|
|
78
|
+
"You must have the 'pymysql' package "
|
|
79
|
+
"installed to make a connection to MySQL. "
|
|
80
|
+
"Please install it using 'pip install pymysql'"
|
|
81
|
+
)
|
|
82
|
+
import pendulum
|
|
83
|
+
import pymysql.converters
|
|
84
|
+
|
|
85
|
+
pymysql.converters.conversions[pendulum.DateTime] = (
|
|
86
|
+
pymysql.converters.escape_datetime
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Initialize the connection pool if the option is set
|
|
90
|
+
initialize_size = self.full_details.get("connection_pooling_min_size")
|
|
91
|
+
if initialize_size and len(CONNECTION_POOL) < initialize_size:
|
|
92
|
+
for _ in range(initialize_size - len(CONNECTION_POOL)):
|
|
93
|
+
connection = pymysql.connect(
|
|
94
|
+
cursorclass=pymysql.cursors.DictCursor,
|
|
95
|
+
autocommit=autocommit,
|
|
96
|
+
host=self.host,
|
|
97
|
+
user=self.user,
|
|
98
|
+
password=self.password,
|
|
99
|
+
port=self.port,
|
|
100
|
+
database=self.database,
|
|
101
|
+
**self.options,
|
|
102
|
+
)
|
|
103
|
+
CONNECTION_POOL.append(connection)
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
self.full_details.get("connection_pooling_enabled")
|
|
107
|
+
and CONNECTION_POOL
|
|
108
|
+
and len(CONNECTION_POOL) > 0
|
|
109
|
+
):
|
|
110
|
+
connection = CONNECTION_POOL.pop()
|
|
111
|
+
else:
|
|
112
|
+
connection = pymysql.connect(
|
|
113
|
+
cursorclass=pymysql.cursors.DictCursor,
|
|
114
|
+
autocommit=autocommit,
|
|
115
|
+
host=self.host,
|
|
116
|
+
user=self.user,
|
|
117
|
+
password=self.password,
|
|
118
|
+
port=self.port,
|
|
119
|
+
database=self.database,
|
|
120
|
+
**self.options,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
connection.close = self.close_connection
|
|
124
|
+
|
|
125
|
+
self.open = 1
|
|
126
|
+
|
|
127
|
+
return connection
|
|
128
|
+
|
|
129
|
+
def reconnect(self):
|
|
130
|
+
self._connection.connect()
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
@classmethod
|
|
134
|
+
def get_default_query_grammar(cls):
|
|
135
|
+
return MySQLGrammar
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def get_default_platform(cls):
|
|
139
|
+
return MySQLPlatform
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def get_default_post_processor(cls):
|
|
143
|
+
return MySQLPostProcessor
|
|
144
|
+
|
|
145
|
+
def get_database_name(self):
|
|
146
|
+
return self.database
|
|
147
|
+
|
|
148
|
+
def commit(self):
|
|
149
|
+
"""Transaction"""
|
|
150
|
+
self._connection.commit()
|
|
151
|
+
self.transaction_level -= 1
|
|
152
|
+
if self.get_transaction_level() <= 0:
|
|
153
|
+
self.open = 0
|
|
154
|
+
self._connection.close()
|
|
155
|
+
|
|
156
|
+
def dry(self):
|
|
157
|
+
"""Transaction"""
|
|
158
|
+
self._dry = True
|
|
159
|
+
return self
|
|
160
|
+
|
|
161
|
+
def begin(self):
|
|
162
|
+
"""Mysql Transaction"""
|
|
163
|
+
self._connection.begin()
|
|
164
|
+
self.transaction_level += 1
|
|
165
|
+
return self
|
|
166
|
+
|
|
167
|
+
def rollback(self):
|
|
168
|
+
"""Transaction"""
|
|
169
|
+
self._connection.rollback()
|
|
170
|
+
self.transaction_level -= 1
|
|
171
|
+
if self.get_transaction_level() <= 0:
|
|
172
|
+
self.open = 0
|
|
173
|
+
self._connection.close()
|
|
174
|
+
|
|
175
|
+
def get_transaction_level(self):
|
|
176
|
+
"""Transaction"""
|
|
177
|
+
return self.transaction_level
|
|
178
|
+
|
|
179
|
+
def get_cursor(self):
|
|
180
|
+
return self._cursor
|
|
181
|
+
|
|
182
|
+
def query(self, query, bindings=(), results="*"):
|
|
183
|
+
"""Make the actual query that
|
|
184
|
+
will reach the database and come back with a result.
|
|
185
|
+
|
|
186
|
+
Arguments:
|
|
187
|
+
query {string} -- A string query.
|
|
188
|
+
This could be a qmarked string or a regular query.
|
|
189
|
+
bindings {tuple} -- A tuple of bindings
|
|
190
|
+
|
|
191
|
+
Keyword Arguments:
|
|
192
|
+
results {str|1} -- If the results is equal to an
|
|
193
|
+
asterisks it will call 'fetchAll'
|
|
194
|
+
else it will return 'fetchOne' and
|
|
195
|
+
return a single record. (default: {"*"})
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
dict|None -- Returns a dictionary of results or None
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
if self._dry:
|
|
202
|
+
return {}
|
|
203
|
+
|
|
204
|
+
if not self.open:
|
|
205
|
+
if self._connection is None:
|
|
206
|
+
self._connection = self.create_connection()
|
|
207
|
+
|
|
208
|
+
self._connection.connect()
|
|
209
|
+
|
|
210
|
+
self._cursor = self._connection.cursor()
|
|
211
|
+
|
|
212
|
+
try:
|
|
213
|
+
with self._cursor as cursor:
|
|
214
|
+
if isinstance(query, list):
|
|
215
|
+
for q in query:
|
|
216
|
+
q = q.replace("?", "%s")
|
|
217
|
+
self.statement(q, ())
|
|
218
|
+
return
|
|
219
|
+
|
|
220
|
+
query = query.replace("?", "%s")
|
|
221
|
+
self.statement(query, bindings)
|
|
222
|
+
if results == 1:
|
|
223
|
+
return self.format_cursor_results(cursor.fetchone())
|
|
224
|
+
else:
|
|
225
|
+
return self.format_cursor_results(cursor.fetchall())
|
|
226
|
+
except Exception as e:
|
|
227
|
+
raise QueryException(str(e)) from e
|
|
228
|
+
finally:
|
|
229
|
+
self._cursor.close()
|
|
230
|
+
if self.get_transaction_level() <= 0:
|
|
231
|
+
self.open = 0
|
|
232
|
+
self._connection.close()
|