reydb 1.2.18__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/rengine.py ADDED
@@ -0,0 +1,596 @@
1
+ # !/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ @Time : 2022-12-05
6
+ @Author : Rey
7
+ @Contact : reyxbo@163.com
8
+ @Explain : Database engine methods.
9
+ """
10
+
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
+ 'DatabaseEngineSuper',
24
+ 'DatabaseEngine',
25
+ 'DatabaseEngineAsync'
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 DatabaseEngineSuper(
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 engine 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
+ )
152
+ info = {
153
+ key: value
154
+ for key, value in self.__dict__.items()
155
+ if (
156
+ key not in filter_key
157
+ and key[0] != '_'
158
+ )
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 DatabaseEngine():
214
+ url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
215
+ case DatabaseEngineAsync():
216
+ url_ = f'mysql+aiomysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
217
+
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 DatabaseEngine():
253
+ engine = sqlalchemy_create_engine(**engine_params)
254
+ case DatabaseEngineAsync():
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:
283
+ """
284
+ Build database connection instance.
285
+
286
+ Parameters
287
+ ----------
288
+ autocommit: Whether automatic commit execute.
289
+
290
+ Returns
291
+ -------
292
+ Database connection instance.
293
+ """
294
+
295
+ # Build.
296
+ match self:
297
+ case DatabaseEngine():
298
+ conn = rconn.DatabaseConnection(self, autocommit)
299
+ case DatabaseEngineAsync():
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 DatabaseEngine():
335
+ orm = rorm.DatabaseORM(self)
336
+ case DatabaseEngineAsync():
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 DatabaseEngine():
355
+ build = rbuild.DatabaseBuild(self)
356
+ case DatabaseEngineAsync():
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 DatabaseEngine():
375
+ error = rerror.DatabaseError(self)
376
+ case DatabaseEngineAsync():
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 DatabaseEngine():
395
+ config = rconfig.DatabaseConfig(self)
396
+ case DatabaseEngineAsync():
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 DatabaseEngine():
415
+ schema = rinfo.DatabaseInformationSchema(self)
416
+ case DatabaseEngineAsync():
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.
430
+ """
431
+
432
+ # Build.
433
+ match self:
434
+ case DatabaseEngine():
435
+ var = rinfo.DatabaseInformationParameterVariables(self)
436
+ case DatabaseEngineAsync():
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.
446
+
447
+ Returns
448
+ -------
449
+ Instance.
450
+ """
451
+
452
+ # Build.
453
+ match self:
454
+ case DatabaseEngine():
455
+ stat = rinfo.DatabaseInformationParameterStatus(self)
456
+ case DatabaseEngineAsync():
457
+ stat = rinfo.DatabaseInformationParameterStatusAsync(self)
458
+
459
+ return stat
460
+
461
+
462
+ @property
463
+ def glob_var(self) -> DatabaseInformationParameterVariablesGlobalT:
464
+ """
465
+ Build global database parameters variable instance.
466
+
467
+ Returns
468
+ -------
469
+ Instance.
470
+ """
471
+
472
+ # Build.
473
+ match self:
474
+ case DatabaseEngine():
475
+ var = rinfo.DatabaseInformationParameterVariablesGlobal(self)
476
+ case DatabaseEngineAsync():
477
+ var = rinfo.DatabaseInformationParameterVariablesGlobalAsync(self)
478
+
479
+ return var
480
+
481
+
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 DatabaseEngine():
495
+ stat = rinfo.DatabaseInformationParameterStatusGlobal(self)
496
+ case DatabaseEngineAsync():
497
+ stat = rinfo.DatabaseInformationParameterStatusGlobalAsync(self)
498
+
499
+ return stat
500
+
501
+
502
+ class DatabaseEngine(
503
+ DatabaseEngineSuper[
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
+ ):
517
+ """
518
+ Database engine type, based `MySQL`.
519
+ """
520
+
521
+
522
+ @property
523
+ def async_database(self) -> 'DatabaseEngineAsync':
524
+ """
525
+ Same engine `DatabaseEngineAsync` instance.
526
+ """
527
+
528
+ # Build.
529
+ db = DatabaseEngineAsync(
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 DatabaseEngineAsync(
547
+ DatabaseEngineSuper[
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
+ ):
561
+ """
562
+ Asynchronous database engine type, based `MySQL`.
563
+ """
564
+
565
+
566
+ @property
567
+ def sync_database(self) -> DatabaseEngine:
568
+ """
569
+ Same engine `Database` instance.
570
+ """
571
+
572
+ # Build.
573
+ db = DatabaseEngine(
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()
reydb/rerror.py CHANGED
@@ -2,7 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- @Time : 2025-08-20 16:57:19
5
+ @Time : 2025-08-20
6
6
  @Author : Rey
7
7
  @Contact : reyxbo@163.com
8
8
  @Explain : Database error methods.
@@ -16,7 +16,7 @@ from traceback import StackSummary
16
16
  from functools import wraps as functools_wraps
17
17
  from reykit.rbase import T, Exit, catch_exc
18
18
 
19
- from . import rdb
19
+ from . import rengine
20
20
  from . import rorm
21
21
  from .rbase import DatabaseBase
22
22
 
@@ -29,7 +29,7 @@ __all__ = (
29
29
  )
30
30
 
31
31
 
32
- DatabaseT = TypeVar('DatabaseT', 'rdb.Database', 'rdb.DatabaseAsync')
32
+ DatabaseEngineT = TypeVar('DatabaseEngineT', 'rdb.Database', 'rdb.DatabaseEngineAsync')
33
33
 
34
34
 
35
35
  class DatabaseORMTableError(rorm.Model, table=True):
@@ -47,7 +47,7 @@ class DatabaseORMTableError(rorm.Model, table=True):
47
47
  note: str = rorm.Field(rorm.types.VARCHAR(500), comment='Error note.')
48
48
 
49
49
 
50
- class DatabaseErrorSuper(DatabaseBase, Generic[DatabaseT]):
50
+ class DatabaseErrorSuper(DatabaseBase, Generic[DatabaseEngineT]):
51
51
  """
