reydb 1.2.19__py3-none-any.whl → 1.2.21__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/rdb.py CHANGED
@@ -2,21 +2,19 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- @Time : 2022-12-05 14:10:02
5
+ @Time : 2025-10-09
6
6
  @Author : Rey
7
7
  @Contact : reyxbo@163.com
8
8
  @Explain : Database methods.
9
9
  """
10
10
 
11
11
 
12
- from typing import TypeVar, Generic, overload
13
- from urllib.parse import quote as urllib_quote
14
- from pymysql.constants.CLIENT import MULTI_STATEMENTS
15
- from sqlalchemy import Engine, create_engine as sqlalchemy_create_engine
16
- from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine as sqlalchemy_create_async_engine
17
- from reykit.rtext import join_data_text
12
+ from typing import TypeVar, Generic, Self, Type
13
+ from functools import wraps as functools_wraps
14
+ from reykit.rbase import CallableT, Null, throw, warn
18
15
 
19
- from . import rbase, rbuild, rconfig, rconn, rerror, rexec, rinfo, rorm
16
+ from .rbase import DatabaseBase
17
+ from .rengine import DatabaseEngine, DatabaseEngineAsync
20
18
 
21
19
 
22
20
  __all__ = (
@@ -26,571 +24,114 @@ __all__ = (
26
24
  )
27
25
 
28
26
 
29
- DatabaseConnectionT = TypeVar('DatabaseConnectionT', 'rconn.DatabaseConnection', 'rconn.DatabaseConnectionAsync')
30
- DatabaseExecuteT = TypeVar('DatabaseExecuteT', 'rexec.DatabaseExecute', 'rexec.DatabaseExecuteAsync')
31
- DatabaseORMT = TypeVar('DatabaseORMT', 'rorm.DatabaseORM', 'rorm.DatabaseORMAsync')
32
- DatabaseBuildT = TypeVar('DatabaseBuildT', 'rbuild.DatabaseBuild', 'rbuild.DatabaseBuildAsync')
33
- DatabaseConfigT = TypeVar('DatabaseConfigT', 'rconfig.DatabaseConfig', 'rconfig.DatabaseConfigAsync')
34
- DatabaseInformationSchemaT = TypeVar(
35
- 'DatabaseInformationSchemaT',
36
- 'rinfo.DatabaseInformationSchema',
37
- 'rinfo.DatabaseInformationSchemaAsync'
38
- )
39
- DatabaseInformationParameterVariablesT = TypeVar(
40
- 'DatabaseInformationParameterVariablesT',
41
- 'rinfo.DatabaseInformationParameterVariables',
42
- 'rinfo.DatabaseInformationParameterVariablesAsync'
43
- )
44
- DatabaseInformationParameterStatusT = TypeVar(
45
- 'DatabaseInformationParameterStatusT',
46
- 'rinfo.DatabaseInformationParameterStatus',
47
- 'rinfo.DatabaseInformationParameterStatusAsync'
48
- )
49
- DatabaseInformationParameterVariablesGlobalT = TypeVar(
50
- 'DatabaseInformationParameterVariablesGlobalT',
51
- 'rinfo.DatabaseInformationParameterVariablesGlobal',
52
- 'rinfo.DatabaseInformationParameterVariablesGlobalAsync'
53
- )
54
- DatabaseInformationParameterStatusGlobalT = TypeVar(
55
- 'DatabaseInformationParameterStatusGlobalT',
56
- 'rinfo.DatabaseInformationParameterStatusGlobal',
57
- 'rinfo.DatabaseInformationParameterStatusGlobalAsync'
58
- )
27
+ DatabaseEngineT = TypeVar('DatabaseEngineT', DatabaseEngine, DatabaseEngineAsync)
59
28
 
60
29
 
61
- class DatabaseSuper(
62
- rbase.DatabaseBase,
63
- Generic[
64
- rbase.EngineT,
65
- DatabaseConnectionT,
66
- DatabaseExecuteT,
67
- DatabaseORMT,
68
- DatabaseBuildT,
69
- DatabaseConfigT,
70
- DatabaseInformationSchemaT,
71
- DatabaseInformationParameterVariablesT,
72
- DatabaseInformationParameterStatusT,
73
- DatabaseInformationParameterVariablesGlobalT,
74
- DatabaseInformationParameterStatusGlobalT
75
- ]
76
- ):
30
+ class DatabaseSuper(DatabaseBase, Generic[DatabaseEngineT]):
77
31
  """
