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,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()