reydb 1.1.52__py3-none-any.whl → 1.1.54__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.
- reydb/rbase.py +90 -2
- reydb/rconfig.py +3 -3
- reydb/rconn.py +187 -18
- reydb/rdb.py +165 -28
- reydb/rexec.py +1002 -293
- reydb/rfile.py +1 -1
- reydb/rorm.py +233 -36
- {reydb-1.1.52.dist-info → reydb-1.1.54.dist-info}/METADATA +1 -1
- reydb-1.1.54.dist-info/RECORD +17 -0
- reydb-1.1.52.dist-info/RECORD +0 -17
- {reydb-1.1.52.dist-info → reydb-1.1.54.dist-info}/WHEEL +0 -0
- {reydb-1.1.52.dist-info → reydb-1.1.54.dist-info}/licenses/LICENSE +0 -0
reydb/rbase.py
CHANGED
@@ -9,19 +9,28 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from typing import Any, TypedDict, Literal
|
12
|
+
from typing import Any, TypedDict, Literal
|
13
|
+
from enum import EnumType
|
14
|
+
from sqlalchemy import text as sqlalchemy_text
|
13
15
|
from sqlalchemy.engine.base import Engine, Connection
|
14
16
|
from sqlalchemy.engine.url import URL
|
15
17
|
from sqlalchemy.sql.elements import TextClause
|
16
18
|
from reykit.rbase import Base, throw
|
17
19
|
from reykit.rre import search
|
18
20
|
|
21
|
+
from reykit.rdata import to_json
|
22
|
+
from reykit.rre import findall
|
23
|
+
|
19
24
|
|
20
25
|
__all__ = (
|
21
26
|
'DatabaseBase',
|
27
|
+
'handle_sql',
|
28
|
+
'handle_data',
|
22
29
|
'extract_url',
|
23
30
|
'extract_engine',
|
24
|
-
'extract_path'
|
31
|
+
'extract_path',
|
32
|
+
'get_syntax',
|
33
|
+
'is_multi_sql'
|
25
34
|
)
|
26
35
|
|
27
36
|
|
@@ -47,6 +56,85 @@ class DatabaseBase(Base):
|
|
47
56
|
"""
|
48
57
|
|
49
58
|
|
59
|
+
def handle_sql(sql: str | TextClause) -> TextClause:
|
60
|
+
"""
|
61
|
+
Handle SQL.
|
62
|
+
|
63
|
+
Parameters
|
64
|
+
----------
|
65
|
+
sql : SQL in method `sqlalchemy.text` format, or TextClause object.
|
66
|
+
|
67
|
+
Returns
|
68
|
+
-------
|
69
|
+
TextClause instance.
|
70
|
+
"""
|
71
|
+
|
72
|
+
# Handle parameter.
|
73
|
+
if type(sql) == TextClause:
|
74
|
+
sql = sql.text
|
75
|
+
|
76
|
+
# Handle.
|
77
|
+
sql = sql.strip()
|
78
|
+
if sql[-1] != ';':
|
79
|
+
sql += ';'
|
80
|
+
sql = sqlalchemy_text(sql)
|
81
|
+
|
82
|
+
return sql
|
83
|
+
|
84
|
+
|
85
|
+
def handle_data(data: list[dict], sql: str | TextClause) -> list[dict]:
|
86
|
+
"""
|
87
|
+
Handle data based on the content of SQL.
|
88
|
+
|
89
|
+
Parameters
|
90
|
+
----------
|
91
|
+
data : Data set for filling.
|
92
|
+
sql : SQL in method `sqlalchemy.text` format, or TextClause object.
|
93
|
+
|
94
|
+
Returns
|
95
|
+
-------
|
96
|
+
Filled data.
|
97
|
+
"""
|
98
|
+
|
99
|
+
# Handle parameter.
|
100
|
+
if type(sql) == TextClause:
|
101
|
+
sql = sql.text
|
102
|
+
|
103
|
+
# Extract keys.
|
104
|
+
pattern = '(?<!\\\\):(\\w+)'
|
105
|
+
sql_keys = findall(pattern, sql)
|
106
|
+
|
107
|
+
# Extract keys of syntax "in".
|
108
|
+
pattern = '[iI][nN]\\s+(?<!\\\\):(\\w+)'
|
109
|
+
sql_keys_in = findall(pattern, sql)
|
110
|
+
|
111
|
+
# Loop.
|
112
|
+
for row in data:
|
113
|
+
if row == {}:
|
114
|
+
continue
|
115
|
+
for key in sql_keys:
|
116
|
+
value = row.get(key)
|
117
|
+
|
118
|
+
# Empty string.
|
119
|
+
if value == '':
|
120
|
+
value = None
|
121
|
+
|
122
|
+
# Convert.
|
123
|
+
elif (
|
124
|
+
type(value) in (list, dict)
|
125
|
+
and key not in sql_keys_in
|
126
|
+
):
|
127
|
+
value = to_json(value)
|
128
|
+
|
129
|
+
# Enum.
|
130
|
+
elif isinstance(type(value), EnumType):
|
131
|
+
value = value.value
|
132
|
+
|
133
|
+
row[key] = value
|
134
|
+
|
135
|
+
return data
|
136
|
+
|
137
|
+
|
50
138
|
def extract_url(url: str | URL) -> URLParameters:
|
51
139
|
"""
|
52
140
|
Extract parameters from URL of string.
|
reydb/rconfig.py
CHANGED
@@ -17,7 +17,7 @@ from datetime import (
|
|
17
17
|
time as Time,
|
18
18
|
timedelta as Timedelta
|
19
19
|
)
|
20
|
-
from reykit.rbase import
|
20
|
+
from reykit.rbase import Null, throw
|
21
21
|
|
22
22
|
from .rdb import Database
|
23
23
|
|
@@ -445,10 +445,10 @@ class DatabaseConfig(object):
|
|
445
445
|
"""
|
446
446
|
|
447
447
|
# Get.
|
448
|
-
value = self.get(key,
|
448
|
+
value = self.get(key, Null)
|
449
449
|
|
450
450
|
# Check.
|
451
|
-
if value ==
|
451
|
+
if value == Null:
|
452
452
|
throw(KeyError, key)
|
453
453
|
|
454
454
|
return value
|
reydb/rconn.py
CHANGED
@@ -10,7 +10,8 @@
|
|
10
10
|
|
11
11
|
|
12
12
|
from typing import Self
|
13
|
-
from sqlalchemy import Transaction
|
13
|
+
from sqlalchemy import Connection, Transaction
|
14
|
+
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncTransaction
|
14
15
|
|
15
16
|
from .rbase import DatabaseBase
|
16
17
|
from .rdb import Database
|
@@ -18,6 +19,7 @@ from .rdb import Database
|
|
18
19
|
|
19
20
|
__all__ = (
|
20
21
|
'DatabaseConnection',
|
22
|
+
'DatabaseConnectionAsync'
|
21
23
|
)
|
22
24
|
|
23
25
|
|
@@ -47,11 +49,44 @@ class DatabaseConnection(DatabaseBase):
|
|
47
49
|
# Build.
|
48
50
|
self.db = db
|
49
51
|
self.autocommit = autocommit
|
50
|
-
self.
|
51
|
-
self.
|
52
|
+
self.execute = DatabaseExecute(self)
|
53
|
+
self.conn: Connection | None = None
|
52
54
|
self.begin: Transaction | None = None
|
53
55
|
|
54
56
|
|
57
|
+
def get_conn(self) -> Connection:
|
58
|
+
"""
|
59
|
+
Get `Connection` instance.
|
60
|
+
|
61
|
+
Returns
|
62
|
+
-------
|
63
|
+
Instance.
|
64
|
+
"""
|
65
|
+
|
66
|
+
# Create.
|
67
|
+
if self.conn is None:
|
68
|
+
self.conn = self.db.engine.connect()
|
69
|
+
|
70
|
+
return self.conn
|
71
|
+
|
72
|
+
|
73
|
+
def get_begin(self) -> Transaction:
|
74
|
+
"""
|
75
|
+
Get `Transaction` instance.
|
76
|
+
|
77
|
+
Returns
|
78
|
+
-------
|
79
|
+
Instance.
|
80
|
+
"""
|
81
|
+
|
82
|
+
# Create.
|
83
|
+
if self.begin is None:
|
84
|
+
conn = self.get_conn()
|
85
|
+
self.begin = conn.begin()
|
86
|
+
|
87
|
+
return self.begin
|
88
|
+
|
89
|
+
|
55
90
|
def commit(self) -> None:
|
56
91
|
"""
|
57
92
|
Commit cumulative executions.
|
@@ -80,7 +115,12 @@ class DatabaseConnection(DatabaseBase):
|
|
80
115
|
"""
|
81
116
|
|
82
117
|
# Close.
|
83
|
-
self.
|
118
|
+
if self.begin is not None:
|
119
|
+
self.begin.close()
|
120
|
+
self.begin = None
|
121
|
+
if self.conn is not None:
|
122
|
+
self.conn.close()
|
123
|
+
self.conn = None
|
84
124
|
|
85
125
|
|
86
126
|
def __enter__(self) -> Self:
|
@@ -113,34 +153,163 @@ class DatabaseConnection(DatabaseBase):
|
|
113
153
|
self.commit()
|
114
154
|
|
115
155
|
# Close.
|
116
|
-
|
117
|
-
self.close()
|
156
|
+
self.close()
|
118
157
|
|
119
158
|
|
120
|
-
|
159
|
+
def insert_id(self) -> int:
|
160
|
+
"""
|
161
|
+
Return last self increasing ID.
|
121
162
|
|
163
|
+
Returns
|
164
|
+
-------
|
165
|
+
ID.
|
166
|
+
"""
|
122
167
|
|
123
|
-
|
124
|
-
|
168
|
+
# Get.
|
169
|
+
sql = 'SELECT LAST_INSERT_ID()'
|
170
|
+
result = self.execute(sql)
|
171
|
+
id_ = result.scalar()
|
172
|
+
|
173
|
+
return id_
|
174
|
+
|
175
|
+
|
176
|
+
class DatabaseConnectionAsync(DatabaseBase):
|
177
|
+
"""
|
178
|
+
Asynchronous database connection type.
|
179
|
+
"""
|
180
|
+
|
181
|
+
|
182
|
+
def __init__(
|
183
|
+
self,
|
184
|
+
db: Database,
|
185
|
+
autocommit: bool
|
186
|
+
) -> None:
|
187
|
+
"""
|
188
|
+
Build instance attributes.
|
189
|
+
|
190
|
+
Parameters
|
191
|
+
----------
|
192
|
+
db : `DatabaseAsync` instance.
|
193
|
+
autocommit: Whether automatic commit execute.
|
125
194
|
"""
|
126
|
-
|
195
|
+
|
196
|
+
# Import.
|
197
|
+
from .rexec import DatabaseExecuteAsync
|
198
|
+
|
199
|
+
# Build.
|
200
|
+
self.db = db
|
201
|
+
self.autocommit = autocommit
|
202
|
+
self.aexecute = DatabaseExecuteAsync(self)
|
203
|
+
self.aconn: AsyncConnection | None = None
|
204
|
+
self.abegin: AsyncTransaction | None = None
|
205
|
+
|
206
|
+
|
207
|
+
async def get_conn(self) -> AsyncConnection:
|
208
|
+
"""
|
209
|
+
Asynchronous get `Connection` instance.
|
127
210
|
|
128
211
|
Returns
|
129
212
|
-------
|
130
213
|
Instance.
|
131
214
|
"""
|
132
215
|
|
133
|
-
# Create
|
134
|
-
if self.
|
135
|
-
self.
|
216
|
+
# Create.
|
217
|
+
if self.aconn is None:
|
218
|
+
self.aconn = await self.db.aengine.connect()
|
136
219
|
|
137
|
-
return self.
|
220
|
+
return self.aconn
|
138
221
|
|
139
222
|
|
140
|
-
|
141
|
-
def insert_id(self) -> int:
|
223
|
+
async def get_begin(self) -> AsyncTransaction:
|
142
224
|
"""
|
143
|
-
|
225
|
+
Asynchronous get `Transaction` instance.
|
226
|
+
|
227
|
+
Returns
|
228
|
+
-------
|
229
|
+
Instance.
|
230
|
+
"""
|
231
|
+
|
232
|
+
# Create.
|
233
|
+
if self.abegin is None:
|
234
|
+
conn = await self.get_conn()
|
235
|
+
self.abegin = await conn.begin()
|
236
|
+
|
237
|
+
return self.abegin
|
238
|
+
|
239
|
+
|
240
|
+
async def commit(self) -> None:
|
241
|
+
"""
|
242
|
+
Asynchronous commit cumulative executions.
|
243
|
+
"""
|
244
|
+
|
245
|
+
# Commit.
|
246
|
+
if self.abegin is not None:
|
247
|
+
await self.abegin.commit()
|
248
|
+
self.abegin = None
|
249
|
+
|
250
|
+
|
251
|
+
async def rollback(self) -> None:
|
252
|
+
"""
|
253
|
+
Asynchronous rollback cumulative executions.
|
254
|
+
"""
|
255
|
+
|
256
|
+
# Rollback.
|
257
|
+
if self.abegin is not None:
|
258
|
+
await self.abegin.rollback()
|
259
|
+
self.abegin = None
|
260
|
+
|
261
|
+
|
262
|
+
async def close(self) -> None:
|
263
|
+
"""
|
264
|
+
Asynchronous close database connection.
|
265
|
+
"""
|
266
|
+
|
267
|
+
# Close.
|
268
|
+
if self.abegin is not None:
|
269
|
+
await self.abegin.close()
|
270
|
+
self.abegin = None
|
271
|
+
if self.aconn is not None:
|
272
|
+
await self.aconn.close()
|
273
|
+
self.aconn = None
|
274
|
+
|
275
|
+
|
276
|
+
async def __aenter__(self):
|
277
|
+
"""
|
278
|
+
Asynchronous enter syntax `async with`.
|
279
|
+
|
280
|
+
Returns
|
281
|
+
-------
|
282
|
+
Self.
|
283
|
+
"""
|
284
|
+
|
285
|
+
return self
|
286
|
+
|
287
|
+
|
288
|
+
async def __aexit__(
|
289
|
+
self,
|
290
|
+
exc_type: type[BaseException] | None,
|
291
|
+
*_
|
292
|
+
) -> None:
|
293
|
+
"""
|
294
|
+
Asynchronous exit syntax `async with`.
|
295
|
+
|
296
|
+
Parameters
|
297
|
+
----------
|
298
|
+
exc_type : Exception type.
|
299
|
+
"""
|
300
|
+
|
301
|
+
# Commit.
|
302
|
+
if exc_type is None:
|
303
|
+
await self.commit()
|
304
|
+
|
305
|
+
# Close.
|
306
|
+
await self.close()
|
307
|
+
await self.db.dispose()
|
308
|
+
|
309
|
+
|
310
|
+
async def insert_id(self) -> int:
|
311
|
+
"""
|
312
|
+
Asynchronous return last self increasing ID.
|
144
313
|
|
145
314
|
Returns
|
146
315
|
-------
|
@@ -149,7 +318,7 @@ class DatabaseConnection(DatabaseBase):
|
|
149
318
|
|
150
319
|
# Get.
|
151
320
|
sql = 'SELECT LAST_INSERT_ID()'
|
152
|
-
result = self.
|
321
|
+
result = await self.aexecute(sql)
|
153
322
|
id_ = result.scalar()
|
154
323
|
|
155
324
|
return id_
|
reydb/rdb.py
CHANGED
@@ -9,10 +9,12 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
+
from typing import Literal, Final, overload
|
12
13
|
from urllib.parse import quote as urllib_quote
|
13
14
|
from pymysql.constants.CLIENT import MULTI_STATEMENTS
|
14
15
|
from sqlalchemy import create_engine as sqlalchemy_create_engine
|
15
16
|
from sqlalchemy.engine.base import Engine
|
17
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine as sqlalchemy_create_async_engine
|
16
18
|
from reykit.rtext import join_data_text
|
17
19
|
|
18
20
|
from .rbase import DatabaseBase, extract_url
|
@@ -26,10 +28,6 @@ __all__ = (
|
|
26
28
|
class Database(DatabaseBase):
|
27
29
|
"""
|
28
30
|
Database type, based `MySQL`.
|
29
|
-
|
30
|
-
Attributes
|
31
|
-
----------
|
32
|
-
default_report : Whether default to report execution.
|
33
31
|
"""
|
34
32
|
|
35
33
|
default_report: bool = False
|
@@ -45,7 +43,7 @@ class Database(DatabaseBase):
|
|
45
43
|
pool_size: int = 5,
|
46
44
|
max_overflow: int = 10,
|
47
45
|
pool_timeout: float = 30.0,
|
48
|
-
pool_recycle: int | None =
|
46
|
+
pool_recycle: int | None = 3600,
|
49
47
|
**query: str
|
50
48
|
) -> None:
|
51
49
|
"""
|
@@ -62,10 +60,7 @@ class Database(DatabaseBase):
|
|
62
60
|
max_overflow : Number of connections `allowed overflow`.
|
63
61
|
pool_timeout : Number of seconds `wait create` connection.
|
64
62
|
pool_recycle : Number of seconds `recycle` connection.
|
65
|
-
- `None`:
|
66
|
-
When is remote server database, then is database variable `wait_timeout` value.
|
67
|
-
When is local database file, then is `-1`.
|
68
|
-
- `Literal[-1]`: No recycle.
|
63
|
+
- `None | Literal[-1]`: No recycle.
|
69
64
|
- `int`: Use this value.
|
70
65
|
query : Remote server database parameters.
|
71
66
|
"""
|
@@ -90,14 +85,8 @@ class Database(DatabaseBase):
|
|
90
85
|
self.query = query
|
91
86
|
|
92
87
|
# Create engine.
|
93
|
-
self.engine = self.__create_engine()
|
94
|
-
|
95
|
-
# Server recycle time.
|
96
|
-
if pool_recycle is None:
|
97
|
-
wait_timeout = self.variables['wait_timeout']
|
98
|
-
if wait_timeout is not None:
|
99
|
-
self.pool_recycle = int(wait_timeout)
|
100
|
-
self.engine.pool._recycle = self.pool_recycle
|
88
|
+
self.engine = self.__create_engine(False)
|
89
|
+
self.aengine = self.__create_engine(True)
|
101
90
|
|
102
91
|
|
103
92
|
@property
|
@@ -111,7 +100,8 @@ class Database(DatabaseBase):
|
|
111
100
|
"""
|
112
101
|
|
113
102
|
# Get.
|
114
|
-
|
103
|
+
url = self.url(False)
|
104
|
+
url_params = extract_url(url)
|
115
105
|
backend = url_params['backend']
|
116
106
|
|
117
107
|
return backend
|
@@ -128,17 +118,57 @@ class Database(DatabaseBase):
|
|
128
118
|
"""
|
129
119
|
|
130
120
|
# Get.
|
131
|
-
|
121
|
+
url = self.url(False)
|
122
|
+
url_params = extract_url(url)
|
132
123
|
driver = url_params['driver']
|
133
124
|
|
134
125
|
return driver
|
135
126
|
|
136
127
|
|
137
128
|
@property
|
138
|
-
def
|
129
|
+
def abackend(self) -> str:
|
130
|
+
"""
|
131
|
+
Asynchronous database backend name.
|
132
|
+
|
133
|
+
Returns
|
134
|
+
-------
|
135
|
+
Name.
|
136
|
+
"""
|
137
|
+
|
138
|
+
# Get.
|
139
|
+
url = self.url(True)
|
140
|
+
url_params = extract_url(url)
|
141
|
+
backend = url_params['backend']
|
142
|
+
|
143
|
+
return backend
|
144
|
+
|
145
|
+
|
146
|
+
@property
|
147
|
+
def adriver(self) -> str:
|
148
|
+
"""
|
149
|
+
Asynchronous database driver name.
|
150
|
+
|
151
|
+
Returns
|
152
|
+
-------
|
153
|
+
Name.
|
154
|
+
"""
|
155
|
+
|
156
|
+
# Get.
|
157
|
+
url = self.url(True)
|
158
|
+
url_params = extract_url(url)
|
159
|
+
driver = url_params['driver']
|
160
|
+
|
161
|
+
return driver
|
162
|
+
|
163
|
+
|
164
|
+
def url(self, is_async: bool) -> str:
|
139
165
|
"""
|
140
166
|
Generate server URL.
|
141
167
|
|
168
|
+
Parameters
|
169
|
+
----------
|
170
|
+
is_async : Whether to use asynchronous engine.
|
171
|
+
|
142
172
|
Returns
|
143
173
|
-------
|
144
174
|
Server URL.
|
@@ -146,7 +176,10 @@ class Database(DatabaseBase):
|
|
146
176
|
|
147
177
|
# Generate URL.
|
148
178
|
password = urllib_quote(self.password)
|
149
|
-
|
179
|
+
if is_async:
|
180
|
+
url_ = f'mysql+aiomysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
|
181
|
+
else:
|
182
|
+
url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
|
150
183
|
|
151
184
|
# Add Server parameter.
|
152
185
|
if self.query != {}:
|
@@ -161,18 +194,29 @@ class Database(DatabaseBase):
|
|
161
194
|
return url_
|
162
195
|
|
163
196
|
|
164
|
-
|
197
|
+
@overload
|
198
|
+
def __create_engine(self, is_async: Literal[False]) -> Engine: ...
|
199
|
+
|
200
|
+
@overload
|
201
|
+
def __create_engine(self, is_async: Literal[True]) -> AsyncEngine: ...
|
202
|
+
|
203
|
+
def __create_engine(self, is_async: bool) -> Engine | AsyncEngine:
|
165
204
|
"""
|
166
205
|
Create database `Engine` object.
|
167
206
|
|
207
|
+
Parameters
|
208
|
+
----------
|
209
|
+
is_async : Whether to use asynchronous engine.
|
210
|
+
|
168
211
|
Returns
|
169
212
|
-------
|
170
213
|
Engine object.
|
171
214
|
"""
|
172
215
|
|
173
216
|
# Handle parameter.
|
217
|
+
url = self.url(is_async)
|
174
218
|
engine_params = {
|
175
|
-
'url':
|
219
|
+
'url': url,
|
176
220
|
'pool_size': self.pool_size,
|
177
221
|
'max_overflow': self.max_overflow,
|
178
222
|
'pool_timeout': self.pool_timeout,
|
@@ -181,23 +225,44 @@ class Database(DatabaseBase):
|
|
181
225
|
}
|
182
226
|
|
183
227
|
# Create Engine.
|
184
|
-
|
228
|
+
if is_async:
|
229
|
+
engine = sqlalchemy_create_async_engine(**engine_params)
|
230
|
+
else:
|
231
|
+
engine = sqlalchemy_create_engine(**engine_params)
|
185
232
|
|
186
233
|
return engine
|
187
234
|
|
188
235
|
|
189
|
-
|
190
|
-
|
236
|
+
async def dispose(self) -> None:
|
237
|
+
"""
|
238
|
+
Dispose asynchronous connections.
|
239
|
+
"""
|
240
|
+
|
241
|
+
# Dispose.
|
242
|
+
await self.aengine.dispose()
|
243
|
+
|
244
|
+
|
245
|
+
def __conn_count(self, is_async: bool) -> tuple[int, int]:
|
191
246
|
"""
|
192
247
|
Count number of keep open and allowed overflow connection.
|
193
248
|
|
249
|
+
Parameters
|
250
|
+
----------
|
251
|
+
is_async : Whether to use asynchronous engine.
|
252
|
+
|
194
253
|
Returns
|
195
254
|
-------
|
196
255
|
Number of keep open and allowed overflow connection.
|
197
256
|
"""
|
198
257
|
|
258
|
+
# Handle parameter.
|
259
|
+
if is_async:
|
260
|
+
engine = self.aengine
|
261
|
+
else:
|
262
|
+
engine = self.engine
|
263
|
+
|
199
264
|
# Count.
|
200
|
-
_overflow =
|
265
|
+
_overflow: int = engine.pool._overflow
|
201
266
|
if _overflow < 0:
|
202
267
|
keep_n = self.pool_size + _overflow
|
203
268
|
overflow_n = 0
|
@@ -208,6 +273,38 @@ class Database(DatabaseBase):
|
|
208
273
|
return keep_n, overflow_n
|
209
274
|
|
210
275
|
|
276
|
+
@property
|
277
|
+
def conn_count(self) -> tuple[int, int]:
|
278
|
+
"""
|
279
|
+
Count number of keep open and allowed overflow connection.
|
280
|
+
|
281
|
+
Returns
|
282
|
+
-------
|
283
|
+
Number of keep open and allowed overflow connection.
|
284
|
+
"""
|
285
|
+
|
286
|
+
# Count.
|
287
|
+
keep_n, overflow_n = self.__conn_count(False)
|
288
|
+
|
289
|
+
return keep_n, overflow_n
|
290
|
+
|
291
|
+
|
292
|
+
@property
|
293
|
+
def aconn_count(self) -> tuple[int, int]:
|
294
|
+
"""
|
295
|
+
Count number of keep open and allowed overflow asynchronous connection.
|
296
|
+
|
297
|
+
Returns
|
298
|
+
-------
|
299
|
+
Number of keep open and allowed overflow asynchronous connection.
|
300
|
+
"""
|
301
|
+
|
302
|
+
# Count.
|
303
|
+
keep_n, overflow_n = self.__conn_count(True)
|
304
|
+
|
305
|
+
return keep_n, overflow_n
|
306
|
+
|
307
|
+
|
211
308
|
def schema(self, filter_default: bool = True) -> dict[str, dict[str, list[str]]]:
|
212
309
|
"""
|
213
310
|
Get schemata of databases and tables and columns.
|
@@ -317,6 +414,45 @@ class Database(DatabaseBase):
|
|
317
414
|
return exec
|
318
415
|
|
319
416
|
|
417
|
+
def aconnect(self, autocommit: bool = False):
|
418
|
+
"""
|
419
|
+
Build `DatabaseConnectionAsync` instance.
|
420
|
+
|
421
|
+
Parameters
|
422
|
+
----------
|
423
|
+
autocommit: Whether automatic commit execute.
|
424
|
+
|
425
|
+
Returns
|
426
|
+
-------
|
427
|
+
Database connection instance.
|
428
|
+
"""
|
429
|
+
|
430
|
+
# Import.
|
431
|
+
from .rconn import DatabaseConnectionAsync
|
432
|
+
|
433
|
+
# Build.
|
434
|
+
conn = DatabaseConnectionAsync(self, autocommit)
|
435
|
+
|
436
|
+
return conn
|
437
|
+
|
438
|
+
|
439
|
+
@property
|
440
|
+
def aexecute(self):
|
441
|
+
"""
|
442
|
+
Build `DatabaseConnectionAsync` instance.
|
443
|
+
|
444
|
+
Returns
|
445
|
+
-------
|
446
|
+
Instance.
|
447
|
+
"""
|
448
|
+
|
449
|
+
# Build.
|
450
|
+
dbconn = self.aconnect(True)
|
451
|
+
exec = dbconn.aexecute
|
452
|
+
|
453
|
+
return exec
|
454
|
+
|
455
|
+
|
320
456
|
@property
|
321
457
|
def orm(self):
|
322
458
|
"""
|
@@ -546,7 +682,8 @@ class Database(DatabaseBase):
|
|
546
682
|
for key, value in self.__dict__.items()
|
547
683
|
if key not in filter_key
|
548
684
|
}
|
549
|
-
info['
|
685
|
+
info['conn_count'] = self.conn_count
|
686
|
+
info['aconn_count'] = self.aconn_count
|
550
687
|
text = join_data_text(info)
|
551
688
|
|
552
689
|
return text
|