78
- Database super type, based `MySQL`.
32
+ Database super type.
79
33
  """
80
34
 
81
35
 
82
- def __init__(
83
- self,
84
- host: str,
85
- port: int | str,
86
- username: str,
87
- password: str,
88
- database: str,
89
- pool_size: int = 5,
90
- max_overflow: int = 10,
91
- pool_timeout: float = 30.0,
92
- pool_recycle: int | None = 3600,
93
- echo: bool = False,
94
- **query: str
95
- ) -> None:
36
+ def __init__(self):
96
37
  """
97
38
  Build instance attributes.
98
-
99
- Parameters
100
- ----------
101
- host : Remote server database host.
102
- port : Remote server database port.
103
- username : Remote server database username.
104
- password : Remote server database password.
105
- database : Remote server database name.
106
- pool_size : Number of connections `keep open`.
107
- max_overflow : Number of connections `allowed overflow`.
108
- pool_timeout : Number of seconds `wait create` connection.
109
- pool_recycle : Number of seconds `recycle` connection.
110
- - `None | Literal[-1]`: No recycle.
111
- - `int`: Use this value.
112
- echo : Whether report SQL execute information, not include ORM execute.
113
- query : Remote server database parameters.
114
39
  """
115
40
 
116
- # Parameter.
117
- if type(port) == str:
118
- port = int(port)
119
-
120
41
  # Build.
121
- self.username = username
122
- self.password = password
123
- self.host = host
124
- self.port: int | None = port
125
- self.database = database
126
- self.pool_size = pool_size
127
- self.max_overflow = max_overflow
128
- self.pool_timeout = pool_timeout
129
- if pool_recycle is None:
130
- self.pool_recycle = -1
131
- else:
132
- self.pool_recycle = pool_recycle
133
- self.echo = echo
134
- self.query = query
135
-
136
- ## Schema.
137
- self._schema: dict[str, dict[str, list[str]]] | None = None
138
-
139
- ## Create engine.
140
- self.engine = self.__create_engine()
141
-
142
-
143
- def __str__(self) -> str:
144
- """
145
- Return connection information text.
146
- """
147
-
148
- # Generate.
149
- filter_key = (
150
- 'engine',
151
- 'connection',
152
- 'rdatabase',
153
- 'begin'
154
- )
155
- info = {
156
- key: value
157
- for key, value in self.__dict__.items()
158
- if key not in filter_key
159
- }
160
- info['conn_count'] = self.conn_count
161
- text = join_data_text(info)
162
-
163
- return text
164
-
165
-
166
- @property
167
- def backend(self) -> str:
168
- """
169
- Database backend name.
170
-
171
- Returns
172
- -------
173
- Name.
174
- """
175
-
176
- # Get.
177
- url_params = rbase.extract_url(self.url)
178
- backend = url_params['backend']
179
-
180
- return backend
181
-
182
-
183
- @property
184
- def driver(self) -> str:
185
- """
186
- Database driver name.
187
-
188
- Returns
189
- -------
190
- Name.
191
- """
192
-
193
- # Get.
194
- url_params = rbase.extract_url(self.url)
195
- driver = url_params['driver']
196
-
197
- return driver
198
-
199
-
200
- @property
201
- def url(self) -> str:
202
- """
203
- Generate server URL.
204
-
205
- Returns
206
- -------
207
- Server URL.
208
- """
209
-
210
- # Generate URL.
211
- password = urllib_quote(self.password)
212
- match self:
213
- case Database():
214
- url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
215
- case DatabaseAsync():
216
- url_ = f'mysql+aiomysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
42
+ self.__engine_dict: dict[str, DatabaseEngineT] = {}
217
43
 
218
- # Add Server parameter.
219
- if self.query != {}:
220
- query = '&'.join(
221
- [
222
- f'{key}={value}'
223
- for key, value in self.query.items()
224
- ]
225
- )
226
- url_ = f'{url_}?{query}'
227
44
 
228
- return url_
229
-
230
-
231
- def __create_engine(self) -> rbase.EngineT:
232
- """
233
- Create database `Engine` object.
234
-
235
- Returns
236
- -------
237
- Engine object.
238
- """
239
-
240
- # Parameter.
241
- engine_params = {
242
- 'url': self.url,
243
- 'pool_size': self.pool_size,
244
- 'max_overflow': self.max_overflow,
245
- 'pool_timeout': self.pool_timeout,
246
- 'pool_recycle': self.pool_recycle,
247
- 'connect_args': {'client_flag': MULTI_STATEMENTS}
248
- }
249
-
250
- # Create Engine.
251
- match self:
252
- case Database():
253
- engine = sqlalchemy_create_engine(**engine_params)
254
- case DatabaseAsync():
255
- engine = sqlalchemy_create_async_engine(**engine_params)
256
-
257
- return engine
258
-
259
-
260
- @property
261
- def conn_count(self) -> tuple[int, int]:
262
- """
263
- Count number of keep open and allowed overflow connection.
264
-
265
- Returns
266
- -------
267
- Number of keep open and allowed overflow connection.
268
- """
269
-
270
- # Count.
271
- _overflow: int = self.engine.pool._overflow
272
- if _overflow < 0:
273
- keep_n = self.pool_size + _overflow
274
- overflow_n = 0
275
- else:
276
- keep_n = self.pool_size
277
- overflow_n = _overflow
278
-
279
- return keep_n, overflow_n
280
-
281
-
282
- def connect(self, autocommit: bool = False) -> DatabaseConnectionT:
45
+ @classmethod
46
+ def _wrap_add(
47
+ cls_or_self,
48
+ engine_type: Type[DatabaseEngine] | Type[DatabaseEngineAsync],
49
+ type_hint: CallableT
50
+ ) -> CallableT:
283
51
  """
