reydb 1.1.37__py3-none-any.whl → 1.1.39__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 +168 -1
- reydb/rbuild.py +40 -40
- reydb/rconfig.py +1 -1
- reydb/rconn.py +0 -1
- reydb/rdb.py +51 -282
- reydb/rerror.py +1 -1
- reydb/rfile.py +2 -2
- reydb/rparam.py +1 -1
- {reydb-1.1.37.dist-info → reydb-1.1.39.dist-info}/METADATA +1 -1
- reydb-1.1.39.dist-info/RECORD +16 -0
- reydb-1.1.37.dist-info/RECORD +0 -16
- {reydb-1.1.37.dist-info → reydb-1.1.39.dist-info}/WHEEL +0 -0
- {reydb-1.1.37.dist-info → reydb-1.1.39.dist-info}/licenses/LICENSE +0 -0
reydb/rbase.py
CHANGED
@@ -9,11 +9,35 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from
|
12
|
+
from typing import Any, TypedDict, Literal
|
13
|
+
from sqlalchemy.engine.base import Engine, Connection
|
14
|
+
from sqlalchemy.engine.url import URL
|
15
|
+
from reykit.rbase import Base, throw
|
16
|
+
from reykit.rre import search
|
17
|
+
|
18
|
+
from .rbase import DatabaseBase
|
13
19
|
|
14
20
|
|
15
21
|
__all__ = (
|
16
22
|
'DatabaseBase',
|
23
|
+
'extract_url',
|
24
|
+
'extract_engine'
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
URLParameter = TypedDict(
|
29
|
+
'URLParameter',
|
30
|
+
{
|
31
|
+
'drivername': str,
|
32
|
+
'backend': str,
|
33
|
+
'driver': str | None,
|
34
|
+
'username': str | None,
|
35
|
+
'password': str | None,
|
36
|
+
'host': str | None,
|
37
|
+
'port': str | None,
|
38
|
+
'database': str | None,
|
39
|
+
'query': dict[str, str] | None
|
40
|
+
}
|
17
41
|
)
|
18
42
|
|
19
43
|
|
@@ -21,3 +45,146 @@ class DatabaseBase(Base):
|
|
21
45
|
"""
|
22
46
|
Database base type.
|
23
47
|
"""
|
48
|
+
|
49
|
+
|
50
|
+
def extract_url(url: str | URL) -> URLParameter:
|
51
|
+
"""
|
52
|
+
Extract parameters from URL of string.
|
53
|
+
|
54
|
+
Parameters
|
55
|
+
----------
|
56
|
+
url : URL of string.
|
57
|
+
|
58
|
+
Returns
|
59
|
+
-------
|
60
|
+
URL parameters.
|
61
|
+
"""
|
62
|
+
|
63
|
+
# Extract.
|
64
|
+
match url:
|
65
|
+
|
66
|
+
## Type str.
|
67
|
+
case str():
|
68
|
+
pattern_remote = r'^([\w\+]+)://(\w+):(\w+)@(\d+\.\d+\.\d+\.\d+):(\d+)[/]?([^\?]+)?[\?]?(\S+)?$'
|
69
|
+
pattern_local = r'^([\w\+]+):////?([^\?]+)[\?]?(\S+)?$'
|
70
|
+
|
71
|
+
### Server.
|
72
|
+
if (result_remote := search(pattern_remote, url)) is not None:
|
73
|
+
(
|
74
|
+
drivername,
|
75
|
+
username,
|
76
|
+
password,
|
77
|
+
host,
|
78
|
+
port,
|
79
|
+
database,
|
80
|
+
query_str
|
81
|
+
) = result_remote
|
82
|
+
port = int(port)
|
83
|
+
|
84
|
+
### SQLite.
|
85
|
+
elif (result_local := search(pattern_local, url)) is not None:
|
86
|
+
username = password = host = port = None
|
87
|
+
(
|
88
|
+
drivername,
|
89
|
+
database,
|
90
|
+
query_str
|
91
|
+
) = result_local
|
92
|
+
|
93
|
+
### Throw exception.
|
94
|
+
else:
|
95
|
+
throw(ValueError, url)
|
96
|
+
|
97
|
+
if query_str is not None:
|
98
|
+
query = {
|
99
|
+
key: value
|
100
|
+
for query_item_str in query_str.split('&')
|
101
|
+
for key, value in (query_item_str.split('=', 1),)
|
102
|
+
}
|
103
|
+
else:
|
104
|
+
query = {}
|
105
|
+
|
106
|
+
## Type URL.
|
107
|
+
case URL():
|
108
|
+
drivername = url.drivername
|
109
|
+
username = url.username
|
110
|
+
password = url.password
|
111
|
+
host = url.host
|
112
|
+
port = url.port
|
113
|
+
database = url.database
|
114
|
+
query = dict(url.query)
|
115
|
+
|
116
|
+
## Backend and dirver.
|
117
|
+
if '+' in drivername:
|
118
|
+
backend, driver = drivername.split('+', 1)
|
119
|
+
else:
|
120
|
+
backend = drivername
|
121
|
+
driver = None
|
122
|
+
|
123
|
+
# Generate parameter.
|
124
|
+
params = {
|
125
|
+
'drivername': drivername,
|
126
|
+
'backend': backend,
|
127
|
+
'driver': driver,
|
128
|
+
'username': username,
|
129
|
+
'password': password,
|
130
|
+
'host': host,
|
131
|
+
'port': port,
|
132
|
+
'database': database,
|
133
|
+
'query': query
|
134
|
+
}
|
135
|
+
|
136
|
+
return params
|
137
|
+
|
138
|
+
|
139
|
+
def extract_engine(engine: Engine | Connection) -> dict[
|
140
|
+
Literal[
|
141
|
+
'drivername', 'username', 'password', 'host', 'port', 'database', 'query',
|
142
|
+
'pool_size', 'max_overflow', 'pool_timeout', 'pool_recycle'
|
143
|
+
],
|
144
|
+
Any
|
145
|
+
]:
|
146
|
+
"""
|
147
|
+
Extract parameters from `Engine` or `Connection` object.
|
148
|
+
|
149
|
+
Parameters
|
150
|
+
----------
|
151
|
+
engine : Engine or Connection object.
|
152
|
+
|
153
|
+
Returns
|
154
|
+
-------
|
155
|
+
Extracted parameters.
|
156
|
+
"""
|
157
|
+
|
158
|
+
## Extract Engine object from Connection boject.
|
159
|
+
if type(engine) == Connection:
|
160
|
+
engine = engine.engine
|
161
|
+
|
162
|
+
## Extract.
|
163
|
+
drivername: str = engine.url.drivername
|
164
|
+
username: str | None = engine.url.username
|
165
|
+
password: str | None = engine.url.password
|
166
|
+
host: str | None = engine.url.host
|
167
|
+
port: str | None = engine.url.port
|
168
|
+
database: str | None = engine.url.database
|
169
|
+
query: dict[str, str] = dict(engine.url.query)
|
170
|
+
pool_size: int = engine.pool._pool.maxsize
|
171
|
+
max_overflow: int = engine.pool._max_overflow
|
172
|
+
pool_timeout: float = engine.pool._timeout
|
173
|
+
pool_recycle: int = engine.pool._recycle
|
174
|
+
|
175
|
+
# Generate parameter.
|
176
|
+
params = {
|
177
|
+
'drivername': drivername,
|
178
|
+
'username': username,
|
179
|
+
'password': password,
|
180
|
+
'host': host,
|
181
|
+
'port': port,
|
182
|
+
'database': database,
|
183
|
+
'query': query,
|
184
|
+
'pool_size': pool_size,
|
185
|
+
'max_overflow': max_overflow,
|
186
|
+
'pool_timeout': pool_timeout,
|
187
|
+
'pool_recycle': pool_recycle
|
188
|
+
}
|
189
|
+
|
190
|
+
return params
|
reydb/rbuild.py
CHANGED
@@ -52,22 +52,22 @@ class DatabaseBuild(DatabaseBase):
|
|
52
52
|
"""
|
53
53
|
|
54
54
|
|
55
|
-
def __init__(self,
|
55
|
+
def __init__(self, database: Database | DatabaseConnection) -> None:
|
56
56
|
"""
|
57
57
|
Build instance attributes.
|
58
58
|
|
59
59
|
Parameters
|
60
60
|
----------
|
61
|
-
|
61
|
+
database : Database or DatabaseConnection instance.
|
62
62
|
"""
|
63
63
|
|
64
64
|
# SQLite.
|
65
|
-
if
|
66
|
-
text='not suitable for SQLite databases'
|
65
|
+
if database.backend == 'sqlite':
|
66
|
+
text = 'not suitable for SQLite databases'
|
67
67
|
throw(AssertionError, text=text)
|
68
68
|
|
69
69
|
# Set attribute.
|
70
|
-
self.
|
70
|
+
self.database = database
|
71
71
|
self._schema: dict[str, dict[str, list[str]]] | None = None
|
72
72
|
|
73
73
|
|
@@ -98,7 +98,7 @@ class DatabaseBuild(DatabaseBase):
|
|
98
98
|
|
99
99
|
# Execute.
|
100
100
|
if execute:
|
101
|
-
self.
|
101
|
+
self.database.execute(sql)
|
102
102
|
|
103
103
|
return sql
|
104
104
|
|
@@ -118,7 +118,7 @@ class DatabaseBuild(DatabaseBase):
|
|
118
118
|
Parameters
|
119
119
|
----------
|
120
120
|
name : Field name.
|
121
|
-
|
121
|
+
type_ : Field type.
|
122
122
|
constraint : Field constraint.
|
123
123
|
comment : Field comment.
|
124
124
|
position : Field position.
|
@@ -285,7 +285,7 @@ class DatabaseBuild(DatabaseBase):
|
|
285
285
|
"""
|
286
286
|
|
287
287
|
# Handle parameter.
|
288
|
-
database, table, _ = self.
|
288
|
+
database, table, _ = self.database.extract_path(path)
|
289
289
|
if fields.__class__ == dict:
|
290
290
|
fields = [fields]
|
291
291
|
if primary.__class__ == str:
|
@@ -347,7 +347,7 @@ class DatabaseBuild(DatabaseBase):
|
|
347
347
|
|
348
348
|
# Execute.
|
349
349
|
if execute:
|
350
|
-
self.
|
350
|
+
self.database.execute(sql)
|
351
351
|
|
352
352
|
return sql
|
353
353
|
|
@@ -375,7 +375,7 @@ class DatabaseBuild(DatabaseBase):
|
|
375
375
|
"""
|
376
376
|
|
377
377
|
# Handle parameter.
|
378
|
-
database, view, _ = self.
|
378
|
+
database, view, _ = self.database.extract_path(path)
|
379
379
|
|
380
380
|
# Generate SQL.
|
381
381
|
select = select.replace('\n', '\n ')
|
@@ -383,7 +383,7 @@ class DatabaseBuild(DatabaseBase):
|
|
383
383
|
|
384
384
|
# Execute.
|
385
385
|
if execute:
|
386
|
-
self.
|
386
|
+
self.database.execute(sql)
|
387
387
|
|
388
388
|
return sql
|
389
389
|
|
@@ -476,7 +476,7 @@ class DatabaseBuild(DatabaseBase):
|
|
476
476
|
|
477
477
|
# Execute.
|
478
478
|
if execute:
|
479
|
-
self.
|
479
|
+
self.database.execute(sql)
|
480
480
|
|
481
481
|
return sql
|
482
482
|
|
@@ -502,14 +502,14 @@ class DatabaseBuild(DatabaseBase):
|
|
502
502
|
"""
|
503
503
|
|
504
504
|
# Handle parameter.
|
505
|
-
database, table, _ = self.
|
505
|
+
database, table, _ = self.database.extract_path(path)
|
506
506
|
|
507
507
|
# Generate.
|
508
508
|
sql = f'DROP TABLE `{database}`.`{table}`'
|
509
509
|
|
510
510
|
# Execute.
|
511
511
|
if execute:
|
512
|
-
self.
|
512
|
+
self.database.execute(sql)
|
513
513
|
|
514
514
|
return sql
|
515
515
|
|
@@ -535,14 +535,14 @@ class DatabaseBuild(DatabaseBase):
|
|
535
535
|
"""
|
536
536
|
|
537
537
|
# Handle parameter.
|
538
|
-
database, view, _ = self.
|
538
|
+
database, view, _ = self.database.extract_path(path)
|
539
539
|
|
540
540
|
# Generate SQL.
|
541
541
|
sql = 'DROP VIEW `%s`.`%s`' % (database, view)
|
542
542
|
|
543
543
|
# Execute.
|
544
544
|
if execute:
|
545
|
-
self.
|
545
|
+
self.database.execute(sql)
|
546
546
|
|
547
547
|
return sql
|
548
548
|
|
@@ -592,7 +592,7 @@ class DatabaseBuild(DatabaseBase):
|
|
592
592
|
|
593
593
|
# Execute.
|
594
594
|
if execute:
|
595
|
-
self.
|
595
|
+
self.database.execute(sql)
|
596
596
|
|
597
597
|
return sql
|
598
598
|
|
@@ -649,7 +649,7 @@ class DatabaseBuild(DatabaseBase):
|
|
649
649
|
"""
|
650
650
|
|
651
651
|
# Handle parameter.
|
652
|
-
database, table, _ = self.
|
652
|
+
database, table, _ = self.database.extract_path(path)
|
653
653
|
if fields.__class__ == dict:
|
654
654
|
fields = [fields]
|
655
655
|
if primary.__class__ == str:
|
@@ -707,7 +707,7 @@ class DatabaseBuild(DatabaseBase):
|
|
707
707
|
|
708
708
|
# Execute.
|
709
709
|
if execute:
|
710
|
-
self.
|
710
|
+
self.database.execute(sql)
|
711
711
|
|
712
712
|
return sql
|
713
713
|
|
@@ -739,7 +739,7 @@ class DatabaseBuild(DatabaseBase):
|
|
739
739
|
"""
|
740
740
|
|
741
741
|
# Handle parameter.
|
742
|
-
database, table, _ = self.
|
742
|
+
database, table, _ = self.database.extract_path(path)
|
743
743
|
if fields.__class__ == str:
|
744
744
|
fields = [fields]
|
745
745
|
if indexes.__class__ == str:
|
@@ -778,7 +778,7 @@ class DatabaseBuild(DatabaseBase):
|
|
778
778
|
|
779
779
|
# Execute.
|
780
780
|
if execute:
|
781
|
-
self.
|
781
|
+
self.database.execute(sql)
|
782
782
|
|
783
783
|
return sql
|
784
784
|
|
@@ -829,7 +829,7 @@ class DatabaseBuild(DatabaseBase):
|
|
829
829
|
"""
|
830
830
|
|
831
831
|
# Handle parameter.
|
832
|
-
database, table, _ = self.
|
832
|
+
database, table, _ = self.database.extract_path(path)
|
833
833
|
if fields.__class__ == dict:
|
834
834
|
fields = [fields]
|
835
835
|
|
@@ -897,7 +897,7 @@ class DatabaseBuild(DatabaseBase):
|
|
897
897
|
|
898
898
|
# Execute.
|
899
899
|
if execute:
|
900
|
-
self.
|
900
|
+
self.database.execute(sql)
|
901
901
|
|
902
902
|
return sql
|
903
903
|
|
@@ -925,14 +925,14 @@ class DatabaseBuild(DatabaseBase):
|
|
925
925
|
"""
|
926
926
|
|
927
927
|
# Handle parameter.
|
928
|
-
database, view, _ = self.
|
928
|
+
database, view, _ = self.database.extract_path(path)
|
929
929
|
|
930
930
|
# Generate SQL.
|
931
931
|
sql = 'ALTER VIEW `%s`.`%s` AS\n%s' % (database, view, select)
|
932
932
|
|
933
933
|
# Execute.
|
934
934
|
if execute:
|
935
|
-
self.
|
935
|
+
self.database.execute(sql)
|
936
936
|
|
937
937
|
return sql
|
938
938
|
|
@@ -958,14 +958,14 @@ class DatabaseBuild(DatabaseBase):
|
|
958
958
|
"""
|
959
959
|
|
960
960
|
# Handle parameter.
|
961
|
-
database, table, _ = self.
|
961
|
+
database, table, _ = self.database.extract_path(path)
|
962
962
|
|
963
963
|
# Generate.
|
964
964
|
sql = f'TRUNCATE TABLE `{database}`.`{table}`'
|
965
965
|
|
966
966
|
# Execute.
|
967
967
|
if execute:
|
968
|
-
self.
|
968
|
+
self.database.execute(sql)
|
969
969
|
|
970
970
|
return sql
|
971
971
|
|
@@ -989,9 +989,9 @@ class DatabaseBuild(DatabaseBase):
|
|
989
989
|
"""
|
990
990
|
|
991
991
|
# Handle parameter.
|
992
|
-
database, table, column = self.
|
992
|
+
database, table, column = self.database.extract_path(path, 'database')
|
993
993
|
if self._schema is None:
|
994
|
-
self._schema = self.
|
994
|
+
self._schema = self.database.schema(False)
|
995
995
|
|
996
996
|
# Judge.
|
997
997
|
judge = (
|
@@ -1081,7 +1081,7 @@ class DatabaseBuild(DatabaseBase):
|
|
1081
1081
|
database = params['name']
|
1082
1082
|
|
1083
1083
|
## Exist.
|
1084
|
-
exist = self.
|
1084
|
+
exist = self.database.build.exist((database, None, None))
|
1085
1085
|
if exist:
|
1086
1086
|
continue
|
1087
1087
|
|
@@ -1092,7 +1092,7 @@ class DatabaseBuild(DatabaseBase):
|
|
1092
1092
|
self.input_confirm_build(sql)
|
1093
1093
|
|
1094
1094
|
## Execute.
|
1095
|
-
self.
|
1095
|
+
self.database.execute(sql)
|
1096
1096
|
|
1097
1097
|
## Report.
|
1098
1098
|
text = f"Database '{database}' build completed."
|
@@ -1101,10 +1101,10 @@ class DatabaseBuild(DatabaseBase):
|
|
1101
1101
|
# Table.
|
1102
1102
|
for params in tables:
|
1103
1103
|
path = params['path']
|
1104
|
-
database, table, _ = self.
|
1104
|
+
database, table, _ = self.database.extract_path(path)
|
1105
1105
|
|
1106
1106
|
## Exist.
|
1107
|
-
exist = self.
|
1107
|
+
exist = self.database.build.exist((database, table, None))
|
1108
1108
|
if exist:
|
1109
1109
|
continue
|
1110
1110
|
|
@@ -1115,7 +1115,7 @@ class DatabaseBuild(DatabaseBase):
|
|
1115
1115
|
self.input_confirm_build(sql)
|
1116
1116
|
|
1117
1117
|
## Execute.
|
1118
|
-
self.
|
1118
|
+
self.database.execute(sql)
|
1119
1119
|
|
1120
1120
|
## Report.
|
1121
1121
|
text = f"Table '{table}' of database '{database}' build completed."
|
@@ -1124,10 +1124,10 @@ class DatabaseBuild(DatabaseBase):
|
|
1124
1124
|
# View.
|
1125
1125
|
for params in views:
|
1126
1126
|
path = params['path']
|
1127
|
-
database, view, _ = self.
|
1127
|
+
database, view, _ = self.database.extract_path(path)
|
1128
1128
|
|
1129
1129
|
## Exist.
|
1130
|
-
exist = self.
|
1130
|
+
exist = self.database.build.exist((database, view, None))
|
1131
1131
|
if exist:
|
1132
1132
|
continue
|
1133
1133
|
|
@@ -1138,7 +1138,7 @@ class DatabaseBuild(DatabaseBase):
|
|
1138
1138
|
self.input_confirm_build(sql)
|
1139
1139
|
|
1140
1140
|
## Execute.
|
1141
|
-
self.
|
1141
|
+
self.database.execute(sql)
|
1142
1142
|
|
1143
1143
|
## Report.
|
1144
1144
|
text = f"View '{view}' of database '{database}' build completed."
|
@@ -1147,10 +1147,10 @@ class DatabaseBuild(DatabaseBase):
|
|
1147
1147
|
# View stats.
|
1148
1148
|
for params in views_stats:
|
1149
1149
|
path = params['path']
|
1150
|
-
database, view, _ = self.
|
1150
|
+
database, view, _ = self.database.extract_path(path)
|
1151
1151
|
|
1152
1152
|
## Exist.
|
1153
|
-
exist = self.
|
1153
|
+
exist = self.database.build.exist((database, view, None))
|
1154
1154
|
if exist:
|
1155
1155
|
continue
|
1156
1156
|
|
@@ -1161,7 +1161,7 @@ class DatabaseBuild(DatabaseBase):
|
|
1161
1161
|
self.input_confirm_build(sql)
|
1162
1162
|
|
1163
1163
|
## Execute.
|
1164
|
-
self.
|
1164
|
+
self.database.execute(sql)
|
1165
1165
|
|
1166
1166
|
## Report.
|
1167
1167
|
text = f"View '{view}' of database '{database}' build completed."
|
reydb/rconfig.py
CHANGED
reydb/rconn.py
CHANGED
reydb/rdb.py
CHANGED
@@ -13,9 +13,9 @@ from typing import Any, Literal, overload
|
|
13
13
|
from collections.abc import Iterable, Generator
|
14
14
|
from enum import EnumType
|
15
15
|
from urllib.parse import quote as urllib_quote
|
16
|
+
from pymysql.constants.CLIENT import MULTI_STATEMENTS
|
16
17
|
from sqlalchemy import create_engine as sqlalchemy_create_engine, text as sqlalchemy_text
|
17
18
|
from sqlalchemy.engine.base import Engine, Connection
|
18
|
-
from sqlalchemy.engine.url import URL
|
19
19
|
from sqlalchemy.sql.elements import TextClause
|
20
20
|
from sqlalchemy.exc import OperationalError
|
21
21
|
from reykit.rbase import throw, is_iterable, get_first_notnone
|
@@ -27,7 +27,7 @@ from reykit.rtable import TableData, Table
|
|
27
27
|
from reykit.rtext import join_data_text
|
28
28
|
from reykit.rwrap import wrap_runtime, wrap_retry
|
29
29
|
|
30
|
-
from .rbase import DatabaseBase
|
30
|
+
from .rbase import DatabaseBase, extract_url
|
31
31
|
|
32
32
|
|
33
33
|
__all__ = (
|
@@ -45,6 +45,7 @@ monkey_sqlalchemy_row_index_field()
|
|
45
45
|
class Database(DatabaseBase):
|
46
46
|
"""
|
47
47
|
Database type.
|
48
|
+
Based `MySQL` or `SQLite`.
|
48
49
|
|
49
50
|
Examples
|
50
51
|
--------
|
@@ -66,7 +67,6 @@ class Database(DatabaseBase):
|
|
66
67
|
username: str,
|
67
68
|
password: str,
|
68
69
|
database: str | None = None,
|
69
|
-
drivername: str | None = None,
|
70
70
|
*,
|
71
71
|
pool_size: int = 5,
|
72
72
|
max_overflow: int = 10,
|
@@ -81,7 +81,6 @@ class Database(DatabaseBase):
|
|
81
81
|
self,
|
82
82
|
*,
|
83
83
|
database: str,
|
84
|
-
drivername: str | None = None,
|
85
84
|
pool_size: int = 5,
|
86
85
|
max_overflow: int = 10,
|
87
86
|
pool_timeout: float = 30.0,
|
@@ -94,7 +93,6 @@ class Database(DatabaseBase):
|
|
94
93
|
def __init__(
|
95
94
|
self,
|
96
95
|
*,
|
97
|
-
drivername: str | None = None,
|
98
96
|
pool_size: int = 5,
|
99
97
|
max_overflow: int = 10,
|
100
98
|
pool_timeout: float = 30.0,
|
@@ -103,25 +101,6 @@ class Database(DatabaseBase):
|
|
103
101
|
**query: str
|
104
102
|
) -> None: ...
|
105
103
|
|
106
|
-
@overload
|
107
|
-
def __init__(
|
108
|
-
self,
|
109
|
-
*,
|
110
|
-
url: str | URL,
|
111
|
-
pool_size: int = 5,
|
112
|
-
max_overflow: int = 10,
|
113
|
-
pool_timeout: float = 30.0,
|
114
|
-
pool_recycle: int | None = None,
|
115
|
-
retry: bool = False
|
116
|
-
) -> None: ...
|
117
|
-
|
118
|
-
@overload
|
119
|
-
def __init__(
|
120
|
-
self,
|
121
|
-
*,
|
122
|
-
engine: Engine | Connection,
|
123
|
-
retry: bool = False
|
124
|
-
) -> None: ...
|
125
104
|
|
126
105
|
def __init__(
|
127
106
|
self,
|
@@ -130,9 +109,6 @@ class Database(DatabaseBase):
|
|
130
109
|
username: str | None = None,
|
131
110
|
password: str | None = None,
|
132
111
|
database: str | None = None,
|
133
|
-
drivername: str | Iterable[str] | None = None,
|
134
|
-
url: str | URL | None = None,
|
135
|
-
engine: Engine | Connection | None = None,
|
136
112
|
pool_size: int = 5,
|
137
113
|
max_overflow: int = 10,
|
138
114
|
pool_timeout: float = 30.0,
|
@@ -149,16 +125,8 @@ class Database(DatabaseBase):
|
|
149
125
|
port : Remote server database port.
|
150
126
|
username : Remote server database username.
|
151
127
|
password : Remote server database password.
|
152
|
-
database : Remote server database name or local database file path
|
153
|
-
When parameters `host`, `port`, `username`, `password`, `database` are all `None`, then
|
154
|
-
drivername : Database backend and driver name.
|
155
|
-
- `None`: Automatic select.
|
156
|
-
When is remote server database, then is `mysql+mysqldb` and `mysql+pymysql`, `mysql+mysqlconnector`.
|
157
|
-
When is local database file or use memory, then is `sqlite`.
|
158
|
-
- `str`: Use this value.
|
159
|
-
- `Iterable[str]`: Try one by one use, set value after success.
|
160
|
-
url : Get parameter from server `URL`.
|
161
|
-
engine : Use existing `Engine` or `Connection` object, and get parameter from it.
|
128
|
+
database : Remote server database name or local database file path.
|
129
|
+
- `None`: When parameters `host`, `port`, `username`, `password`, `database` are all `None`, then using memory store.
|
162
130
|
pool_size : Number of connections `keep open`.
|
163
131
|
max_overflow : Number of connections `allowed overflow`.
|
164
132
|
pool_timeout : Number of seconds `wait create` connection.
|
@@ -172,74 +140,30 @@ class Database(DatabaseBase):
|
|
172
140
|
query : Remote server database parameters.
|
173
141
|
"""
|
174
142
|
|
175
|
-
# Handle parameter.
|
176
|
-
|
177
|
-
## From Engine or Connection.
|
178
|
-
if engine is not None:
|
179
|
-
if type(engine) == Connection:
|
180
|
-
engine = engine.engine
|
181
|
-
params = self.extract_engine(engine)
|
182
|
-
username: str | None = params['username']
|
183
|
-
password: str | None = params['password']
|
184
|
-
host: str | None = params['host']
|
185
|
-
port: int | None = params['port']
|
186
|
-
database: str | None = params['database']
|
187
|
-
drivername: str = params['drivername']
|
188
|
-
pool_size: int = params['pool_size']
|
189
|
-
max_overflow: int = params['max_overflow']
|
190
|
-
pool_timeout: float = params['pool_timeout']
|
191
|
-
pool_recycle: int = params['pool_recycle']
|
192
|
-
query: dict = params['query']
|
193
|
-
|
194
|
-
## From URL.
|
195
|
-
elif url is not None:
|
196
|
-
params = self.extract_url(url)
|
197
|
-
username: str | None = params['username']
|
198
|
-
password: str | None = params['password']
|
199
|
-
host: str | None = params['host']
|
200
|
-
port: int | None = params['port']
|
201
|
-
database: str | None = params['database']
|
202
|
-
drivername: str = params['drivername']
|
203
|
-
query: dict = params['query']
|
204
|
-
|
205
143
|
# Handle parameter.
|
206
144
|
if type(port) == str:
|
207
145
|
port = int(port)
|
208
146
|
|
209
|
-
#
|
210
|
-
self.username
|
211
|
-
self.password
|
212
|
-
self.host
|
147
|
+
# Build.
|
148
|
+
self.username = username
|
149
|
+
self.password = password
|
150
|
+
self.host = host
|
213
151
|
self.port: int | None = port
|
214
|
-
self.database
|
215
|
-
self.
|
216
|
-
self.
|
217
|
-
self.
|
218
|
-
self.max_overflow: int = max_overflow
|
219
|
-
self.pool_timeout: float = pool_timeout
|
152
|
+
self.database = database
|
153
|
+
self.pool_size = pool_size
|
154
|
+
self.max_overflow = max_overflow
|
155
|
+
self.pool_timeout = pool_timeout
|
220
156
|
if pool_recycle is None:
|
221
157
|
self.pool_recycle = -1
|
222
158
|
else:
|
223
159
|
self.pool_recycle = pool_recycle
|
224
|
-
self.retry
|
225
|
-
self.query
|
226
|
-
if (
|
227
|
-
self.database is None
|
228
|
-
and self.mode == 'memory'
|
229
|
-
):
|
230
|
-
self.database = ':memory:'
|
231
|
-
if self.drivername is None:
|
232
|
-
if self.mode == 'server':
|
233
|
-
self.drivername = ('mysql+mysqldb', 'mysql+pymysql', 'mysql+mysqlconnector')
|
234
|
-
else:
|
235
|
-
self.drivername = 'sqlite'
|
160
|
+
self.retry = retry
|
161
|
+
self.query = query
|
236
162
|
|
237
163
|
# Create engine.
|
238
|
-
|
239
|
-
self.engine = self.__create_engine()
|
240
|
-
self.drivername: str
|
164
|
+
self.engine = self.__create_engine()
|
241
165
|
|
242
|
-
#
|
166
|
+
# Server recycle time.
|
243
167
|
if pool_recycle is None:
|
244
168
|
if self.mode == 'server':
|
245
169
|
wait_timeout = self.variables['wait_timeout']
|
@@ -248,144 +172,6 @@ class Database(DatabaseBase):
|
|
248
172
|
self.engine.pool._recycle = self.pool_recycle
|
249
173
|
|
250
174
|
|
251
|
-
def extract_url(self, url: str | URL) -> dict[
|
252
|
-
Literal['drivername', 'username', 'password', 'host', 'port', 'database', 'query'],
|
253
|
-
Any
|
254
|
-
]:
|
255
|
-
"""
|
256
|
-
Extract parameters from URL of string.
|
257
|
-
|
258
|
-
Parameters
|
259
|
-
----------
|
260
|
-
url : URL of string.
|
261
|
-
|
262
|
-
Returns
|
263
|
-
-------
|
264
|
-
Extracted parameters.
|
265
|
-
"""
|
266
|
-
|
267
|
-
# Extract.
|
268
|
-
match url:
|
269
|
-
|
270
|
-
## Type str.
|
271
|
-
case str():
|
272
|
-
pattern_remote = r'^([\w\+]+)://(\w+):(\w+)@(\d+\.\d+\.\d+\.\d+):(\d+)[/]?([^\?]+)?[\?]?(\S+)?$'
|
273
|
-
pattern_local = r'^([\w\+]+):////?([^\?]+)[\?]?(\S+)?$'
|
274
|
-
|
275
|
-
### Remote.
|
276
|
-
if (result_remote := search(pattern_remote, url)) is not None:
|
277
|
-
(
|
278
|
-
drivername,
|
279
|
-
username,
|
280
|
-
password,
|
281
|
-
host,
|
282
|
-
port,
|
283
|
-
database,
|
284
|
-
query_str
|
285
|
-
) = result_remote
|
286
|
-
port = int(port)
|
287
|
-
|
288
|
-
### Local.
|
289
|
-
elif (result_local := search(pattern_local, url)) is not None:
|
290
|
-
username = password = host = port = None
|
291
|
-
(
|
292
|
-
drivername,
|
293
|
-
database,
|
294
|
-
query_str
|
295
|
-
) = result_local
|
296
|
-
|
297
|
-
### Throw exception.
|
298
|
-
else:
|
299
|
-
throw(ValueError, url)
|
300
|
-
|
301
|
-
drivername: str
|
302
|
-
if query_str is not None:
|
303
|
-
query = {
|
304
|
-
key: value
|
305
|
-
for query_item_str in query_str.split('&')
|
306
|
-
for key, value in (query_item_str.split('=', 1),)
|
307
|
-
}
|
308
|
-
else:
|
309
|
-
query = {}
|
310
|
-
|
311
|
-
## Type URL.
|
312
|
-
case URL():
|
313
|
-
drivername = url.drivername
|
314
|
-
username = url.username
|
315
|
-
password = url.password
|
316
|
-
host = url.host
|
317
|
-
port = url.port
|
318
|
-
database = url.database
|
319
|
-
query = dict(url.query)
|
320
|
-
|
321
|
-
# Generate parameter.
|
322
|
-
params = {
|
323
|
-
'drivername': drivername,
|
324
|
-
'username': username,
|
325
|
-
'password': password,
|
326
|
-
'host': host,
|
327
|
-
'port': port,
|
328
|
-
'database': database,
|
329
|
-
'query': query
|
330
|
-
}
|
331
|
-
|
332
|
-
return params
|
333
|
-
|
334
|
-
|
335
|
-
def extract_engine(self, engine: Engine | Connection) -> dict[
|
336
|
-
Literal[
|
337
|
-
'drivername', 'username', 'password', 'host', 'port', 'database', 'query',
|
338
|
-
'pool_size', 'max_overflow', 'pool_timeout', 'pool_recycle'
|
339
|
-
],
|
340
|
-
Any
|
341
|
-
]:
|
342
|
-
"""
|
343
|
-
Extract parameters from `Engine` or `Connection` object.
|
344
|
-
|
345
|
-
Parameters
|
346
|
-
----------
|
347
|
-
engine : Engine or Connection object.
|
348
|
-
|
349
|
-
Returns
|
350
|
-
-------
|
351
|
-
Extracted parameters.
|
352
|
-
"""
|
353
|
-
|
354
|
-
## Extract Engine object from Connection boject.
|
355
|
-
if type(engine) == Connection:
|
356
|
-
engine = engine.engine
|
357
|
-
|
358
|
-
## Extract.
|
359
|
-
drivername: str = engine.url.drivername
|
360
|
-
username: str | None = engine.url.username
|
361
|
-
password: str | None = engine.url.password
|
362
|
-
host: str | None = engine.url.host
|
363
|
-
port: str | None = engine.url.port
|
364
|
-
database: str | None = engine.url.database
|
365
|
-
query: dict[str, str] = dict(engine.url.query)
|
366
|
-
pool_size: int = engine.pool._pool.maxsize
|
367
|
-
max_overflow: int = engine.pool._max_overflow
|
368
|
-
pool_timeout: float = engine.pool._timeout
|
369
|
-
pool_recycle: int = engine.pool._recycle
|
370
|
-
|
371
|
-
# Generate parameter.
|
372
|
-
params = {
|
373
|
-
'drivername': drivername,
|
374
|
-
'username': username,
|
375
|
-
'password': password,
|
376
|
-
'host': host,
|
377
|
-
'port': port,
|
378
|
-
'database': database,
|
379
|
-
'query': query,
|
380
|
-
'pool_size': pool_size,
|
381
|
-
'max_overflow': max_overflow,
|
382
|
-
'pool_timeout': pool_timeout,
|
383
|
-
'pool_recycle': pool_recycle
|
384
|
-
}
|
385
|
-
|
386
|
-
return params
|
387
|
-
|
388
|
-
|
389
175
|
@overload
|
390
176
|
def extract_path(
|
391
177
|
self,
|
@@ -478,30 +264,27 @@ class Database(DatabaseBase):
|
|
478
264
|
"""
|
479
265
|
|
480
266
|
# Get.
|
481
|
-
|
482
|
-
|
267
|
+
url_params = extract_url(self.url)
|
268
|
+
backend = url_params['backend']
|
483
269
|
|
484
|
-
return
|
270
|
+
return backend
|
485
271
|
|
486
272
|
|
487
273
|
@property
|
488
|
-
def driver(self) -> str
|
274
|
+
def driver(self) -> str:
|
489
275
|
"""
|
490
276
|
Database driver name.
|
491
277
|
|
492
278
|
Returns
|
493
279
|
-------
|
494
|
-
|
280
|
+
Name.
|
495
281
|
"""
|
496
282
|
|
497
283
|
# Get.
|
498
|
-
|
499
|
-
|
500
|
-
value = value.lower()
|
501
|
-
else:
|
502
|
-
value = None
|
284
|
+
url_params = extract_url(self.url)
|
285
|
+
driver = url_params['driver']
|
503
286
|
|
504
|
-
return
|
287
|
+
return driver
|
505
288
|
|
506
289
|
|
507
290
|
@property
|
@@ -542,16 +325,20 @@ class Database(DatabaseBase):
|
|
542
325
|
|
543
326
|
# Generate URL.
|
544
327
|
|
545
|
-
##
|
328
|
+
## Server.
|
546
329
|
if self.mode == 'server':
|
547
330
|
password = urllib_quote(self.password)
|
548
|
-
url_ = f'
|
331
|
+
url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}'
|
549
332
|
if self.database is not None:
|
550
333
|
url_ = f'{url_}/{self.database}'
|
551
334
|
|
552
|
-
## File
|
335
|
+
## File.
|
336
|
+
elif self.mode == 'file':
|
337
|
+
url_ = f'sqlite:///{self.database}'
|
338
|
+
|
339
|
+
## Memory.
|
553
340
|
else:
|
554
|
-
url_ = f'
|
341
|
+
url_ = f'sqlite:///:memory:'
|
555
342
|
|
556
343
|
# Add Server parameter.
|
557
344
|
if self.query != {}:
|
@@ -576,44 +363,25 @@ class Database(DatabaseBase):
|
|
576
363
|
"""
|
577
364
|
|
578
365
|
# Handle parameter.
|
579
|
-
if
|
580
|
-
|
366
|
+
if self.mode == 'memory':
|
367
|
+
engine_params = {
|
368
|
+
'url': self.url,
|
369
|
+
'pool_recycle': self.pool_recycle
|
370
|
+
}
|
581
371
|
else:
|
582
|
-
|
372
|
+
engine_params = {
|
373
|
+
'url': self.url,
|
374
|
+
'pool_size': self.pool_size,
|
375
|
+
'max_overflow': self.max_overflow,
|
376
|
+
'pool_timeout': self.pool_timeout,
|
377
|
+
'pool_recycle': self.pool_recycle,
|
378
|
+
'connect_args': {'client_flag': MULTI_STATEMENTS}
|
379
|
+
}
|
583
380
|
|
584
381
|
# Create Engine.
|
585
|
-
|
586
|
-
self.drivername = drivername
|
587
|
-
if self.mode == 'memory':
|
588
|
-
engine_params = {
|
589
|
-
'url': self.url,
|
590
|
-
'pool_recycle': self.pool_recycle
|
591
|
-
}
|
592
|
-
else:
|
593
|
-
engine_params = {
|
594
|
-
'url': self.url,
|
595
|
-
'pool_size': self.pool_size,
|
596
|
-
'max_overflow': self.max_overflow,
|
597
|
-
'pool_timeout': self.pool_timeout,
|
598
|
-
'pool_recycle': self.pool_recycle
|
599
|
-
}
|
600
|
-
|
601
|
-
## Try.
|
602
|
-
try:
|
603
|
-
engine = sqlalchemy_create_engine(**engine_params)
|
604
|
-
except ModuleNotFoundError:
|
605
|
-
pass
|
606
|
-
else:
|
607
|
-
return engine
|
382
|
+
engine = sqlalchemy_create_engine(**engine_params)
|
608
383
|
|
609
|
-
|
610
|
-
drivernames_str = ' and '.join(
|
611
|
-
[
|
612
|
-
"'%s'" % dirvername.split('+', 1)[-1]
|
613
|
-
for dirvername in drivernames
|
614
|
-
]
|
615
|
-
)
|
616
|
-
raise ModuleNotFoundError(f'module {drivernames_str} not fund')
|
384
|
+
return engine
|
617
385
|
|
618
386
|
|
619
387
|
@property
|
@@ -1793,9 +1561,10 @@ class Database(DatabaseBase):
|
|
1793
1561
|
Schemata of databases and tables and columns.
|
1794
1562
|
"""
|
1795
1563
|
|
1796
|
-
#
|
1564
|
+
# Check.
|
1797
1565
|
if self.backend == 'sqlite':
|
1798
|
-
|
1566
|
+
text = 'not suitable for SQLite databases'
|
1567
|
+
throw(AssertionError, text=text)
|
1799
1568
|
|
1800
1569
|
# Handle parameter.
|
1801
1570
|
filter_db = (
|
reydb/rerror.py
CHANGED
reydb/rfile.py
CHANGED
@@ -43,9 +43,9 @@ class DatabaseFile(DatabaseBase):
|
|
43
43
|
database : Database or DatabaseConnection instance.
|
44
44
|
"""
|
45
45
|
|
46
|
-
#
|
46
|
+
# Check.
|
47
47
|
if database.backend == 'sqlite':
|
48
|
-
text='not suitable for SQLite databases'
|
48
|
+
text = 'not suitable for SQLite databases'
|
49
49
|
throw(AssertionError, text=text)
|
50
50
|
|
51
51
|
# Build.
|
reydb/rparam.py
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
reydb/__init__.py,sha256=SqjJEBMiUMnKkNfmOvw_jprZcj9Edi0jyBKt67xeYUE,544
|
2
|
+
reydb/rall.py,sha256=UWnbtl4oG4YqXyqTMN_5uqE-QqD5nb_-dvarotlTUeU,388
|
3
|
+
reydb/rbase.py,sha256=LQ1r4wh5SolOH5MbkMMwLb4I0Sq8HxDrthgdFp9cdYQ,4837
|
4
|
+
reydb/rbuild.py,sha256=iXJ76BNlUflJfMAAEbPuQLyVePyye8aDq7MaXD16Ktw,32419
|
5
|
+
reydb/rconfig.py,sha256=1uQG-khhkupKgzC51nYku3P__-qdaSXZB13GdDyKy00,12312
|
6
|
+
reydb/rconn.py,sha256=YWscFMjBph9ttPXjzTTpaziTd7v7vnE0b7E4mVpJ6oc,6163
|
7
|
+
reydb/rdb.py,sha256=cSh5qVRhkQQVAuYemYOD0MGtJtYIIBGhrjapeiy6sFE,54207
|
8
|
+
reydb/rerror.py,sha256=lirCR6yv1-9JsC6ZIKCkS0ezcNojAOAbJpup2xtsyx0,9968
|
9
|
+
reydb/rexec.py,sha256=dGdRkG1XR0Z66T0r4nPCSdQzSRWc_Q3t6TPSSrDTIxY,9042
|
10
|
+
reydb/rfile.py,sha256=JoXI_YgR5TDR7kh06eU0TngEOkSW8DmcZ4SDjTl22Wk,15255
|
11
|
+
reydb/rinfo.py,sha256=KXTkcpTGAD3p9RVKKcnmc_FjJtiKRPk-K5ZepPOnphQ,15253
|
12
|
+
reydb/rparam.py,sha256=VTHBW4gnBjLtITrv73Rtb1Ppw3UJu_LXeKy2tJuGIBE,7016
|
13
|
+
reydb-1.1.39.dist-info/METADATA,sha256=_hw0AJJ6kGH7Y0ZvVL3O4OOIs_o7l1peP7C81NAby4I,1550
|
14
|
+
reydb-1.1.39.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
15
|
+
reydb-1.1.39.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
16
|
+
reydb-1.1.39.dist-info/RECORD,,
|
reydb-1.1.37.dist-info/RECORD
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
reydb/__init__.py,sha256=SqjJEBMiUMnKkNfmOvw_jprZcj9Edi0jyBKt67xeYUE,544
|
2
|
-
reydb/rall.py,sha256=UWnbtl4oG4YqXyqTMN_5uqE-QqD5nb_-dvarotlTUeU,388
|
3
|
-
reydb/rbase.py,sha256=X8bDBmKyIiLXGvOVnTh5nD0ltkhOPWU6g4BebifOZYY,312
|
4
|
-
reydb/rbuild.py,sha256=s4lLVQONfL5a9B6mw5D7bfbPyJoYNIqBxlas9rCM1Y8,32458
|
5
|
-
reydb/rconfig.py,sha256=7xcgoN9iRwXxQJjy-J5nJxXVWpBDjFlmebAhqgMOlKA,12310
|
6
|
-
reydb/rconn.py,sha256=kdw2xQb0JqSUXM-BD7XfJ-ZqaWHxYkeT8psRhOK43mA,6211
|
7
|
-
reydb/rdb.py,sha256=OQ3ztC4G53usAbocqGwTqo1ry1AIGjoWTN7pn8Pn3Uk,62184
|
8
|
-
reydb/rerror.py,sha256=xHLvRxu8KBvUdfVS7mD906jx9XTQPGwEl7psBLGEZ5w,9966
|
9
|
-
reydb/rexec.py,sha256=dGdRkG1XR0Z66T0r4nPCSdQzSRWc_Q3t6TPSSrDTIxY,9042
|
10
|
-
reydb/rfile.py,sha256=7g6hPBz33p-mkGFc6LEmL2hpFes-LM-AWQ0SxgJe2BI,15254
|
11
|
-
reydb/rinfo.py,sha256=KXTkcpTGAD3p9RVKKcnmc_FjJtiKRPk-K5ZepPOnphQ,15253
|
12
|
-
reydb/rparam.py,sha256=3BGDBD8QshOf2J70ZJ6LJ9PiH-1ZU3ruZwoE0bN6OOw,7017
|
13
|
-
reydb-1.1.37.dist-info/METADATA,sha256=8rl-hgsdLLZBhuXi4syRQ830G_I4a6KT48Kp2YpAMSw,1550
|
14
|
-
reydb-1.1.37.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
15
|
-
reydb-1.1.37.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
|
16
|
-
reydb-1.1.37.dist-info/RECORD,,
|
File without changes
|
File without changes
|