reydb 1.1.38__py3-none-any.whl → 1.1.40__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 CHANGED
@@ -9,11 +9,33 @@
9
9
  """
10
10
 
11
11
 
12
- from reykit.rbase import Base
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
13
17
 
14
18
 
15
19
  __all__ = (
16
20
  'DatabaseBase',
21
+ 'extract_url',
22
+ 'extract_engine'
23
+ )
24
+
25
+
26
+ URLParameter = TypedDict(
27
+ 'URLParameter',
28
+ {
29
+ 'drivername': str,
30
+ 'backend': str,
31
+ 'driver': str | None,
32
+ 'username': str | None,
33
+ 'password': str | None,
34
+ 'host': str | None,
35
+ 'port': str | None,
36
+ 'database': str | None,
37
+ 'query': dict[str, str] | None
38
+ }
17
39
  )
18
40
 
19
41
 
@@ -21,3 +43,147 @@ class DatabaseBase(Base):
21
43
  """
22
44
  Database base type.
23
45
  """
46
+
47
+
48
+ def extract_url(url: str | URL) -> URLParameter:
49
+ """
50
+ Extract parameters from URL of string.
51
+
52
+ Parameters
53
+ ----------
54
+ url : URL of string.
55
+
56
+ Returns
57
+ -------
58
+ URL parameters.
59
+ """
60
+
61
+ # Extract.
62
+ match url:
63
+
64
+ ## Type str.
65
+ case str():
66
+ pattern_remote = r'^([^+]+)\+?([^:]+)??://([^:]+):([^@]+)@([^:]+):(\d+)[/]?([^\?]+)?\??(\S+)?$'
67
+ pattern_local = r'^([^+]+)\+?([^:]+)??:////?([^\?]+)[\?]?(\S+)?$'
68
+
69
+ ### Server.
70
+ if (result_remote := search(pattern_remote, url)) is not None:
71
+ (
72
+ backend,
73
+ driver,
74
+ username,
75
+ password,
76
+ host,
77
+ port,
78
+ database,
79
+ query_str
80
+ ) = result_remote
81
+ port = int(port)
82
+
83
+ ### SQLite.
84
+ elif (result_local := search(pattern_local, url)) is not None:
85
+ username = password = host = port = None
86
+ (
87
+ backend,
88
+ driver,
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
+ ## Drivername.
117
+ if driver is None:
118
+ drivername = backend
119
+ else:
120
+ drivername = f'{backend}+{driver}'
121
+
122
+ # Generate parameter.
123
+ params = {
124
+ 'drivername': drivername,
125
+ 'backend': backend,
126
+ 'driver': driver,
127
+ 'username': username,
128
+ 'password': password,
129
+ 'host': host,
130
+ 'port': port,
131
+ 'database': database,
132
+ 'query': query
133
+ }
134
+
135
+ return params
136
+
137
+
138
+ def extract_engine(engine: Engine | Connection) -> dict[
139
+ Literal[
140
+ 'drivername', 'username', 'password', 'host', 'port', 'database', 'query',
141
+ 'pool_size', 'max_overflow', 'pool_timeout', 'pool_recycle'
142
+ ],
143
+ Any
144
+ ]:
145
+ """
146
+ Extract parameters from `Engine` or `Connection` object.
147
+
148
+ Parameters
149
+ ----------
150
+ engine : Engine or Connection object.
151
+
152
+ Returns
153
+ -------
154
+ Extracted parameters.
155
+ """
156
+
157
+ ## Extract Engine object from Connection boject.
158
+ if type(engine) == Connection:
159
+ engine = engine.engine
160
+
161
+ ## Extract.
162
+ drivername: str = engine.url.drivername
163
+ username: str | None = engine.url.username
164
+ password: str | None = engine.url.password
165
+ host: str | None = engine.url.host
166
+ port: str | None = engine.url.port
167
+ database: str | None = engine.url.database
168
+ query: dict[str, str] = dict(engine.url.query)
169
+ pool_size: int = engine.pool._pool.maxsize
170
+ max_overflow: int = engine.pool._max_overflow
171
+ pool_timeout: float = engine.pool._timeout
172
+ pool_recycle: int = engine.pool._recycle
173
+
174
+ # Generate parameter.
175
+ params = {
176
+ 'drivername': drivername,
177
+ 'username': username,
178
+ 'password': password,
179
+ 'host': host,
180
+ 'port': port,
181
+ 'database': database,
182
+ 'query': query,
183
+ 'pool_size': pool_size,
184
+ 'max_overflow': max_overflow,
185
+ 'pool_timeout': pool_timeout,
186
+ 'pool_recycle': pool_recycle
187
+ }
188
+
189
+ return params
reydb/rbuild.py CHANGED
@@ -52,22 +52,22 @@ class DatabaseBuild(DatabaseBase):
52
52
  """