284
- Build database connection instance.
52
+ Decorator, create and add database engine.
285
53
 
286
54
  Parameters
287
55
  ----------
288
- autocommit: Whether automatic commit execute.
56
+ engine_type : Database engine type.
57
+ type_hint : Type hint.
289
58
 
290
59
  Returns
291
60
  -------
292
- Database connection instance.
61
+ Decorated method.
293
62
  """
294
63
 
295
- # Build.
296
- match self:
297
- case Database():
298
- conn = rconn.DatabaseConnection(self, autocommit)
299
- case DatabaseAsync():
300
- conn = rconn.DatabaseConnectionAsync(self, autocommit)
301
64
 
302
- return conn
65
+ @functools_wraps(engine_type.__init__)
66
+ def func(self: Self, *args, **kwargs):
303
67
 
68
+ # Build.
69
+ engine: DatabaseEngineT = engine_type(*args, **kwargs)
304
70
 
305
- @property
306
- def execute(self) -> DatabaseExecuteT:
307
- """
308
- Build database execute instance.
71
+ # Warning.
72
+ if engine.database in self.__engine_dict:
73
+ warn(f'database engine "{engine.database}" re registered.')
309
74
 
310
- Returns
311
- -------
312
- Instance.
313
- """
75
+ # Add.
76
+ self.__engine_dict[engine.database] = engine
314
77
 
315
- # Build.
316
- conn = self.connect(True)
317
- exec = conn.execute
78
+ return engine
318
79
 
319
- return exec
320
80
 
81
+ return func
321
82
 
322
- @property
323
- def orm(self) -> DatabaseORMT:
324
- """
325
- Build database ORM instance.
326
83
 
