reydb 1.1.48__py3-none-any.whl → 1.1.50__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/__init__.py +1 -0
- reydb/rall.py +1 -0
- reydb/rbase.py +101 -2
- reydb/rbuild.py +41 -46
- reydb/rconfig.py +16 -18
- reydb/rconn.py +23 -44
- reydb/rdb.py +113 -1454
- reydb/rerror.py +6 -12
- reydb/rexec.py +820 -183
- reydb/rfile.py +10 -17
- reydb/rinfo.py +77 -137
- reydb/rorm.py +39 -0
- reydb/rparam.py +13 -14
- {reydb-1.1.48.dist-info → reydb-1.1.50.dist-info}/METADATA +1 -1
- reydb-1.1.50.dist-info/RECORD +17 -0
- reydb-1.1.48.dist-info/RECORD +0 -16
- {reydb-1.1.48.dist-info → reydb-1.1.50.dist-info}/WHEEL +0 -0
- {reydb-1.1.48.dist-info → reydb-1.1.50.dist-info}/licenses/LICENSE +0 -0
reydb/rdb.py
CHANGED
@@ -9,107 +9,44 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from typing import Any, Literal, overload
|
13
|
-
from collections.abc import Iterable, Generator, Container
|
14
|
-
from enum import EnumType
|
15
12
|
from urllib.parse import quote as urllib_quote
|
16
13
|
from pymysql.constants.CLIENT import MULTI_STATEMENTS
|
17
|
-
from sqlalchemy import create_engine as sqlalchemy_create_engine
|
18
|
-
from sqlalchemy.engine.base import Engine
|
19
|
-
from sqlalchemy.sql.elements import TextClause
|
20
|
-
from reykit.rbase import throw, get_first_notnone
|
21
|
-
from reykit.rdata import Generator, to_json
|
22
|
-
from reykit.rmonkey import monkey_sqlalchemy_result_more_fetch, monkey_sqlalchemy_row_index_field
|
23
|
-
from reykit.rre import search, findall
|
24
|
-
from reykit.rstdout import echo
|
25
|
-
from reykit.rtable import TableData, Table
|
14
|
+
from sqlalchemy import create_engine as sqlalchemy_create_engine
|
15
|
+
from sqlalchemy.engine.base import Engine
|
26
16
|
from reykit.rtext import join_data_text
|
27
|
-
from reykit.rwrap import wrap_runtime
|
28
17
|
|
29
18
|
from .rbase import DatabaseBase, extract_url
|
30
19
|
|
31
20
|
|
32
21
|
__all__ = (
|
33
|
-
'
|
34
|
-
'Database'
|
22
|
+
'Database',
|
35
23
|
)
|
36
24
|
|
37
25
|
|
38
|
-
# Monkey path.
|
39
|
-
Result_ = monkey_sqlalchemy_result_more_fetch()
|
40
|
-
Result = Result_
|
41
|
-
monkey_sqlalchemy_row_index_field()
|
42
|
-
|
43
|
-
|
44
26
|
class Database(DatabaseBase):
|
45
27
|
"""
|
46
|
-
Database type
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
>>> rdb = Database()
|
52
|
-
>>> result = rdb.execute('SELECT 1 as `a`')
|
53
|
-
>>> result.to_table()
|
54
|
-
[{'a': 1}]
|
28
|
+
Database type, based `MySQL`.
|
29
|
+
|
30
|
+
Attributes
|
31
|
+
----------
|
32
|
+
default_report : Whether default to report execution.
|
55
33
|
"""
|
56
34
|
|
57
|
-
# Default value.
|
58
35
|
default_report: bool = False
|
59
36
|
|
60
37
|
|
61
|
-
@overload
|
62
38
|
def __init__(
|
63
39
|
self,
|
64
40
|
host: str,
|
65
41
|
port: int | str,
|
66
42
|
username: str,
|
67
43
|
password: str,
|
68
|
-
database: str | None = None,
|
69
|
-
*,
|
70
|
-
pool_size: int = 5,
|
71
|
-
max_overflow: int = 10,
|
72
|
-
pool_timeout: float = 30.0,
|
73
|
-
pool_recycle: int | None = None,
|
74
|
-
**query: str
|
75
|
-
) -> None: ...
|
76
|
-
|
77
|
-
@overload
|
78
|
-
def __init__(
|
79
|
-
self,
|
80
|
-
*,
|
81
44
|
database: str,
|
82
45
|
pool_size: int = 5,
|
83
46
|
max_overflow: int = 10,
|
84
47
|
pool_timeout: float = 30.0,
|
85
48
|
pool_recycle: int | None = None,
|
86
49
|
**query: str
|
87
|
-
) -> None: ...
|
88
|
-
|
89
|
-
@overload
|
90
|
-
def __init__(
|
91
|
-
self,
|
92
|
-
*,
|
93
|
-
pool_size: int = 5,
|
94
|
-
max_overflow: int = 10,
|
95
|
-
pool_timeout: float = 30.0,
|
96
|
-
pool_recycle: int | None = None,
|
97
|
-
**query: str
|
98
|
-
) -> None: ...
|
99
|
-
|
100
|
-
|
101
|
-
def __init__(
|
102
|
-
self,
|
103
|
-
host: str | None = None,
|
104
|
-
port: int | str | None = None,
|
105
|
-
username: str | None = None,
|
106
|
-
password: str | None = None,
|
107
|
-
database: str | None = None,
|
108
|
-
pool_size: int = 5,
|
109
|
-
max_overflow: int = 10,
|
110
|
-
pool_timeout: float = 30.0,
|
111
|
-
pool_recycle: int | None = None,
|
112
|
-
**query: str
|
113
50
|
) -> None:
|
114
51
|
"""
|
115
52
|
Build instance attributes.
|
@@ -120,8 +57,7 @@ class Database(DatabaseBase):
|
|
120
57
|
port : Remote server database port.
|
121
58
|
username : Remote server database username.
|
122
59
|
password : Remote server database password.
|
123
|
-
database : Remote server database name
|
124
|
-
- `None`: When parameters `host`, `port`, `username`, `password`, `database` are all `None`, then using memory store.
|
60
|
+
database : Remote server database name.
|
125
61
|
pool_size : Number of connections `keep open`.
|
126
62
|
max_overflow : Number of connections `allowed overflow`.
|
127
63
|
pool_timeout : Number of seconds `wait create` connection.
|
@@ -158,94 +94,12 @@ class Database(DatabaseBase):
|
|
158
94
|
|
159
95
|
# Server recycle time.
|
160
96
|
if pool_recycle is None:
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
self.pool_recycle = int(wait_timeout)
|
97
|
+
wait_timeout = self.variables['wait_timeout']
|
98
|
+
if wait_timeout is not None:
|
99
|
+
self.pool_recycle = int(wait_timeout)
|
165
100
|
self.engine.pool._recycle = self.pool_recycle
|
166
101
|
|
167
102
|
|
168
|
-
@overload
|
169
|
-
def extract_path(
|
170
|
-
self,
|
171
|
-
path: str,
|
172
|
-
main: Literal['table', 'database'] = 'table'
|
173
|
-
) -> tuple[str, str, str | None]: ...
|
174
|
-
|
175
|
-
@overload
|
176
|
-
def extract_path(
|
177
|
-
self,
|
178
|
-
path: tuple[str | None, str | None] | tuple[str | None, str | None, str | None],
|
179
|
-
main: Literal['table', 'database'] = 'table'
|
180
|
-
) -> tuple[str, str | None, str | None]: ...
|
181
|
-
|
182
|
-
def extract_path(
|
183
|
-
self,
|
184
|
-
path: str | tuple[str | None, str | None] | tuple[str | None, str | None, str | None],
|
185
|
-
main: Literal['table', 'database'] = 'table'
|
186
|
-
) -> tuple[str, str | None, str | None]:
|
187
|
-
"""
|
188
|
-
Extract table name and database name and column name from path.
|
189
|
-
|
190
|
-
Parameters
|
191
|
-
----------
|
192
|
-
path : Table name, can contain database name, otherwise use `self.rdatabase.database`.
|
193
|
-
- `str`: Automatic extract database name and table name.
|
194
|
-
Not contain '.' or contain '`': Main name.
|
195
|
-
Contain '.': Database name and table name, column name is optional. Example 'database.table[.column]'.
|
196
|
-
- `tuple[str, str]`: Database name and table name.
|
197
|
-
- `tuple[str, str | None, str | None]`: Database name and table name and column name.
|
198
|
-
path : Automatic extract.
|
199
|
-
main : Priority main name, 'table' or 'database'.
|
200
|
-
|
201
|
-
Returns
|
202
|
-
-------
|
203
|
-
Database name and table name and column name.
|
204
|
-
"""
|
205
|
-
|
206
|
-
# Type str.
|
207
|
-
if type(path) == str:
|
208
|
-
|
209
|
-
## Single.
|
210
|
-
if (
|
211
|
-
'.' not in path
|
212
|
-
or '`' in path
|
213
|
-
):
|
214
|
-
name = path.replace('`', '')
|
215
|
-
match main:
|
216
|
-
case 'table':
|
217
|
-
names = (self.database, name, None)
|
218
|
-
case 'database':
|
219
|
-
names = (name, None, None)
|
220
|
-
case _:
|
221
|
-
throw(ValueError, main)
|
222
|
-
|
223
|
-
## Multiple.
|
224
|
-
else:
|
225
|
-
names = path.split('.', 2)
|
226
|
-
if len(names) == 2:
|
227
|
-
names.append(None)
|
228
|
-
names = tuple(names)
|
229
|
-
|
230
|
-
# Type tuple.
|
231
|
-
else:
|
232
|
-
if len(path) == 2:
|
233
|
-
path += (None,)
|
234
|
-
if path[0] is None:
|
235
|
-
path = (self.database,) + names[1:]
|
236
|
-
names = path
|
237
|
-
|
238
|
-
# SQLite.
|
239
|
-
if self.backend == 'sqlite':
|
240
|
-
names = ('main',) + names[1:]
|
241
|
-
|
242
|
-
# Check.
|
243
|
-
if names[0] is None:
|
244
|
-
throw(ValueError, names)
|
245
|
-
|
246
|
-
return names
|
247
|
-
|
248
|
-
|
249
103
|
@property
|
250
104
|
def backend(self) -> str:
|
251
105
|
"""
|
@@ -280,32 +134,6 @@ class Database(DatabaseBase):
|
|
280
134
|
return driver
|
281
135
|
|
282
136
|
|
283
|
-
@property
|
284
|
-
def mode(self) -> Literal['server', 'file', 'memory']:
|
285
|
-
"""
|
286
|
-
Database store mode.
|
287
|
-
|
288
|
-
Returns
|
289
|
-
-------
|
290
|
-
Mode.
|
291
|
-
"""
|
292
|
-
|
293
|
-
# Judge.
|
294
|
-
if (
|
295
|
-
self.username is not None
|
296
|
-
and self.password is not None
|
297
|
-
and self.host is not None
|
298
|
-
and self.port is not None
|
299
|
-
):
|
300
|
-
value = 'server'
|
301
|
-
elif self.database not in (None, ':memory:'):
|
302
|
-
value = 'file'
|
303
|
-
else:
|
304
|
-
value = 'memory'
|
305
|
-
|
306
|
-
return value
|
307
|
-
|
308
|
-
|
309
137
|
@property
|
310
138
|
def url(self) -> str:
|
311
139
|
"""
|
@@ -317,21 +145,8 @@ class Database(DatabaseBase):
|
|
317
145
|
"""
|
318
146
|
|
319
147
|
# Generate URL.
|
320
|
-
|
321
|
-
|
322
|
-
if self.mode == 'server':
|
323
|
-
password = urllib_quote(self.password)
|
324
|
-
url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}'
|
325
|
-
if self.database is not None:
|
326
|
-
url_ = f'{url_}/{self.database}'
|
327
|
-
|
328
|
-
## File.
|
329
|
-
elif self.mode == 'file':
|
330
|
-
url_ = f'sqlite:///{self.database}'
|
331
|
-
|
332
|
-
## Memory.
|
333
|
-
else:
|
334
|
-
url_ = f'sqlite:///:memory:'
|
148
|
+
password = urllib_quote(self.password)
|
149
|
+
url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
|
335
150
|
|
336
151
|
# Add Server parameter.
|
337
152
|
if self.query != {}:
|
@@ -356,20 +171,14 @@ class Database(DatabaseBase):
|
|
356
171
|
"""
|
357
172
|
|
358
173
|
# Handle parameter.
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
'pool_size': self.pool_size,
|
368
|
-
'max_overflow': self.max_overflow,
|
369
|
-
'pool_timeout': self.pool_timeout,
|
370
|
-
'pool_recycle': self.pool_recycle,
|
371
|
-
'connect_args': {'client_flag': MULTI_STATEMENTS}
|
372
|
-
}
|
174
|
+
engine_params = {
|
175
|
+
'url': self.url,
|
176
|
+
'pool_size': self.pool_size,
|
177
|
+
'max_overflow': self.max_overflow,
|
178
|
+
'pool_timeout': self.pool_timeout,
|
179
|
+
'pool_recycle': self.pool_recycle,
|
180
|
+
'connect_args': {'client_flag': MULTI_STATEMENTS}
|
181
|
+
}
|
373
182
|
|
374
183
|
# Create Engine.
|
375
184
|
engine = sqlalchemy_create_engine(**engine_params)
|
@@ -378,7 +187,7 @@ class Database(DatabaseBase):
|
|
378
187
|
|
379
188
|
|
380
189
|
@property
|
381
|
-
def
|
190
|
+
def count_conn(self) -> tuple[int, int]:
|
382
191
|
"""
|
383
192
|
Count number of keep open and allowed overflow connection.
|
384
193
|
|
@@ -387,1182 +196,18 @@ class Database(DatabaseBase):
|
|
387
196
|
Number of keep open and allowed overflow connection.
|
388
197
|
"""
|
389
198
|
|
390
|
-
# Handle parameter.
|
391
|
-
if hasattr(self, 'engine'):
|
392
|
-
rdatabase = self
|
393
|
-
else:
|
394
|
-
rdatabase: Database = self.rdatabase
|
395
|
-
|
396
199
|
# Count.
|
397
|
-
_overflow =
|
200
|
+
_overflow = self.engine.pool._overflow
|
398
201
|
if _overflow < 0:
|
399
|
-
keep_n =
|
202
|
+
keep_n = self.pool_size + _overflow
|
400
203
|
overflow_n = 0
|
401
204
|
else:
|
402
|
-
keep_n =
|
205
|
+
keep_n = self.pool_size
|
403
206
|
overflow_n = _overflow
|
404
207
|
|
405
208
|
return keep_n, overflow_n
|
406
209
|
|
407
210
|
|
408
|
-
def handle_sql(self, sql: str | TextClause) -> TextClause:
|
409
|
-
"""
|
410
|
-
Handle SQL.
|
411
|
-
|
412
|
-
Parameters
|
413
|
-
----------
|
414
|
-
sql : SQL in method `sqlalchemy.text` format, or TextClause object.
|
415
|
-
|
416
|
-
Returns
|
417
|
-
-------
|
418
|
-
TextClause instance.
|
419
|
-
"""
|
420
|
-
|
421
|
-
# Handle parameter.
|
422
|
-
if type(sql) == TextClause:
|
423
|
-
sql = sql.text
|
424
|
-
|
425
|
-
# Handle.
|
426
|
-
sql = sql.strip()
|
427
|
-
if sql[-1] != ';':
|
428
|
-
sql += ';'
|
429
|
-
sql = sqlalchemy_text(sql)
|
430
|
-
|
431
|
-
return sql
|
432
|
-
|
433
|
-
|
434
|
-
def handle_data(
|
435
|
-
self,
|
436
|
-
data: list[dict],
|
437
|
-
sql: str | TextClause,
|
438
|
-
) -> list[dict]:
|
439
|
-
"""
|
440
|
-
Handle data based on the content of SQL.
|
441
|
-
|
442
|
-
Parameters
|
443
|
-
----------
|
444
|
-
data : Data set for filling.
|
445
|
-
sql : SQL in method `sqlalchemy.text` format, or TextClause object.
|
446
|
-
|
447
|
-
Returns
|
448
|
-
-------
|
449
|
-
Filled data.
|
450
|
-
"""
|
451
|
-
|
452
|
-
# Handle parameter.
|
453
|
-
if type(sql) == TextClause:
|
454
|
-
sql = sql.text
|
455
|
-
|
456
|
-
# Extract keys.
|
457
|
-
pattern = '(?<!\\\\):(\\w+)'
|
458
|
-
sql_keys = findall(pattern, sql)
|
459
|
-
|
460
|
-
# Extract keys of syntax "in".
|
461
|
-
pattern = '[iI][nN]\\s+(?<!\\\\):(\\w+)'
|
462
|
-
sql_keys_in = findall(pattern, sql)
|
463
|
-
|
464
|
-
# Loop.
|
465
|
-
for row in data:
|
466
|
-
if row == {}:
|
467
|
-
continue
|
468
|
-
for key in sql_keys:
|
469
|
-
value = row.get(key)
|
470
|
-
|
471
|
-
# Empty string.
|
472
|
-
if value == '':
|
473
|
-
value = None
|
474
|
-
|
475
|
-
# Convert.
|
476
|
-
elif (
|
477
|
-
type(value) in (list, dict)
|
478
|
-
and key not in sql_keys_in
|
479
|
-
):
|
480
|
-
value = to_json(value)
|
481
|
-
|
482
|
-
# Enum.
|
483
|
-
elif isinstance(type(value), EnumType):
|
484
|
-
value = value.value
|
485
|
-
|
486
|
-
row[key] = value
|
487
|
-
|
488
|
-
return data
|
489
|
-
|
490
|
-
|
491
|
-
def get_syntax(self, sql: str | TextClause) -> list[str]:
|
492
|
-
"""
|
493
|
-
Extract SQL syntax type for each segment form SQL.
|
494
|
-
|
495
|
-
Parameters
|
496
|
-
----------
|
497
|
-
sql : SQL text or TextClause object.
|
498
|
-
|
499
|
-
Returns
|
500
|
-
-------
|
501
|
-
SQL syntax type for each segment.
|
502
|
-
"""
|
503
|
-
|
504
|
-
# Handle parameter.
|
505
|
-
if type(sql) == TextClause:
|
506
|
-
sql = sql.text
|
507
|
-
|
508
|
-
# Extract.
|
509
|
-
syntax = [
|
510
|
-
search('[a-zA-Z]+', sql_part).upper()
|
511
|
-
for sql_part in sql.split(';')
|
512
|
-
if sql_part != ''
|
513
|
-
]
|
514
|
-
|
515
|
-
return syntax
|
516
|
-
|
517
|
-
|
518
|
-
def is_multi_sql(self, sql: str | TextClause) -> bool:
|
519
|
-
"""
|
520
|
-
Judge whether it is multi segment SQL.
|
521
|
-
|
522
|
-
Parameters
|
523
|
-
----------
|
524
|
-
sql : SQL text or TextClause object.
|
525
|
-
|
526
|
-
Returns
|
527
|
-
-------
|
528
|
-
Judgment result.
|
529
|
-
"""
|
530
|
-
|
531
|
-
# Handle parameter.
|
532
|
-
if type(sql) == TextClause:
|
533
|
-
sql = sql.text
|
534
|
-
|
535
|
-
# Judge.
|
536
|
-
if ';' in sql.rstrip()[:-1]:
|
537
|
-
return True
|
538
|
-
return False
|
539
|
-
|
540
|
-
|
541
|
-
def executor_report(
|
542
|
-
self,
|
543
|
-
connection: Connection,
|
544
|
-
sql: TextClause,
|
545
|
-
data: list[dict]
|
546
|
-
) -> Result:
|
547
|
-
"""
|
548
|
-
SQL executor and report SQL execute information
|
549
|
-
|
550
|
-
Parameters
|
551
|
-
----------
|
552
|
-
connection : Connection object.
|
553
|
-
sql : TextClause object.
|
554
|
-
data : Data set for filling.
|
555
|
-
|
556
|
-
Returns
|
557
|
-
-------
|
558
|
-
Result object.
|
559
|
-
"""
|
560
|
-
|
561
|
-
# Execute.
|
562
|
-
execute = wrap_runtime(connection.execute, to_return=True)
|
563
|
-
result, report_runtime, *_ = execute(sql, data)
|
564
|
-
|
565
|
-
# Report.
|
566
|
-
report_info = (
|
567
|
-
f'{report_runtime}\n'
|
568
|
-
f'Row Count: {result.rowcount}'
|
569
|
-
)
|
570
|
-
sqls = [
|
571
|
-
sql_part.strip()
|
572
|
-
for sql_part in sql.text.split(';')
|
573
|
-
if sql_part != ''
|
574
|
-
]
|
575
|
-
if data == []:
|
576
|
-
echo(report_info, *sqls, title='SQL')
|
577
|
-
else:
|
578
|
-
echo(report_info, *sqls, data, title='SQL')
|
579
|
-
|
580
|
-
return result
|
581
|
-
|
582
|
-
|
583
|
-
def executor(
|
584
|
-
self,
|
585
|
-
sql: TextClause,
|
586
|
-
data: list[dict],
|
587
|
-
report: bool
|
588
|
-
) -> Result:
|
589
|
-
"""
|
590
|
-
SQL executor.
|
591
|
-
|
592
|
-
Parameters
|
593
|
-
----------
|
594
|
-
sql : TextClause object.
|
595
|
-
data : Data set for filling.
|
596
|
-
report : Whether report SQL execute information.
|
597
|
-
|
598
|
-
Returns
|
599
|
-
-------
|
600
|
-
Result object.
|
601
|
-
"""
|
602
|
-
|
603
|
-
# Create connection.
|
604
|
-
with self.engine.connect() as connection:
|
605
|
-
|
606
|
-
# Create transaction.
|
607
|
-
with connection.begin():
|
608
|
-
|
609
|
-
# Execute.
|
610
|
-
|
611
|
-
## Report.
|
612
|
-
if report:
|
613
|
-
result = self.executor_report(connection, sql, data)
|
614
|
-
|
615
|
-
## Not report.
|
616
|
-
else:
|
617
|
-
result = connection.execute(sql, data)
|
618
|
-
|
619
|
-
return result
|
620
|
-
|
621
|
-
|
622
|
-
def execute(
|
623
|
-
self,
|
624
|
-
sql: str | TextClause,
|
625
|
-
data: TableData | None = None,
|
626
|
-
report: bool | None = None,
|
627
|
-
**kwdata: Any
|
628
|
-
) -> Result:
|
629
|
-
"""
|
630
|
-
Execute SQL.
|
631
|
-
|
632
|
-
Parameters
|
633
|
-
----------
|
634
|
-
sql : SQL in method `sqlalchemy.text` format, or `TextClause` object.
|
635
|
-
data : Data set for filling.
|
636
|
-
report : Whether report SQL execute information.
|
637
|
-
- `None`: Use attribute `default_report`.
|
638
|
-
- `bool`: Use this value.
|
639
|
-
kwdata : Keyword parameters for filling.
|
640
|
-
|
641
|
-
Returns
|
642
|
-
-------
|
643
|
-
Result object.
|
644
|
-
"""
|
645
|
-
|
646
|
-
# Handle parameter by priority.
|
647
|
-
report = get_first_notnone(report, self.default_report)
|
648
|
-
|
649
|
-
# Handle parameter.
|
650
|
-
sql = self.handle_sql(sql)
|
651
|
-
if data is None:
|
652
|
-
if kwdata == {}:
|
653
|
-
data = []
|
654
|
-
else:
|
655
|
-
data = [kwdata]
|
656
|
-
else:
|
657
|
-
data_table = Table(data)
|
658
|
-
data = data_table.to_table()
|
659
|
-
for row in data:
|
660
|
-
row.update(kwdata)
|
661
|
-
data = self.handle_data(data, sql)
|
662
|
-
|
663
|
-
# Execute.
|
664
|
-
result = self.executor(sql, data, report)
|
665
|
-
|
666
|
-
return result
|
667
|
-
|
668
|
-
|
669
|
-
def execute_select(
|
670
|
-
self,
|
671
|
-
path: str | tuple[str, str],
|
672
|
-
fields: str | Iterable[str] | None = None,
|
673
|
-
where: str | None = None,
|
674
|
-
group: str | None = None,
|
675
|
-
having: str | None = None,
|
676
|
-
order: str | None = None,
|
677
|
-
limit: int | str | tuple[int, int] | None = None,
|
678
|
-
report: bool | None = None,
|
679
|
-
**kwdata: Any
|
680
|
-
) -> Result:
|
681
|
-
"""
|
682
|
-
Execute select SQL.
|
683
|
-
|
684
|
-
Parameters
|
685
|
-
----------
|
686
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
687
|
-
- `str`: Automatic extract database name and table name.
|
688
|
-
- `tuple[str, str]`: Database name and table name.
|
689
|
-
fields : Select clause content.
|
690
|
-
- `None`: Is `SELECT *`.
|
691
|
-
- `str`: Join as `SELECT str`.
|
692
|
-
- `Iterable[str]`, Join as `SELECT ``str``: ...`.
|
693
|
-
`str and first character is ':'`: Use this syntax.
|
694
|
-
`str`: Use this field.
|
695
|
-
where : Clause `WHERE` content, join as `WHERE str`.
|
696
|
-
group : Clause `GROUP BY` content, join as `GROUP BY str`.
|
697
|
-
having : Clause `HAVING` content, join as `HAVING str`.
|
698
|
-
order : Clause `ORDER BY` content, join as `ORDER BY str`.
|
699
|
-
limit : Clause `LIMIT` content.
|
700
|
-
- `int | str`: Join as `LIMIT int/str`.
|
701
|
-
- `tuple[int, int]`: Join as `LIMIT int, int`.
|
702
|
-
report : Whether report SQL execute information.
|
703
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
704
|
-
- `int`: Use this value.
|
705
|
-
kwdata : Keyword parameters for filling.
|
706
|
-
|
707
|
-
Returns
|
708
|
-
-------
|
709
|
-
Result object.
|
710
|
-
|
711
|
-
Examples
|
712
|
-
--------
|
713
|
-
Parameter `fields`.
|
714
|
-
>>> fields = ['id', ':`id` + 1 AS `id_`']
|
715
|
-
>>> result = Database.execute_select('database.table', fields)
|
716
|
-
>>> print(result.to_table())
|
717
|
-
[{'id': 1, 'id_': 2}, ...]
|
718
|
-
|
719
|
-
Parameter `kwdata`.
|
720
|
-
>>> fields = '`id`, `id` + :value AS `id_`'
|
721
|
-
>>> result = Database.execute_select('database.table', fields, value=1)
|
722
|
-
>>> print(result.to_table())
|
723
|
-
[{'id': 1, 'id_': 2}, ...]
|
724
|
-
"""
|
725
|
-
|
726
|
-
# Handle parameter.
|
727
|
-
database, table, _ = self.extract_path(path)
|
728
|
-
|
729
|
-
# Generate SQL.
|
730
|
-
sql_list = []
|
731
|
-
|
732
|
-
## Part 'SELECT' syntax.
|
733
|
-
if fields is None:
|
734
|
-
fields = '*'
|
735
|
-
elif type(fields) != str:
|
736
|
-
fields = ', '.join(
|
737
|
-
[
|
738
|
-
field[1:]
|
739
|
-
if (
|
740
|
-
field.startswith(':')
|
741
|
-
and field != ':'
|
742
|
-
)
|
743
|
-
else f'`{field}`'
|
744
|
-
for field in fields
|
745
|
-
]
|
746
|
-
)
|
747
|
-
sql_select = f'SELECT {fields}'
|
748
|
-
sql_list.append(sql_select)
|
749
|
-
|
750
|
-
## Part 'FROM' syntax.
|
751
|
-
sql_from = f'FROM `{database}`.`{table}`'
|
752
|
-
sql_list.append(sql_from)
|
753
|
-
|
754
|
-
## Part 'WHERE' syntax.
|
755
|
-
if where is not None:
|
756
|
-
sql_where = f'WHERE {where}'
|
757
|
-
sql_list.append(sql_where)
|
758
|
-
|
759
|
-
## Part 'GROUP BY' syntax.
|
760
|
-
if group is not None:
|
761
|
-
sql_group = f'GROUP BY {group}'
|
762
|
-
sql_list.append(sql_group)
|
763
|
-
|
764
|
-
## Part 'GROUP BY' syntax.
|
765
|
-
if having is not None:
|
766
|
-
sql_having = f'HAVING {having}'
|
767
|
-
sql_list.append(sql_having)
|
768
|
-
|
769
|
-
## Part 'ORDER BY' syntax.
|
770
|
-
if order is not None:
|
771
|
-
sql_order = f'ORDER BY {order}'
|
772
|
-
sql_list.append(sql_order)
|
773
|
-
|
774
|
-
## Part 'LIMIT' syntax.
|
775
|
-
if limit is not None:
|
776
|
-
if type(limit) in (str, int):
|
777
|
-
sql_limit = f'LIMIT {limit}'
|
778
|
-
else:
|
779
|
-
if len(limit) == 2:
|
780
|
-
sql_limit = f'LIMIT {limit[0]}, {limit[1]}'
|
781
|
-
else:
|
782
|
-
throw(ValueError, limit)
|
783
|
-
sql_list.append(sql_limit)
|
784
|
-
|
785
|
-
## Join sql part.
|
786
|
-
sql = '\n'.join(sql_list)
|
787
|
-
|
788
|
-
# Execute SQL.
|
789
|
-
result = self.execute(sql, report=report, **kwdata)
|
790
|
-
|
791
|
-
return result
|
792
|
-
|
793
|
-
|
794
|
-
def execute_insert(
|
795
|
-
self,
|
796
|
-
path: str | tuple[str, str],
|
797
|
-
data: TableData,
|
798
|
-
duplicate: Literal['ignore', 'update'] | Container[str] | None = None,
|
799
|
-
report: bool | None = None,
|
800
|
-
**kwdata: Any
|
801
|
-
) -> Result:
|
802
|
-
"""
|
803
|
-
Insert the data of table in the datebase.
|
804
|
-
|
805
|
-
Parameters
|
806
|
-
----------
|
807
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
808
|
-
- `str`: Automatic extract database name and table name.
|
809
|
-
- `tuple[str, str]`: Database name and table name.
|
810
|
-
data : Insert data.
|
811
|
-
duplicate : Handle method when constraint error.
|
812
|
-
- `None`: Not handled.
|
813
|
-
- `ignore`: Use `UPDATE IGNORE INTO` clause.
|
814
|
-
- `update`: Use `ON DUPLICATE KEY UPDATE` clause and update all fields.
|
815
|
-
- `Container[str]`: Use `ON DUPLICATE KEY UPDATE` clause and update this fields.
|
816
|
-
report : Whether report SQL execute information.
|
817
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
818
|
-
- `int`: Use this value.
|
819
|
-
kwdata : Keyword parameters for filling.
|
820
|
-
- `str and first character is ':'`: Use this syntax.
|
821
|
-
- `Any`: Use this value.
|
822
|
-
|
823
|
-
Returns
|
824
|
-
-------
|
825
|
-
Result object.
|
826
|
-
|
827
|
-
Examples
|
828
|
-
--------
|
829
|
-
Parameter `data` and `kwdata`.
|
830
|
-
>>> data = [{'key': 'a'}, {'key': 'b'}]
|
831
|
-
>>> kwdata = {'value1': 1, 'value2': ':(SELECT 2)'}
|
832
|
-
>>> result = Database.execute_insert('database.table', data, **kwdata)
|
833
|
-
>>> print(result.rowcount)
|
834
|
-
2
|
835
|
-
>>> result = Database.execute_select('database.table')
|
836
|
-
>>> print(result.to_table())
|
837
|
-
[{'key': 'a', 'value1': 1, 'value2': 2}, {'key': 'b', 'value1': 1, 'value2': 2}]
|
838
|
-
"""
|
839
|
-
|
840
|
-
# Handle parameter.
|
841
|
-
database, table, _ = self.extract_path(path)
|
842
|
-
|
843
|
-
# Handle parameter.
|
844
|
-
|
845
|
-
## Data.
|
846
|
-
data_table = Table(data)
|
847
|
-
data = data_table.to_table()
|
848
|
-
|
849
|
-
## Check.
|
850
|
-
if data in ([], [{}]):
|
851
|
-
throw(ValueError, data)
|
852
|
-
|
853
|
-
## Keyword data.
|
854
|
-
kwdata_method = {}
|
855
|
-
kwdata_replace = {}
|
856
|
-
for key, value in kwdata.items():
|
857
|
-
if (
|
858
|
-
type(value) == str
|
859
|
-
and value.startswith(':')
|
860
|
-
and value != ':'
|
861
|
-
):
|
862
|
-
kwdata_method[key] = value[1:]
|
863
|
-
else:
|
864
|
-
kwdata_replace[key] = value
|
865
|
-
|
866
|
-
# Generate SQL.
|
867
|
-
|
868
|
-
## Part 'fields' syntax.
|
869
|
-
fields_replace = {
|
870
|
-
field
|
871
|
-
for row in data
|
872
|
-
for field in row
|
873
|
-
}
|
874
|
-
fields_replace = {
|
875
|
-
field
|
876
|
-
for field in fields_replace
|
877
|
-
if field not in kwdata
|
878
|
-
}
|
879
|
-
sql_fields_list = (
|
880
|
-
*kwdata_method,
|
881
|
-
*kwdata_replace,
|
882
|
-
*fields_replace
|
883
|
-
)
|
884
|
-
sql_fields = ', '.join(
|
885
|
-
[
|
886
|
-
f'`{field}`'
|
887
|
-
for field in sql_fields_list
|
888
|
-
]
|
889
|
-
)
|
890
|
-
|
891
|
-
## Part 'values' syntax.
|
892
|
-
sql_values_list = (
|
893
|
-
*kwdata_method.values(),
|
894
|
-
*[
|
895
|
-
':' + field
|
896
|
-
for field in (
|
897
|
-
*kwdata_replace,
|
898
|
-
*fields_replace
|
899
|
-
)
|
900
|
-
]
|
901
|
-
)
|
902
|
-
sql_values = ', '.join(sql_values_list)
|
903
|
-
|
904
|
-
## Join sql part.
|
905
|
-
match duplicate:
|
906
|
-
|
907
|
-
### Not handle.
|
908
|
-
case None:
|
909
|
-
sql = (
|
910
|
-
f'INSERT INTO `{database}`.`{table}`({sql_fields})\n'
|
911
|
-
f'VALUES({sql_values})'
|
912
|
-
)
|
913
|
-
|
914
|
-
### Ignore.
|
915
|
-
case 'ignore':
|
916
|
-
sql = (
|
917
|
-
f'INSERT IGNORE INTO `{database}`.`{table}`({sql_fields})\n'
|
918
|
-
f'VALUES({sql_values})'
|
919
|
-
)
|
920
|
-
|
921
|
-
### Update.
|
922
|
-
case _:
|
923
|
-
sql_fields_list_update = sql_fields_list
|
924
|
-
if duplicate != 'update':
|
925
|
-
sql_fields_list_update = [
|
926
|
-
field
|
927
|
-
for field in sql_fields_list
|
928
|
-
if field in duplicate
|
929
|
-
]
|
930
|
-
update_content = ',\n '.join(
|
931
|
-
[
|
932
|
-
f'`{field}` = VALUES(`{field}`)'
|
933
|
-
for field in sql_fields_list_update
|
934
|
-
]
|
935
|
-
)
|
936
|
-
sql = (
|
937
|
-
f'INSERT INTO `{database}`.`{table}`({sql_fields})\n'
|
938
|
-
f'VALUES({sql_values})\n'
|
939
|
-
'ON DUPLICATE KEY UPDATE\n'
|
940
|
-
f' {update_content}'
|
941
|
-
)
|
942
|
-
|
943
|
-
# Execute SQL.
|
944
|
-
result = self.execute(sql, data, report, **kwdata_replace)
|
945
|
-
|
946
|
-
return result
|
947
|
-
|
948
|
-
|
949
|
-
def execute_update(
|
950
|
-
self,
|
951
|
-
path: str | tuple[str, str],
|
952
|
-
data: TableData,
|
953
|
-
where_fields: str | Iterable[str] | None = None,
|
954
|
-
report: bool | None = None,
|
955
|
-
**kwdata: Any
|
956
|
-
) -> Result:
|
957
|
-
"""
|
958
|
-
Update the data of table in the datebase.
|
959
|
-
|
960
|
-
Parameters
|
961
|
-
----------
|
962
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
963
|
-
- `str`: Automatic extract database name and table name.
|
964
|
-
- `tuple[str, str]`: Database name and table name.
|
965
|
-
data : Update data, clause `SET` and `WHERE` and `ORDER BY` and `LIMIT` content.
|
966
|
-
- `Key`: Table field.
|
967
|
-
`literal['order']`: Clause `ORDER BY` content, join as `ORDER BY str`.
|
968
|
-
`literal['limit']`: Clause `LIMIT` content, join as `LIMIT str`.
|
969
|
-
`Other`: Clause `SET` and `WHERE` content.
|
970
|
-
- `Value`: Table value.
|
971
|
-
`list | tuple`: Join as `field IN :str`.
|
972
|
-
`Any`: Join as `field = :str`.
|
973
|
-
where_fields : Clause `WHERE` content fields.
|
974
|
-
- `None`: The first key value pair of each item is judged.
|
975
|
-
- `str`: This key value pair of each item is judged.
|
976
|
-
- `Iterable[str]`: Multiple judged, `and`: relationship.
|
977
|
-
report : Whether report SQL execute information.
|
978
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
979
|
-
- `int`: Use this value.
|
980
|
-
kwdata : Keyword parameters for filling.
|
981
|
-
- `str and first character is ':'`: Use this syntax.
|
982
|
-
- `Any`: Use this value.
|
983
|
-
|
984
|
-
Returns
|
985
|
-
-------
|
986
|
-
Result object.
|
987
|
-
|
988
|
-
Examples
|
989
|
-
--------
|
990
|
-
Parameter `data` and `kwdata`.
|
991
|
-
>>> data = [{'key': 'a'}, {'key': 'b'}]
|
992
|
-
>>> kwdata = {'value': 1, 'name': ':`key`'}
|
993
|
-
>>> result = Database.execute_update('database.table', data, **kwdata)
|
994
|
-
>>> print(result.rowcount)
|
995
|
-
2
|
996
|
-
>>> result = Database.execute_select('database.table')
|
997
|
-
>>> print(result.to_table())
|
998
|
-
[{'key': 'a', 'value': 1, 'name': 'a'}, {'key': 'b', 'value': 1, 'name': 'b'}]
|
999
|
-
"""
|
1000
|
-
|
1001
|
-
# Handle parameter.
|
1002
|
-
database, table, _ = self.extract_path(path)
|
1003
|
-
|
1004
|
-
# Handle parameter.
|
1005
|
-
|
1006
|
-
## Data.
|
1007
|
-
data_table = Table(data)
|
1008
|
-
data = data_table.to_table()
|
1009
|
-
|
1010
|
-
## Check.
|
1011
|
-
if data in ([], [{}]):
|
1012
|
-
throw(ValueError, data)
|
1013
|
-
|
1014
|
-
## Keyword data.
|
1015
|
-
kwdata_method = {}
|
1016
|
-
kwdata_replace = {}
|
1017
|
-
for key, value in kwdata.items():
|
1018
|
-
if (
|
1019
|
-
type(value) == str
|
1020
|
-
and value.startswith(':')
|
1021
|
-
and value != ':'
|
1022
|
-
):
|
1023
|
-
kwdata_method[key] = value[1:]
|
1024
|
-
else:
|
1025
|
-
kwdata_replace[key] = value
|
1026
|
-
sql_set_list_kwdata = [
|
1027
|
-
f'`{key}` = {value}'
|
1028
|
-
for key, value in kwdata_method.items()
|
1029
|
-
]
|
1030
|
-
sql_set_list_kwdata.extend(
|
1031
|
-
[
|
1032
|
-
f'`{key}` = :{key}'
|
1033
|
-
for key in kwdata_replace
|
1034
|
-
]
|
1035
|
-
)
|
1036
|
-
|
1037
|
-
# Generate SQL.
|
1038
|
-
data_flatten = kwdata_replace
|
1039
|
-
if where_fields is None:
|
1040
|
-
no_where = True
|
1041
|
-
else:
|
1042
|
-
no_where = False
|
1043
|
-
if type(where_fields) == str:
|
1044
|
-
where_fields = [where_fields]
|
1045
|
-
sqls_list = []
|
1046
|
-
sql_update = f'UPDATE `{database}`.`{table}`'
|
1047
|
-
for index, row in enumerate(data):
|
1048
|
-
sql_parts = [sql_update]
|
1049
|
-
for key, value in row.items():
|
1050
|
-
if key in ('order', 'limit'):
|
1051
|
-
continue
|
1052
|
-
index_key = f'{index}_{key}'
|
1053
|
-
data_flatten[index_key] = value
|
1054
|
-
if no_where:
|
1055
|
-
for key in row:
|
1056
|
-
where_fields = [key]
|
1057
|
-
break
|
1058
|
-
|
1059
|
-
## Part 'SET' syntax.
|
1060
|
-
sql_set_list = sql_set_list_kwdata.copy()
|
1061
|
-
sql_set_list.extend(
|
1062
|
-
[
|
1063
|
-
f'`{key}` = :{index}_{key}'
|
1064
|
-
for key in row
|
1065
|
-
if (
|
1066
|
-
key not in where_fields
|
1067
|
-
and key not in kwdata
|
1068
|
-
and key not in ('order', 'limit')
|
1069
|
-
)
|
1070
|
-
]
|
1071
|
-
)
|
1072
|
-
sql_set = 'SET ' + ',\n '.join(sql_set_list)
|
1073
|
-
sql_parts.append(sql_set)
|
1074
|
-
|
1075
|
-
## Part 'WHERE' syntax.
|
1076
|
-
sql_where_list = []
|
1077
|
-
for field in where_fields:
|
1078
|
-
index_field = f'{index}_{field}'
|
1079
|
-
index_value = data_flatten[index_field]
|
1080
|
-
if type(index_value) in (list, tuple):
|
1081
|
-
sql_where_part = f'`{field}` IN :{index_field}'
|
1082
|
-
else:
|
1083
|
-
sql_where_part = f'`{field}` = :{index_field}'
|
1084
|
-
sql_where_list.append(sql_where_part)
|
1085
|
-
sql_where = 'WHERE ' + '\n AND '.join(sql_where_list)
|
1086
|
-
sql_parts.append(sql_where)
|
1087
|
-
|
1088
|
-
## Part 'ORDER BY' syntax.
|
1089
|
-
order = row.get('order')
|
1090
|
-
if order is not None:
|
1091
|
-
sql_order = f'ORDER BY {order}'
|
1092
|
-
sql_parts.append(sql_order)
|
1093
|
-
|
1094
|
-
## Part 'LIMIT' syntax.
|
1095
|
-
limit = row.get('limit')
|
1096
|
-
if limit is not None:
|
1097
|
-
sql_limit = f'LIMIT {limit}'
|
1098
|
-
sql_parts.append(sql_limit)
|
1099
|
-
|
1100
|
-
## Join sql part.
|
1101
|
-
sql = '\n'.join(sql_parts)
|
1102
|
-
sqls_list.append(sql)
|
1103
|
-
|
1104
|
-
## Join sqls.
|
1105
|
-
sqls = ';\n'.join(sqls_list)
|
1106
|
-
|
1107
|
-
# Execute SQL.
|
1108
|
-
result = self.execute(sqls, data_flatten, report)
|
1109
|
-
|
1110
|
-
return result
|
1111
|
-
|
1112
|
-
|
1113
|
-
def execute_delete(
|
1114
|
-
self,
|
1115
|
-
path: str | tuple[str, str],
|
1116
|
-
where: str | None = None,
|
1117
|
-
order: str | None = None,
|
1118
|
-
limit: int | str | None = None,
|
1119
|
-
report: bool | None = None,
|
1120
|
-
**kwdata: Any
|
1121
|
-
) -> Result:
|
1122
|
-
"""
|
1123
|
-
Delete the data of table in the datebase.
|
1124
|
-
|
1125
|
-
Parameters
|
1126
|
-
----------
|
1127
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
1128
|
-
- `str`: Automatic extract database name and table name.
|
1129
|
-
- `tuple[str, str]`: Database name and table name.
|
1130
|
-
where : Clause `WHERE` content, join as `WHERE str`.
|
1131
|
-
order : Clause `ORDER BY` content, join as `ORDER BY str`.
|
1132
|
-
limit : Clause `LIMIT` content, join as `LIMIT int/str`.
|
1133
|
-
report : Whether report SQL execute information.
|
1134
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
1135
|
-
- `int`: Use this value.
|
1136
|
-
kwdata : Keyword parameters for filling.
|
1137
|
-
|
1138
|
-
Returns
|
1139
|
-
-------
|
1140
|
-
Result object.
|
1141
|
-
|
1142
|
-
Examples
|
1143
|
-
--------
|
1144
|
-
Parameter `where` and `kwdata`.
|
1145
|
-
>>> where = '`id` IN :ids'
|
1146
|
-
>>> ids = (1, 2)
|
1147
|
-
>>> result = Database.execute_delete('database.table', where, ids=ids)
|
1148
|
-
>>> print(result.rowcount)
|
1149
|
-
2
|
1150
|
-
"""
|
1151
|
-
|
1152
|
-
# Handle parameter.
|
1153
|
-
database, table, _ = self.extract_path(path)
|
1154
|
-
|
1155
|
-
# Generate SQL.
|
1156
|
-
sqls = []
|
1157
|
-
|
1158
|
-
## Part 'DELETE' syntax.
|
1159
|
-
sql_delete = f'DELETE FROM `{database}`.`{table}`'
|
1160
|
-
sqls.append(sql_delete)
|
1161
|
-
|
1162
|
-
## Part 'WHERE' syntax.
|
1163
|
-
if where is not None:
|
1164
|
-
sql_where = f'WHERE {where}'
|
1165
|
-
sqls.append(sql_where)
|
1166
|
-
|
1167
|
-
## Part 'ORDER BY' syntax.
|
1168
|
-
if order is not None:
|
1169
|
-
sql_order = f'ORDER BY {order}'
|
1170
|
-
sqls.append(sql_order)
|
1171
|
-
|
1172
|
-
## Part 'LIMIT' syntax.
|
1173
|
-
if limit is not None:
|
1174
|
-
sql_limit = f'LIMIT {limit}'
|
1175
|
-
sqls.append(sql_limit)
|
1176
|
-
|
1177
|
-
## Join sqls.
|
1178
|
-
sqls = '\n'.join(sqls)
|
1179
|
-
|
1180
|
-
# Execute SQL.
|
1181
|
-
result = self.execute(sqls, report=report, **kwdata)
|
1182
|
-
|
1183
|
-
return result
|
1184
|
-
|
1185
|
-
|
1186
|
-
def execute_copy(
|
1187
|
-
self,
|
1188
|
-
path: str | tuple[str, str],
|
1189
|
-
where: str | None = None,
|
1190
|
-
limit: int | str | tuple[int, int] | None = None,
|
1191
|
-
report: bool | None = None,
|
1192
|
-
**kwdata: Any
|
1193
|
-
) -> Result:
|
1194
|
-
"""
|
1195
|
-
Copy record of table in the datebase.
|
1196
|
-
|
1197
|
-
Parameters
|
1198
|
-
----------
|
1199
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
1200
|
-
- `str`: Automatic extract database name and table name.
|
1201
|
-
- `tuple[str, str]`: Database name and table name.
|
1202
|
-
where : Clause `WHERE` content, join as `WHERE str`.
|
1203
|
-
limit : Clause `LIMIT` content.
|
1204
|
-
- `int | str`: Join as `LIMIT int/str`.
|
1205
|
-
- `tuple[int, int]`: Join as `LIMIT int, int`.
|
1206
|
-
report : Whether report SQL execute information.
|
1207
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
1208
|
-
- `int`: Use this value.
|
1209
|
-
kwdata : Keyword parameters for filling.
|
1210
|
-
- `In 'WHERE' syntax`: Fill 'WHERE' syntax.
|
1211
|
-
- `Not in 'WHERE' syntax`: Fill 'INSERT' and 'SELECT' syntax.
|
1212
|
-
`str and first character is ':'`: Use this syntax.
|
1213
|
-
`Any`: Use this value.
|
1214
|
-
|
1215
|
-
Returns
|
1216
|
-
-------
|
1217
|
-
Result object.
|
1218
|
-
|
1219
|
-
Examples
|
1220
|
-
--------
|
1221
|
-
Parameter `where` and `kwdata`.
|
1222
|
-
>>> where = '`id` IN :ids'
|
1223
|
-
>>> ids = (1, 2, 3)
|
1224
|
-
>>> result = Database.execute_copy('database.table', where, 2, ids=ids, id=None, time=':NOW()')
|
1225
|
-
>>> print(result.rowcount)
|
1226
|
-
2
|
1227
|
-
"""
|
1228
|
-
|
1229
|
-
# Handle parameter.
|
1230
|
-
database, table, _ = self.extract_path(path)
|
1231
|
-
table_info: list[dict] = self.info(database)(table)()
|
1232
|
-
|
1233
|
-
## SQLite.
|
1234
|
-
if self.backend == 'sqlite':
|
1235
|
-
field_key = 'name'
|
1236
|
-
|
1237
|
-
## Other.
|
1238
|
-
else:
|
1239
|
-
field_key = 'COLUMN_NAME'
|
1240
|
-
|
1241
|
-
fields = [
|
1242
|
-
row[field_key]
|
1243
|
-
for row in table_info
|
1244
|
-
]
|
1245
|
-
pattern = '(?<!\\\\):(\\w+)'
|
1246
|
-
if type(where) == str:
|
1247
|
-
where_keys = findall(pattern, where)
|
1248
|
-
else:
|
1249
|
-
where_keys = ()
|
1250
|
-
|
1251
|
-
# Generate SQL.
|
1252
|
-
sqls = []
|
1253
|
-
|
1254
|
-
## Part 'INSERT' syntax.
|
1255
|
-
sql_fields = ', '.join(
|
1256
|
-
f'`{field}`'
|
1257
|
-
for field in fields
|
1258
|
-
if field not in kwdata
|
1259
|
-
)
|
1260
|
-
if kwdata != {}:
|
1261
|
-
sql_fields_kwdata = ', '.join(
|
1262
|
-
f'`{field}`'
|
1263
|
-
for field in kwdata
|
1264
|
-
if field not in where_keys
|
1265
|
-
)
|
1266
|
-
sql_fields_filter = filter(
|
1267
|
-
lambda sql: sql != '',
|
1268
|
-
(
|
1269
|
-
sql_fields,
|
1270
|
-
sql_fields_kwdata
|
1271
|
-
)
|
1272
|
-
)
|
1273
|
-
sql_fields = ', '.join(sql_fields_filter)
|
1274
|
-
sql_insert = f'INSERT INTO `{database}`.`{table}`({sql_fields})'
|
1275
|
-
sqls.append(sql_insert)
|
1276
|
-
|
1277
|
-
## Part 'SELECT' syntax.
|
1278
|
-
sql_values = ', '.join(
|
1279
|
-
f'`{field}`'
|
1280
|
-
for field in fields
|
1281
|
-
if field not in kwdata
|
1282
|
-
)
|
1283
|
-
if kwdata != {}:
|
1284
|
-
sql_values_kwdata = ', '.join(
|
1285
|
-
value[1:]
|
1286
|
-
if (
|
1287
|
-
type(value) == str
|
1288
|
-
and value.startswith(':')
|
1289
|
-
and value != ':'
|
1290
|
-
)
|
1291
|
-
else f':{field}'
|
1292
|
-
for field, value in kwdata.items()
|
1293
|
-
if field not in where_keys
|
1294
|
-
)
|
1295
|
-
sql_values_filter = filter(
|
1296
|
-
lambda sql: sql != '',
|
1297
|
-
(
|
1298
|
-
sql_values,
|
1299
|
-
sql_values_kwdata
|
1300
|
-
)
|
1301
|
-
)
|
1302
|
-
sql_values = ', '.join(sql_values_filter)
|
1303
|
-
sql_select = (
|
1304
|
-
f'SELECT {sql_values}\n'
|
1305
|
-
f'FROM `{database}`.`{table}`'
|
1306
|
-
)
|
1307
|
-
sqls.append(sql_select)
|
1308
|
-
|
1309
|
-
## Part 'WHERE' syntax.
|
1310
|
-
if where is not None:
|
1311
|
-
sql_where = f'WHERE {where}'
|
1312
|
-
sqls.append(sql_where)
|
1313
|
-
|
1314
|
-
## Part 'LIMIT' syntax.
|
1315
|
-
if limit is not None:
|
1316
|
-
if type(limit) in (str, int):
|
1317
|
-
sql_limit = f'LIMIT {limit}'
|
1318
|
-
else:
|
1319
|
-
if len(limit) == 2:
|
1320
|
-
sql_limit = f'LIMIT {limit[0]}, {limit[1]}'
|
1321
|
-
else:
|
1322
|
-
throw(ValueError, limit)
|
1323
|
-
sqls.append(sql_limit)
|
1324
|
-
|
1325
|
-
## Join.
|
1326
|
-
sql = '\n'.join(sqls)
|
1327
|
-
|
1328
|
-
# Execute SQL.
|
1329
|
-
result = self.execute(sql, report=report, **kwdata)
|
1330
|
-
|
1331
|
-
return result
|
1332
|
-
|
1333
|
-
|
1334
|
-
def execute_count(
|
1335
|
-
self,
|
1336
|
-
path: str | tuple[str, str],
|
1337
|
-
where: str | None = None,
|
1338
|
-
report: bool | None = None,
|
1339
|
-
**kwdata: Any
|
1340
|
-
) -> int:
|
1341
|
-
"""
|
1342
|
-
Count records.
|
1343
|
-
|
1344
|
-
Parameters
|
1345
|
-
----------
|
1346
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
1347
|
-
- `str`: Automatic extract database name and table name.
|
1348
|
-
- `tuple[str, str]`: Database name and table name.
|
1349
|
-
where : Match condition, `WHERE` clause content, join as `WHERE str`.
|
1350
|
-
- `None`: Match all.
|
1351
|
-
- `str`: Match condition.
|
1352
|
-
report : Whether report SQL execute information.
|
1353
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
1354
|
-
- `int`: Use this value.
|
1355
|
-
kwdata : Keyword parameters for filling.
|
1356
|
-
|
1357
|
-
Returns
|
1358
|
-
-------
|
1359
|
-
Record count.
|
1360
|
-
|
1361
|
-
Examples
|
1362
|
-
--------
|
1363
|
-
Parameter `where` and `kwdata`.
|
1364
|
-
>>> where = '`id` IN :ids'
|
1365
|
-
>>> ids = (1, 2)
|
1366
|
-
>>> result = Database.execute_count('database.table', where, ids=ids)
|
1367
|
-
>>> print(result)
|
1368
|
-
2
|
1369
|
-
"""
|
1370
|
-
|
1371
|
-
# Handle parameter.
|
1372
|
-
database, table, _ = self.extract_path(path)
|
1373
|
-
|
1374
|
-
# Execute.
|
1375
|
-
result = self.execute_select((database, table), '1', where=where, report=report, **kwdata)
|
1376
|
-
count = len(tuple(result))
|
1377
|
-
|
1378
|
-
return count
|
1379
|
-
|
1380
|
-
|
1381
|
-
def execute_exist(
|
1382
|
-
self,
|
1383
|
-
path: str | tuple[str, str],
|
1384
|
-
where: str | None = None,
|
1385
|
-
report: bool | None = None,
|
1386
|
-
**kwdata: Any
|
1387
|
-
) -> bool:
|
1388
|
-
"""
|
1389
|
-
Judge the exist of record.
|
1390
|
-
|
1391
|
-
Parameters
|
1392
|
-
----------
|
1393
|
-
path : Table name, can contain database name, otherwise use `self.database`.
|
1394
|
-
- `str`: Automatic extract database name and table name.
|
1395
|
-
- `tuple[str, str]`: Database name and table name.
|
1396
|
-
where : Match condition, `WHERE` clause content, join as `WHERE str`.
|
1397
|
-
- `None`: Match all.
|
1398
|
-
- `str`: Match condition.
|
1399
|
-
report : Whether report SQL execute information.
|
1400
|
-
- `None`, Use attribute `report_execute_info`: of object `ROption`.
|
1401
|
-
- `int`: Use this value.
|
1402
|
-
kwdata : Keyword parameters for filling.
|
1403
|
-
|
1404
|
-
Returns
|
1405
|
-
-------
|
1406
|
-
Judged result.
|
1407
|
-
|
1408
|
-
Examples
|
1409
|
-
--------
|
1410
|
-
Parameter `where` and `kwdata`.
|
1411
|
-
>>> data = [{'id': 1}]
|
1412
|
-
>>> Database.execute_insert('database.table', data)
|
1413
|
-
>>> where = '`id` = :id_'
|
1414
|
-
>>> id_ = 1
|
1415
|
-
>>> result = Database.execute_exist('database.table', where, id_=id_)
|
1416
|
-
>>> print(result)
|
1417
|
-
True
|
1418
|
-
"""
|
1419
|
-
|
1420
|
-
# Handle parameter.
|
1421
|
-
database, table, _ = self.extract_path(path)
|
1422
|
-
|
1423
|
-
# Execute.
|
1424
|
-
result = self.execute_count(path, where, report, **kwdata)
|
1425
|
-
|
1426
|
-
# Judge.
|
1427
|
-
judge = result != 0
|
1428
|
-
|
1429
|
-
return judge
|
1430
|
-
|
1431
|
-
|
1432
|
-
def execute_generator(
|
1433
|
-
self,
|
1434
|
-
sql: str | TextClause,
|
1435
|
-
data: TableData,
|
1436
|
-
report: bool | None = None,
|
1437
|
-
**kwdata: Any
|
1438
|
-
) -> Generator[Result, Any, None]:
|
1439
|
-
"""
|
1440
|
-
Return a generator that can execute SQL.
|
1441
|
-
|
1442
|
-
Parameters
|
1443
|
-
----------
|
1444
|
-
sql : SQL in method `sqlalchemy.text` format, or `TextClause` object.
|
1445
|
-
data : Data set for filling.
|
1446
|
-
report : Whether report SQL execute information.
|
1447
|
-
- `None`: Use attribute `default_report`.
|
1448
|
-
- `bool`: Use this value.
|
1449
|
-
kwdata : Keyword parameters for filling.
|
1450
|
-
|
1451
|
-
Returns
|
1452
|
-
-------
|
1453
|
-
Generator.
|
1454
|
-
"""
|
1455
|
-
|
1456
|
-
# Instance.
|
1457
|
-
generator = Generator(
|
1458
|
-
self.execute,
|
1459
|
-
sql=sql,
|
1460
|
-
report=report,
|
1461
|
-
**kwdata
|
1462
|
-
)
|
1463
|
-
|
1464
|
-
# Add.
|
1465
|
-
for row in data:
|
1466
|
-
generator(**row)
|
1467
|
-
|
1468
|
-
return generator.generator
|
1469
|
-
|
1470
|
-
|
1471
|
-
def connect(self):
|
1472
|
-
"""
|
1473
|
-
Build `DatabaseConnection` instance.
|
1474
|
-
|
1475
|
-
Returns
|
1476
|
-
-------
|
1477
|
-
Database connection instance.
|
1478
|
-
"""
|
1479
|
-
|
1480
|
-
# Import.
|
1481
|
-
from .rconn import DatabaseConnection
|
1482
|
-
|
1483
|
-
# Build.
|
1484
|
-
dbconnection = DatabaseConnection(
|
1485
|
-
self.engine.connect(),
|
1486
|
-
self
|
1487
|
-
)
|
1488
|
-
|
1489
|
-
return dbconnection
|
1490
|
-
|
1491
|
-
|
1492
|
-
@property
|
1493
|
-
def exe(self):
|
1494
|
-
"""
|
1495
|
-
Build `database path` instance.
|
1496
|
-
|
1497
|
-
Returns
|
1498
|
-
-------
|
1499
|
-
Instance.
|
1500
|
-
|
1501
|
-
Examples
|
1502
|
-
--------
|
1503
|
-
Execute.
|
1504
|
-
>>> sql = 'select :value'
|
1505
|
-
>>> result = DatabaseExecute(sql, value=1)
|
1506
|
-
|
1507
|
-
Select.
|
1508
|
-
>>> field = ['id', 'value']
|
1509
|
-
>>> where = '`id` = ids'
|
1510
|
-
>>> ids = (1, 2)
|
1511
|
-
>>> result = DatabaseExecute.database.table(field, where, ids=ids)
|
1512
|
-
|
1513
|
-
Insert.
|
1514
|
-
>>> data = [{'id': 1}, {'id': 2}]
|
1515
|
-
>>> duplicate = 'ignore'
|
1516
|
-
>>> result = DatabaseExecute.database.table + data
|
1517
|
-
>>> result = DatabaseExecute.database.table + (data, duplicate)
|
1518
|
-
>>> result = DatabaseExecute.database.table + {'data': data, 'duplicate': duplicate}
|
1519
|
-
|
1520
|
-
Update.
|
1521
|
-
>>> data = [{'name': 'a', 'id': 1}, {'name': 'b', 'id': 2}]
|
1522
|
-
>>> where_fields = 'id'
|
1523
|
-
>>> result = DatabaseExecute.database.table & data
|
1524
|
-
>>> result = DatabaseExecute.database.table & (data, where_fields)
|
1525
|
-
>>> result = DatabaseExecute.database.table & {'data': data, 'where_fields': where_fields}
|
1526
|
-
|
1527
|
-
Delete.
|
1528
|
-
>>> where = '`id` IN (1, 2)'
|
1529
|
-
>>> report = True
|
1530
|
-
>>> result = DatabaseExecute.database.table - where
|
1531
|
-
>>> result = DatabaseExecute.database.table - (where, report)
|
1532
|
-
>>> result = DatabaseExecute.database.table - {'where': where, 'report': report}
|
1533
|
-
|
1534
|
-
Copy.
|
1535
|
-
>>> where = '`id` IN (1, 2)'
|
1536
|
-
>>> limit = 1
|
1537
|
-
>>> result = DatabaseExecute.database.table * where
|
1538
|
-
>>> result = DatabaseExecute.database.table * (where, limit)
|
1539
|
-
>>> result = DatabaseExecute.database.table * {'where': where, 'limit': limit}
|
1540
|
-
|
1541
|
-
Exist.
|
1542
|
-
>>> where = '`id` IN (1, 2)'
|
1543
|
-
>>> report = True
|
1544
|
-
>>> result = where in DatabaseExecute.database.table
|
1545
|
-
>>> result = (where, report) in DatabaseExecute.database.table
|
1546
|
-
>>> result = {'where': where, 'report': report} in DatabaseExecute.database.table
|
1547
|
-
|
1548
|
-
Count.
|
1549
|
-
>>> result = len(DatabaseExecute.database.table)
|
1550
|
-
|
1551
|
-
Default database.
|
1552
|
-
>>> field = ['id', 'value']
|
1553
|
-
>>> engine = Database(**server, database)
|
1554
|
-
>>> result = engine.exe.table()
|
1555
|
-
"""
|
1556
|
-
|
1557
|
-
# Import.
|
1558
|
-
from .rexec import DatabaseExecute
|
1559
|
-
|
1560
|
-
# Build.
|
1561
|
-
dbexecute = DatabaseExecute(self)
|
1562
|
-
|
1563
|
-
return dbexecute
|
1564
|
-
|
1565
|
-
|
1566
211
|
def schema(self, filter_default: bool = True) -> dict[str, dict[str, list[str]]]:
|
1567
212
|
"""
|
1568
213
|
Get schemata of databases and tables and columns.
|
@@ -1576,11 +221,6 @@ class Database(DatabaseBase):
|
|
1576
221
|
Schemata of databases and tables and columns.
|
1577
222
|
"""
|
1578
223
|
|
1579
|
-
# Check.
|
1580
|
-
if self.backend == 'sqlite':
|
1581
|
-
text = 'not suitable for SQLite databases'
|
1582
|
-
throw(AssertionError, text=text)
|
1583
|
-
|
1584
224
|
# Handle parameter.
|
1585
225
|
filter_db = (
|
1586
226
|
'information_schema',
|
@@ -1632,12 +272,70 @@ class Database(DatabaseBase):
|
|
1632
272
|
column_list.append(column)
|
1633
273
|
|
1634
274
|
## Add empty database.
|
1635
|
-
for
|
1636
|
-
schema_dict[
|
275
|
+
for name in database_names:
|
276
|
+
schema_dict[name] = None
|
1637
277
|
|
1638
278
|
return schema_dict
|
1639
279
|
|
1640
280
|
|
281
|
+
def connect(self, autocommit: bool = False):
|
282
|
+
"""
|
283
|
+
Build `DatabaseConnection` instance.
|
284
|
+
|
285
|
+
Parameters
|
286
|
+
----------
|
287
|
+
autocommit: Whether automatic commit connection.
|
288
|
+
|
289
|
+
Returns
|
290
|
+
-------
|
291
|
+
Database connection instance.
|
292
|
+
"""
|
293
|
+
|
294
|
+
# Import.
|
295
|
+
from .rconn import DatabaseConnection
|
296
|
+
|
297
|
+
# Build.
|
298
|
+
conn = DatabaseConnection(self, autocommit)
|
299
|
+
|
300
|
+
return conn
|
301
|
+
|
302
|
+
|
303
|
+
@property
|
304
|
+
def execute(self):
|
305
|
+
"""
|
306
|
+
Build `DatabaseExecute` instance.
|
307
|
+
|
308
|
+
Returns
|
309
|
+
-------
|
310
|
+
Instance.
|
311
|
+
"""
|
312
|
+
|
313
|
+
# Build.
|
314
|
+
dbconn = self.connect(True)
|
315
|
+
exec = dbconn.execute
|
316
|
+
|
317
|
+
return exec
|
318
|
+
|
319
|
+
|
320
|
+
@property
|
321
|
+
def orm(self):
|
322
|
+
"""
|
323
|
+
Build `DatabaseORM` instance.
|
324
|
+
|
325
|
+
Returns
|
326
|
+
-------
|
327
|
+
Instance.
|
328
|
+
"""
|
329
|
+
|
330
|
+
# Import.
|
331
|
+
from .rorm import DatabaseORM
|
332
|
+
|
333
|
+
# Build.
|
334
|
+
orm = DatabaseORM(self)
|
335
|
+
|
336
|
+
return orm
|
337
|
+
|
338
|
+
|
1641
339
|
@property
|
1642
340
|
def info(self):
|
1643
341
|
"""
|
@@ -1645,7 +343,7 @@ class Database(DatabaseBase):
|
|
1645
343
|
|
1646
344
|
Returns
|
1647
345
|
-------
|
1648
|
-
|
346
|
+
Instance.
|
1649
347
|
|
1650
348
|
Examples
|
1651
349
|
--------
|
@@ -1684,7 +382,7 @@ class Database(DatabaseBase):
|
|
1684
382
|
|
1685
383
|
Returns
|
1686
384
|
-------
|
1687
|
-
|
385
|
+
Instance.
|
1688
386
|
"""
|
1689
387
|
|
1690
388
|
# Import.
|
@@ -1703,7 +401,7 @@ class Database(DatabaseBase):
|
|
1703
401
|
|
1704
402
|
Returns
|
1705
403
|
-------
|
1706
|
-
|
404
|
+
Instance.
|
1707
405
|
"""
|
1708
406
|
|
1709
407
|
# Import.
|
@@ -1722,7 +420,7 @@ class Database(DatabaseBase):
|
|
1722
420
|
|
1723
421
|
Returns
|
1724
422
|
-------
|
1725
|
-
|
423
|
+
Instance.
|
1726
424
|
"""
|
1727
425
|
|
1728
426
|
# Import.
|
@@ -1741,7 +439,7 @@ class Database(DatabaseBase):
|
|
1741
439
|
|
1742
440
|
Returns
|
1743
441
|
-------
|
1744
|
-
|
442
|
+
Instance.
|
1745
443
|
"""
|
1746
444
|
|
1747
445
|
# Import.
|
@@ -1756,108 +454,79 @@ class Database(DatabaseBase):
|
|
1756
454
|
@property
|
1757
455
|
def status(self):
|
1758
456
|
"""
|
1759
|
-
Build `DatabaseParametersStatus`
|
457
|
+
Build `DatabaseParametersStatus` instance.
|
1760
458
|
|
1761
459
|
Returns
|
1762
460
|
-------
|
1763
|
-
|
461
|
+
Instance.
|
1764
462
|
"""
|
1765
463
|
|
1766
464
|
# Import.
|
1767
|
-
from .rparam import DatabaseParametersStatus
|
465
|
+
from .rparam import DatabaseParametersStatus
|
1768
466
|
|
1769
467
|
# Build.
|
468
|
+
dbps = DatabaseParametersStatus(self, False)
|
1770
469
|
|
1771
|
-
|
1772
|
-
if self.backend == 'sqlite':
|
1773
|
-
dbp = DatabaseParametersPragma(self)
|
1774
|
-
|
1775
|
-
## Other.
|
1776
|
-
else:
|
1777
|
-
dbp = DatabaseParametersStatus(self, False)
|
1778
|
-
|
1779
|
-
return dbp
|
470
|
+
return dbps
|
1780
471
|
|
1781
472
|
|
1782
473
|
@property
|
1783
474
|
def global_status(self):
|
1784
475
|
"""
|
1785
|
-
Build `DatabaseParametersStatus`
|
476
|
+
Build global `DatabaseParametersStatus` instance.
|
1786
477
|
|
1787
478
|
Returns
|
1788
479
|
-------
|
1789
|
-
|
480
|
+
Instance.
|
1790
481
|
"""
|
1791
482
|
|
1792
483
|
# Import.
|
1793
|
-
from .rparam import DatabaseParametersStatus
|
484
|
+
from .rparam import DatabaseParametersStatus
|
1794
485
|
|
1795
486
|
# Build.
|
487
|
+
dbps = DatabaseParametersStatus(self, True)
|
1796
488
|
|
1797
|
-
|
1798
|
-
if self.backend == 'sqlite':
|
1799
|
-
dbp = DatabaseParametersPragma(self)
|
1800
|
-
|
1801
|
-
## Other.
|
1802
|
-
else:
|
1803
|
-
dbp = DatabaseParametersStatus(self, True)
|
1804
|
-
|
1805
|
-
return dbp
|
489
|
+
return dbps
|
1806
490
|
|
1807
491
|
|
1808
492
|
@property
|
1809
493
|
def variables(self):
|
1810
494
|
"""
|
1811
|
-
Build `DatabaseParametersVariable`
|
495
|
+
Build `DatabaseParametersVariable` instance.
|
1812
496
|
|
1813
497
|
Returns
|
1814
498
|
-------
|
1815
|
-
|
499
|
+
Instance.
|
1816
500
|
"""
|
1817
501
|
|
1818
502
|
# Import.
|
1819
|
-
from .rparam import DatabaseParametersVariable
|
503
|
+
from .rparam import DatabaseParametersVariable
|
1820
504
|
|
1821
505
|
# Build.
|
506
|
+
dbpv = DatabaseParametersVariable(self, False)
|
1822
507
|
|
1823
|
-
|
1824
|
-
if self.backend == 'sqlite':
|
1825
|
-
dbp = DatabaseParametersPragma(self)
|
1826
|
-
|
1827
|
-
## Other.
|
1828
|
-
else:
|
1829
|
-
dbp = DatabaseParametersVariable(self, False)
|
1830
|
-
|
1831
|
-
return dbp
|
508
|
+
return dbpv
|
1832
509
|
|
1833
510
|
|
1834
511
|
@property
|
1835
512
|
def global_variables(self):
|
1836
513
|
"""
|
1837
|
-
Build global `
|
514
|
+
Build global `DatabaseParametersVariable` instance.
|
1838
515
|
|
1839
516
|
Returns
|
1840
517
|
-------
|
1841
|
-
|
518
|
+
Instance.
|
1842
519
|
"""
|
1843
520
|
|
1844
521
|
# Import.
|
1845
|
-
from .rparam import DatabaseParametersVariable
|
522
|
+
from .rparam import DatabaseParametersVariable
|
1846
523
|
|
1847
524
|
# Build.
|
1848
525
|
|
1849
526
|
## SQLite.
|
1850
|
-
|
1851
|
-
dbp = DatabaseParametersPragma(self)
|
527
|
+
dbpv = DatabaseParametersVariable(self, True)
|
1852
528
|
|
1853
|
-
|
1854
|
-
else:
|
1855
|
-
dbp = DatabaseParametersVariable(self, True)
|
1856
|
-
|
1857
|
-
return dbp
|
1858
|
-
|
1859
|
-
|
1860
|
-
__call__ = execute
|
529
|
+
return dbpv
|
1861
530
|
|
1862
531
|
|
1863
532
|
def __str__(self) -> str:
|
@@ -1865,16 +534,6 @@ class Database(DatabaseBase):
|
|
1865
534
|
Return connection information text.
|
1866
535
|
"""
|
1867
536
|
|
1868
|
-
# Handle parameter.
|
1869
|
-
if hasattr(self, 'engine'):
|
1870
|
-
attr_dict = self.__dict__
|
1871
|
-
else:
|
1872
|
-
rdatabase: Database = self.rdatabase
|
1873
|
-
attr_dict = {
|
1874
|
-
**self.__dict__,
|
1875
|
-
**rdatabase.__dict__
|
1876
|
-
}
|
1877
|
-
|
1878
537
|
# Generate.
|
1879
538
|
filter_key = (
|
1880
539
|
'engine',
|
@@ -1884,10 +543,10 @@ class Database(DatabaseBase):
|
|
1884
543
|
)
|
1885
544
|
info = {
|
1886
545
|
key: value
|
1887
|
-
for key, value in
|
546
|
+
for key, value in self.__dict__.items()
|
1888
547
|
if key not in filter_key
|
1889
548
|
}
|
1890
|
-
info['count'] = self.
|
549
|
+
info['count'] = self.count_conn
|
1891
550
|
text = join_data_text(info)
|
1892
551
|
|
1893
552
|
return text
|