53
53
 
54
54
 
55
- def __init__(self, rdatabase: Database | DatabaseConnection) -> None:
55
+ def __init__(self, database: Database | DatabaseConnection) -> None:
56
56
  """
57
57
  Build instance attributes.
58
58
 
59
59
  Parameters
60
60
  ----------
61
- rdatabase : Database or DatabaseConnection instance.
61
+ database : Database or DatabaseConnection instance.
62
62
  """
63
63
 
64
64
  # SQLite.
65
- if rdatabase.backend == 'sqlite':
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.rdatabase = rdatabase
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.rdatabase.execute(sql)
101
+ self.database.execute(sql)
102
102
 
103
103
  return sql
104
104
 
@@ -285,7 +285,7 @@ class DatabaseBuild(DatabaseBase):
285
285
  """
286
286
 
287
287
  # Handle parameter.
288
- database, table, _ = self.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path, 'database')
992
+ database, table, column = self.database.extract_path(path, 'database')
993
993
  if self._schema is None:
994
- self._schema = self.rdatabase.schema(False)
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.rdatabase.build.exist((database, None, None))
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
1104
+ database, table, _ = self.database.extract_path(path)
1105
1105
 
1106
1106
  ## Exist.
1107
- exist = self.rdatabase.build.exist((database, table, None))
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
1127
+ database, view, _ = self.database.extract_path(path)
1128
1128
 
1129
1129
  ## Exist.
1130
- exist = self.rdatabase.build.exist((database, view, None))
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.rdatabase.execute(sql)
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.rdatabase.extract_path(path)
1150
+ database, view, _ = self.database.extract_path(path)
1151
1151
 
1152
1152
  ## Exist.
1153
- exist = self.rdatabase.build.exist((database, view, None))
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.rdatabase.execute(sql)
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
@@ -56,7 +56,7 @@ class DatabaseConfig(object):
56
56
 
57
57
  # SQLite.
58
58
  if database.backend == 'sqlite':
59
- text='not suitable for SQLite databases'
59
+ text = 'not suitable for SQLite databases'
60
60
  throw(AssertionError, text=text)
61
61
 
62
62
  # Build.
reydb/rconn.py CHANGED
@@ -52,7 +52,6 @@ class DatabaseConnection(Database):
52
52
  self.rdatabase = rdatabase
53
53
  self.begin = None
54
54
  self.begin_count = 0
55
- self.drivername = rdatabase.drivername
56
55
  self.username = rdatabase.username
57
56
  self.password = rdatabase.password
58
57
  self.host = rdatabase.host
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 or use memory.
153
- When parameters `host`, `port`, `username`, `password`, `database` are all `None`, then is `:memory:`.
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
- # Set attribute.
210
- self.username: str | None = username
211
- self.password: str | None = password
212
- self.host: str | None = 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: str | None = database
215
- self.drivername: str | Iterable[str] = drivername
216
- self.engine: Engine | None = engine
217
- self.pool_size: int = pool_size
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: bool = retry
225
- self.query: dict[str, str] = 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
- if self.engine is None:
239
- self.engine = self.__create_engine()
240
- self.drivername: str
164
+ self.engine = self.__create_engine()
241
165
 
242
- # Handle attribute.
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
- value, *_ = self.drivername.split('+', 1)
482
- value = value.lower()
267
+ url_params = extract_url(self.url)
268
+ backend = url_params['backend']
483
269
 
484
- return value
270
+ return backend
485
271
 
486
272
 
487
273
  @property
488
- def driver(self) -> str | None:
274
+ def driver(self) -> str:
489
275
  """