327
- Returns
328
- -------
329
- Instance.
84
+ def __getattr__(self, database: str) -> DatabaseEngineT:
330
85
  """
86
+ Get added database engine.
331
87
 
332
- # Build.
333
- match self:
334
- case Database():
335
- orm = rorm.DatabaseORM(self)
336
- case DatabaseAsync():
337
- orm = rorm.DatabaseORMAsync(self)
338
-
339
- return orm
340
-
341
-
342
- @property
343
- def build(self) -> DatabaseBuildT:
344
- """
345
- Build database build instance.
346
-
347
- Returns
348
- -------
349
- Instance.
350
- """
351
-
352
- # Build.
353
- match self:
354
- case Database():
355
- build = rbuild.DatabaseBuild(self)
356
- case DatabaseAsync():
357
- build = rbuild.DatabaseBuildAsync(self)
358
-
359
- return build
360
-
361
-
362
- @property
363
- def error(self):
364
- """
365
- Build database error instance.
366
-
367
- Returns
368
- -------
369
- Instance.
370
- """
371
-
372
- # Build.
373
- match self:
374
- case Database():
375
- error = rerror.DatabaseError(self)
376
- case DatabaseAsync():
377
- error = rerror.DatabaseErrorAsync(self)
378
-
379
- return error
380
-
381
-
382
- @property
383
- def config(self) -> DatabaseConfigT:
384
- """
385
- Build database config instance.
386
-
387
- Returns
388
- -------
389
- Instance.
390
- """
391
-
392
- # Build.
393
- match self:
394
- case Database():
395
- config = rconfig.DatabaseConfig(self)
396
- case DatabaseAsync():
397
- config = rconfig.DatabaseConfigAsync(self)
398
-
399
- return config
400
-
401
-
402
- @property
403
- def schema(self) -> DatabaseInformationSchemaT:
404
- """
405
- Build database schema instance.
406
-
407
- Returns
408
- -------
409
- Instance.
410
- """
411
-
412
- # Build.
413
- match self:
414
- case Database():
415
- schema = rinfo.DatabaseInformationSchema(self)
416
- case DatabaseAsync():
417
- schema = rinfo.DatabaseInformationSchemaAsync(self)
418
-
419
- return schema
420
-
421
-
422
- @property
423
- def var(self) -> DatabaseInformationParameterVariablesT:
424
- """
425
- Build database parameters variable instance.
426
-
427
- Returns
428
- -------
429
- Instance.
88
+ Parameters
89
+ ----------
90
+ database : Database name.
430
91
  """
431
92
 
432
- # Build.
433
- match self:
434
- case Database():
435
- var = rinfo.DatabaseInformationParameterVariables(self)
436
- case DatabaseAsync():
437
- var = rinfo.DatabaseInformationParameterVariablesAsync(self)
438
-
439
- return var
93
+ # Get.
94
+ engine = self.__engine_dict.get(database, Null)
440
95
 
96
+ # Throw exception.
97
+ if engine == Null:
98
+ text = f"lack of database engine '{database}'"
99
+ throw(AssertionError, text=text)
441
100
 
442
- @property
443
- def stat(self) -> DatabaseInformationParameterVariablesT:
444
- """
445
- Build database parameters status instance.
446
-
447
- Returns
448
- -------
449
- Instance.
450
- """
101
+ return engine
451
102
 
452
- # Build.
453
- match self:
454
- case Database():
455
- stat = rinfo.DatabaseInformationParameterStatus(self)
456
- case DatabaseAsync():
457
- stat = rinfo.DatabaseInformationParameterStatusAsync(self)
458
103
 
459
- return stat
104
+ __getitem__ = __getattr__
460
105
 
461
106
 
462
- @property
463
- def glob_var(self) -> DatabaseInformationParameterVariablesGlobalT:
107
+ def __contains__(self, database: str) -> bool:
464
108
  """
465
- Build global database parameters variable instance.
109
+ Whether the exist this database engine.
466
110
 
