reydb 1.2.19__py3-none-any.whl → 1.2.20__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,595 +2,124 @@
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
18
-
19
- from . import rbase, rbuild, rconfig, rconn, rerror, rexec, rinfo, rorm
20
-
21
-
22
- __all__ = (
23
- 'DatabaseSuper',
24
- 'Database',
25
- 'DatabaseAsync'
26
- )
27
-
28
-
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
- )
59
-
60
-
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
- ):
77
- """
78
- Database super type, based `MySQL`.
79
- """
80
-
81
-
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:
96
- """
97
- 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
- """
115
-
116
- # Parameter.
117
- if type(port) == str:
118
- port = int(port)
119
-
120
- # 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
12
+ from typing import TypeVar, Generic, Self, Type
13
+ from functools import wraps as functools_wraps
14
+ from reykit.rbase import CallableT, warn
181
15
 
16
+ from .rbase import DatabaseBase
17
+ from .rengine import DatabaseEngine, DatabaseEngineAsync
182
18
 
183
- @property
184
- def driver(self) -> str:
185
- """
186
- Database driver name.
187
-
188
- Returns
189
- -------
190
- Name.
191
- """
192
19
 
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
- """
20
+ DatabaseEngineT = TypeVar('DatabaseEngineT', DatabaseEngine, DatabaseEngineAsync)
209
21
 
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}'
217
22
 
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
-
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
23
+ class DatabaseSuper(DatabaseBase, Generic[DatabaseEngineT]):
24
+ """
25
+ Database super type.
26
+ """
258
27
 
259
28
 
260
- @property
261
- def conn_count(self) -> tuple[int, int]:
29
+ def __init__(self):
262
30
  """
263
- Count number of keep open and allowed overflow connection.
264
-
265
- Returns
266
- -------
267
- Number of keep open and allowed overflow connection.
31
+ Build instance attributes.
268
32
  """
269
33
 
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
34
+ # Build.
35
+ self.__engine_dict: dict[str, DatabaseEngineT] = {}
280
36
 
281
37
 
282
- def connect(self, autocommit: bool = False) -> DatabaseConnectionT:
38
+ @classmethod
39
+ def _wrap_add(
40
+ cls_or_self,
41
+ engine_type: Type[DatabaseEngine] | Type[DatabaseEngineAsync],
42
+ type_hint: CallableT
43
+ ) -> CallableT:
283
44
  """
284
- Build database connection instance.
45
+ Decorator, create and add database engine.
285
46
 
286
47
  Parameters
287
48
  ----------
288
- autocommit: Whether automatic commit execute.
289
-
290
- Returns
291
- -------
292
- Database connection instance.
293
- """
294
-
295
- # Build.
296
- match self:
297
- case Database():
298
- conn = rconn.DatabaseConnection(self, autocommit)
299
- case DatabaseAsync():
300
- conn = rconn.DatabaseConnectionAsync(self, autocommit)
301
-
302
- return conn
303
-
304
-
305
- @property
306
- def execute(self) -> DatabaseExecuteT:
307
- """
308
- Build database execute instance.
309
-
310
- Returns
311
- -------
312
- Instance.
313
- """
314
-
315
- # Build.
316
- conn = self.connect(True)
317
- exec = conn.execute
318
-
319
- return exec
320
-
321
-
322
- @property
323
- def orm(self) -> DatabaseORMT:
324
- """
325
- Build database ORM instance.
326
-
327
- Returns
328
- -------
329
- Instance.
330
- """
331
-
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.
49
+ engine_type : Database engine type.
50
+ type_hint : Type hint.
366
51
 
367
52
  Returns
368
53
  -------
369
- Instance.
54
+ Decorated method.
370
55
  """
371
56
 
372
- # Build.
373
- match self:
374
- case Database():
375
- error = rerror.DatabaseError(self)
376
- case DatabaseAsync():
377
- error = rerror.DatabaseErrorAsync(self)
378
57
 