490
276
  Database driver name.
491
277
 
492
278
  Returns
493
279
  -------
494
- name.
280
+ Name.
495
281
  """
496
282
 
497
283
  # Get.
498
- if '+' in self.drivername:
499
- _, value = self.drivername.split('+', 1)
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 value
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
- ## Remove.
328
+ ## Server.
546
329
  if self.mode == 'server':
547
330
  password = urllib_quote(self.password)
548
- url_ = f'{self.drivername}://{self.username}:{password}@{self.host}:{self.port}'
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 or memory.
335
+ ## File.
336
+ elif self.mode == 'file':
337
+ url_ = f'sqlite:///{self.database}'
338
+
339
+ ## Memory.
553
340
  else:
554
- url_ = f'{self.drivername}:///{self.database}'
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 type(self.drivername) == str:
580
- drivernames = (self.drivername,)
366
+ if self.mode == 'memory':
367
+ engine_params = {
368
+ 'url': self.url,
369
+ 'pool_recycle': self.pool_recycle
370
+ }
581
371
  else:
582
- drivernames = self.drivername
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
- for drivername in drivernames:
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
- # Throw exception.
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
- # SQLite.
1564
+ # Check.
1797
1565
  if self.backend == 'sqlite':
1798
- throw(AssertionError, self.drivername)
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
@@ -43,7 +43,7 @@ class DatabaseError(DatabaseBase):
43
43
 
44
44
  # SQLite.
45
45
  if database.backend == 'sqlite':
46
- text='not suitable for SQLite databases'
46
+ text = 'not suitable for SQLite databases'
47
47
  throw(AssertionError, text=text)
48
48
 
49
49
  # Build.
reydb/rfile.py CHANGED
@@ -43,9 +43,9 @@ class DatabaseFile(DatabaseBase):
43
43
  database : Database or DatabaseConnection instance.
44
44
  """
45
45
 
46
- # SQLite.
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
@@ -26,7 +26,7 @@ __all__ = (
26
26
 
27
27
  class DatabaseParameter(DatabaseBase):
28
28
  """
29
- Database parameters type.
29
+ Database parameter type.
30
30
  """
31
31
 
32
32
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reydb
3
- Version: 1.1.38
3
+ Version: 1.1.40
4
4
  Summary: Database method set.
5
5
  Project-URL: homepage, https://github.com/reyxbo/reydb/
6
6
  Author-email: Rey <reyxbo@163.com>
@@ -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=2mP7vSpJHLt-wFkL8tpehYMMIfysyh1Ktg0cR9fjnJk,4821
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.40.dist-info/METADATA,sha256=xQvsJCsasRZEuXV4Aa9eS6IBGKgbXw38vVazAUpcZ0w,1550
14
+ reydb-1.1.40.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ reydb-1.1.40.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
16
+ reydb-1.1.40.dist-info/RECORD,,
@@ -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=nGI25Hoj3iWuyRGJhXQWFNJfq5jASzoGOpJL-B9IwE4,32456
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.38.dist-info/METADATA,sha256=rZepbu5fXPQ4IgwbzryzEymQbedw2NvcYi0oJlQnGVI,1550
14
- reydb-1.1.38.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- reydb-1.1.38.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
16
- reydb-1.1.38.dist-info/RECORD,,
File without changes