467
- Returns
468
- -------
469
- Instance.
111
+ Parameters
112
+ ----------
113
+ database : Database name.
470
114
  """
471
115
 
472
- # Build.
473
- match self:
474
- case Database():
475
- var = rinfo.DatabaseInformationParameterVariablesGlobal(self)
476
- case DatabaseAsync():
477
- var = rinfo.DatabaseInformationParameterVariablesGlobalAsync(self)
116
+ # Judge.
117
+ result = database in self.__engine_dict
478
118
 
479
- return var
119
+ return result
480
120
 
481
121
 
482
- @property
483
- def glob_stat(self) -> DatabaseInformationParameterStatusGlobalT:
484
- """
485
- Build global database parameters status instance.
486
-
487
- Returns
488
- -------
489
- Instance.
490
- """
491
-
492
- # Build.
493
- match self:
494
- case Database():
495
- stat = rinfo.DatabaseInformationParameterStatusGlobal(self)
496
- case DatabaseAsync():
497
- stat = rinfo.DatabaseInformationParameterStatusGlobalAsync(self)
498
-
499
- return stat
500
-
501
-
502
- class Database(
503
- DatabaseSuper[
504
- Engine,
505
- 'rconn.DatabaseConnection',
506
- 'rexec.DatabaseExecute',
507
- 'rorm.DatabaseORM',
508
- 'rbuild.DatabaseBuild',
509
- 'rconfig.DatabaseConfig',
510
- 'rinfo.DatabaseInformationSchema',
511
- 'rinfo.DatabaseInformationParameterVariables',
512
- 'rinfo.DatabaseInformationParameterStatus',
513
- 'rinfo.DatabaseInformationParameterVariablesGlobal',
514
- 'rinfo.DatabaseInformationParameterStatusGlobal'
515
- ]
516
- ):
122
+ class Database(DatabaseSuper[DatabaseEngine]):
517
123
  """
518
- Database type, based `MySQL`.
124
+ Database type.
519
125
  """
520
126
 
521
127
 
522
- @property
523
- def async_database(self) -> 'DatabaseAsync':
524
- """
525
- Same engine `DatabaseAsync` instance.
526
- """
128
+ __call__ = DatabaseSuper._wrap_add(DatabaseEngine, DatabaseEngine.__init__)
527
129
 
528
- # Build.
529
- db = DatabaseAsync(
530
- self.host,
531
- self.port,
532
- self.username,
533
- self.password,
534
- self.database,
535
- self.pool_size,
536
- self.max_overflow,
537
- self.pool_timeout,
538
- self.pool_recycle,
539
- self.echo,
540
- **self.query
541
- )
542
-
543
- return db
544
-
545
-
546
- class DatabaseAsync(
547
- DatabaseSuper[
548
- AsyncEngine,
549
- 'rconn.DatabaseConnectionAsync',
550
- 'rexec.DatabaseExecuteAsync',
551
- 'rorm.DatabaseORMAsync',
552
- 'rbuild.DatabaseBuildAsync',
553
- 'rconfig.DatabaseConfigAsync',
554
- 'rinfo.DatabaseInformationSchemaAsync',
555
- 'rinfo.DatabaseInformationParameterVariablesAsync',
556
- 'rinfo.DatabaseInformationParameterStatusAsync',
557
- 'rinfo.DatabaseInformationParameterVariablesGlobalAsync',
558
- 'rinfo.DatabaseInformationParameterStatusGlobalAsync'
559
- ]
560
- ):
130
+
131
+ class DatabaseAsync(DatabaseSuper[DatabaseEngineAsync]):
561
132
  """
562
- Asynchronous database type, based `MySQL`.
133
+ Asynchronous database type.
563
134
  """
564
135
 
565
136
 
566
- @property
567
- def sync_database(self) -> Database:
568
- """
569
- Same engine `Database` instance.
570
- """
571
-
572
- # Build.
573
- db = Database(
574
- self.host,
575
- self.port,
576
- self.username,
577
- self.password,
578
- self.database,
579
- self.pool_size,
580
- self.max_overflow,
581
- self.pool_timeout,
582
- self.pool_recycle,
583
- self.echo,
584
- **self.query
585
- )
586
-
587
- return db
588
-
589
-
590
- async def dispose(self) -> None:
591
- """
592
- Dispose asynchronous connections.
593
- """
594
-
595
- # Dispose.
596
- await self.engine.dispose()
137
+ __call__ = DatabaseSuper._wrap_add(DatabaseEngineAsync, DatabaseEngineAsync.__init__)