379
- return error
58
+ @functools_wraps(engine_type.__init__)
59
+ def func(self: Self, *args, **kwargs):
380
60
 
61
+ # Build.
62
+ engine: DatabaseEngineT = engine_type(*args, **kwargs)
381
63
 
382
- @property
383
- def config(self) -> DatabaseConfigT:
384
- """
385
- Build database config instance.
64
+ # Warning.
65
+ if engine.database in self.__engine_dict:
66
+ warn(f'database engine "{engine.database}" re registered.')
386
67
 
387
- Returns
388
- -------
389
- Instance.
390
- """
68
+ # Add.
69
+ self.__engine_dict[engine.database] = engine
391
70
 
392
- # Build.
393
- match self:
394
- case Database():
395
- config = rconfig.DatabaseConfig(self)
396
- case DatabaseAsync():
397
- config = rconfig.DatabaseConfigAsync(self)
71
+ return engine
398
72
 
399
- return config
400
73
 
74
+ return func
401
75
 
402
- @property
403
- def schema(self) -> DatabaseInformationSchemaT:
404
- """
405
- Build database schema instance.
406
76
 
407
- Returns
408
- -------
409
- Instance.
77
+ def __getitem__(self, database: str) -> DatabaseEngineT:
410
78
  """
79
+ Get added database engine.
411
80
 
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.
81
+ Parameters
82
+ ----------
83
+ database : Database name.
430
84
  """
431
85
 
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
440
-
441
-
442
- @property
443
- def stat(self) -> DatabaseInformationParameterVariablesT:
444
- """
445
- Build database parameters status instance.
86
+ # Get.
87
+ engine = self.__engine_dict[database]
446
88
 
447
- Returns
448
- -------
449
- Instance.
450
- """
89
+ return engine
451
90
 
452
- # Build.
453
- match self:
454
- case Database():
455
- stat = rinfo.DatabaseInformationParameterStatus(self)
456
- case DatabaseAsync():
457
- stat = rinfo.DatabaseInformationParameterStatusAsync(self)
458
91
 
459
- return stat
92
+ __getattr__ = __getitem__
460
93
 
461
94
 
462
- @property
463
- def glob_var(self) -> DatabaseInformationParameterVariablesGlobalT:
95
+ def __contains__(self, database: str) -> bool:
464
96
  """
465
- Build global database parameters variable instance.
97
+ Whether the exist this database engine.
466
98
 
467
- Returns
468
- -------
469
- Instance.
99
+ Parameters
100
+ ----------
101
+ database : Database name.
470
102
  """
471
103
 
472
- # Build.
473
- match self:
474
- case Database():
475
- var = rinfo.DatabaseInformationParameterVariablesGlobal(self)
476
- case DatabaseAsync():
477
- var = rinfo.DatabaseInformationParameterVariablesGlobalAsync(self)
104
+ # Judge.
105
+ result = database in self.__engine_dict
478
106
 
479
- return var
107
+ return result
480
108
 
481
109
 
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
- ):
110
+ class Database(DatabaseSuper[DatabaseEngine]):
517
111
  """
518
- Database type, based `MySQL`.
112
+ Database type.
519
113
  """
520
114
 
521
115
 
522
- @property
523
- def async_database(self) -> 'DatabaseAsync':
524
- """
525
- Same engine `DatabaseAsync` instance.
526
- """
116
+ __call__ = DatabaseSuper._wrap_add(DatabaseEngine, DatabaseEngine.__init__)
527
117
 
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
- ):
118
+
119
+ class DatabaseAsync(DatabaseSuper[DatabaseEngineAsync]):
561
120
  """
562
- Asynchronous database type, based `MySQL`.
121
+ Asynchronous database type.
563
122
  """
564
123
 
565
124
 
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()
125
+ __call__ = DatabaseSuper._wrap_add(DatabaseEngineAsync, DatabaseEngineAsync.__init__)