52
52
  Database error super type.
53
53
  Can create database used `self.build_db` method.
@@ -56,24 +56,24 @@ class DatabaseErrorSuper(DatabaseBase, Generic[DatabaseT]):
56
56
  _checked: bool = False
57
57
 
58
58
 
59
- def __init__(self, db: DatabaseT) -> None:
59
+ def __init__(self, engine: DatabaseEngineT) -> None:
60
60
  """
61
61
  Build instance attributes.
62
62
 
63
63
  Parameters
64
64
  ----------
65
- db: Database instance.
65
+ engine: Database engine.
66
66
  """
67
67
 
68
68
  # Build.
69
- self.db = db
69
+ self.engine = engine
70
70
 
71
71
  # Build Database.
72
72
  if not self._checked:
73
73
  if type(self) == DatabaseError:
74
74
  self.build_db()
75
75
  elif type(self) == DatabaseErrorAsync:
76
- db.sync_database.error.build_db()
76
+ engine.sync_database.error.build_db()
77
77
  self._checked = True
78
78
 
79
79
 
@@ -87,7 +87,7 @@ class DatabaseErrorSuper(DatabaseBase, Generic[DatabaseT]):
87
87
  """
88
88
 
89
89
  # Parameter.
90
- database = self.db.database
90
+ database = self.engine.database
91
91
 
92
92
  ## Table.
93
93
  tables = [DatabaseORMTableError]
@@ -201,7 +201,7 @@ class DatabaseError(DatabaseErrorSuper['rdb.Database']):
201
201
  tables, views_stats = self.handle_build_db()
202
202
 
203
203
  # Build.
204
- self.db.build.build(tables=tables, views_stats=views_stats, skip=True)
204
+ self.engine.build.build(tables=tables, views_stats=views_stats, skip=True)
205
205
 
206
206
 
207
207
  def record(
@@ -224,7 +224,7 @@ class DatabaseError(DatabaseErrorSuper['rdb.Database']):
224
224
  data = self.handle_record(exc, stack, note)
225
225
 
226
226
  # Insert.
227
- self.db.execute.insert(
227
+ self.engine.execute.insert(
228
228
  'error',
229
229
  data=data
230
230
  )
@@ -363,7 +363,7 @@ class DatabaseError(DatabaseErrorSuper['rdb.Database']):
363
363
  return _func
364
364
 
365
365
 
366
- class DatabaseErrorAsync(DatabaseErrorSuper['rdb.DatabaseAsync']):
366
+ class DatabaseErrorAsync(DatabaseErrorSuper['rdb.DatabaseEngineAsync']):
367
367
  """
368
368
  Asynchronous database error type.
369
369
  Can create database used `self.build_db` method.
@@ -379,7 +379,7 @@ class DatabaseErrorAsync(DatabaseErrorSuper['rdb.DatabaseAsync']):
379
379
  tables, views_stats = self.handle_build_db()
380
380
 
381
381
  # Build.
382
- await self.db.build.build(tables=tables, views_stats=views_stats, skip=True)
382
+ await self.engine.build.build(tables=tables, views_stats=views_stats, skip=True)
383
383
 
384
384
 
385
385
  async def record(
@@ -402,7 +402,7 @@ class DatabaseErrorAsync(DatabaseErrorSuper['rdb.DatabaseAsync']):
402
402
  data = self.handle_record(exc, stack, note)
403
403
 
404
404
  # Insert.
405
- await self.db.execute.insert(
405
+ await self.engine.execute.insert(
406
406
  'error',
407
407
  data=data
408
408
  )