reydb 1.1.48__py3-none-any.whl → 1.1.50__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
@@ -9,107 +9,44 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import Any, Literal, overload
13
- from collections.abc import Iterable, Generator, Container
14
- from enum import EnumType
15
12
  from urllib.parse import quote as urllib_quote
16
13
  from pymysql.constants.CLIENT import MULTI_STATEMENTS
17
- from sqlalchemy import create_engine as sqlalchemy_create_engine, text as sqlalchemy_text
18
- from sqlalchemy.engine.base import Engine, Connection
19
- from sqlalchemy.sql.elements import TextClause
20
- from reykit.rbase import throw, get_first_notnone
21
- from reykit.rdata import Generator, to_json
22
- from reykit.rmonkey import monkey_sqlalchemy_result_more_fetch, monkey_sqlalchemy_row_index_field
23
- from reykit.rre import search, findall
24
- from reykit.rstdout import echo
25
- from reykit.rtable import TableData, Table
14
+ from sqlalchemy import create_engine as sqlalchemy_create_engine
15
+ from sqlalchemy.engine.base import Engine
26
16
  from reykit.rtext import join_data_text
27
- from reykit.rwrap import wrap_runtime
28
17
 
29
18
  from .rbase import DatabaseBase, extract_url
30
19
 
31
20
 
32
21
  __all__ = (
33
- 'Result',
34
- 'Database'
22
+ 'Database',
35
23
  )
36
24
 
37
25
 
38
- # Monkey path.
39
- Result_ = monkey_sqlalchemy_result_more_fetch()
40
- Result = Result_
41
- monkey_sqlalchemy_row_index_field()
42
-
43
-
44
26
  class Database(DatabaseBase):
45
27
  """
46
- Database type.
47
- Based `MySQL` or `SQLite`.
48
-
49
- Examples
50
- --------
51
- >>> rdb = Database()
52
- >>> result = rdb.execute('SELECT 1 as `a`')
53
- >>> result.to_table()
54
- [{'a': 1}]
28
+ Database type, based `MySQL`.
29
+
30
+ Attributes
31
+ ----------
32
+ default_report : Whether default to report execution.
55
33
  """
56
34
 
57
- # Default value.
58
35
  default_report: bool = False
59
36
 
60
37
 
61
- @overload
62
38
  def __init__(
63
39
  self,
64
40
  host: str,
65
41
  port: int | str,
66
42
  username: str,
67
43
  password: str,
68
- database: str | None = None,
69
- *,
70
- pool_size: int = 5,
71
- max_overflow: int = 10,
72
- pool_timeout: float = 30.0,
73
- pool_recycle: int | None = None,
74
- **query: str
75
- ) -> None: ...
76
-
77
- @overload
78
- def __init__(
79
- self,
80
- *,
81
44
  database: str,
82
45
  pool_size: int = 5,
83
46
  max_overflow: int = 10,
84
47
  pool_timeout: float = 30.0,
85
48
  pool_recycle: int | None = None,
86
49
  **query: str
87
- ) -> None: ...
88
-
89
- @overload
90
- def __init__(
91
- self,
92
- *,
93
- pool_size: int = 5,
94
- max_overflow: int = 10,
95
- pool_timeout: float = 30.0,
96
- pool_recycle: int | None = None,
97
- **query: str
98
- ) -> None: ...
99
-
100
-
101
- def __init__(
102
- self,
103
- host: str | None = None,
104
- port: int | str | None = None,
105
- username: str | None = None,
106
- password: str | None = None,
107
- database: str | None = None,
108
- pool_size: int = 5,
109
- max_overflow: int = 10,
110
- pool_timeout: float = 30.0,
111
- pool_recycle: int | None = None,
112
- **query: str
113
50
  ) -> None:
114
51
  """
115
52
  Build instance attributes.
@@ -120,8 +57,7 @@ class Database(DatabaseBase):
120
57
  port : Remote server database port.
121
58
  username : Remote server database username.
122
59
  password : Remote server database password.
123
- database : Remote server database name or local database file path.
124
- - `None`: When parameters `host`, `port`, `username`, `password`, `database` are all `None`, then using memory store.
60
+ database : Remote server database name.
125
61
  pool_size : Number of connections `keep open`.
126
62
  max_overflow : Number of connections `allowed overflow`.
127
63
  pool_timeout : Number of seconds `wait create` connection.
@@ -158,94 +94,12 @@ class Database(DatabaseBase):
158
94
 
159
95
  # Server recycle time.
160
96
  if pool_recycle is None:
161
- if self.mode == 'server':
162
- wait_timeout = self.variables['wait_timeout']
163
- if wait_timeout is not None:
164
- self.pool_recycle = int(wait_timeout)
97
+ wait_timeout = self.variables['wait_timeout']
98
+ if wait_timeout is not None:
99
+ self.pool_recycle = int(wait_timeout)
165
100
  self.engine.pool._recycle = self.pool_recycle
166
101
 
167
102
 
168
- @overload
169
- def extract_path(
170
- self,
171
- path: str,
172
- main: Literal['table', 'database'] = 'table'
173
- ) -> tuple[str, str, str | None]: ...
174
-
175
- @overload
176
- def extract_path(
177
- self,
178
- path: tuple[str | None, str | None] | tuple[str | None, str | None, str | None],
179
- main: Literal['table', 'database'] = 'table'
180
- ) -> tuple[str, str | None, str | None]: ...
181
-
182
- def extract_path(
183
- self,
184
- path: str | tuple[str | None, str | None] | tuple[str | None, str | None, str | None],
185
- main: Literal['table', 'database'] = 'table'
186
- ) -> tuple[str, str | None, str | None]:
187
- """
188
- Extract table name and database name and column name from path.
189
-
190
- Parameters
191
- ----------
192
- path : Table name, can contain database name, otherwise use `self.rdatabase.database`.
193
- - `str`: Automatic extract database name and table name.
194
- Not contain '.' or contain '`': Main name.
195
- Contain '.': Database name and table name, column name is optional. Example 'database.table[.column]'.
196
- - `tuple[str, str]`: Database name and table name.
197
- - `tuple[str, str | None, str | None]`: Database name and table name and column name.
198
- path : Automatic extract.
199
- main : Priority main name, 'table' or 'database'.
200
-
201
- Returns
202
- -------
203
- Database name and table name and column name.
204
- """
205
-
206
- # Type str.
207
- if type(path) == str:
208
-
209
- ## Single.
210
- if (
211
- '.' not in path
212
- or '`' in path
213
- ):
214
- name = path.replace('`', '')
215
- match main:
216
- case 'table':
217
- names = (self.database, name, None)
218
- case 'database':
219
- names = (name, None, None)
220
- case _:
221
- throw(ValueError, main)
222
-
223
- ## Multiple.
224
- else:
225
- names = path.split('.', 2)
226
- if len(names) == 2:
227
- names.append(None)
228
- names = tuple(names)
229
-
230
- # Type tuple.
231
- else:
232
- if len(path) == 2:
233
- path += (None,)
234
- if path[0] is None:
235
- path = (self.database,) + names[1:]
236
- names = path
237
-
238
- # SQLite.
239
- if self.backend == 'sqlite':
240
- names = ('main',) + names[1:]
241
-
242
- # Check.
243
- if names[0] is None:
244
- throw(ValueError, names)
245
-
246
- return names
247
-
248
-
249
103
  @property
250
104
  def backend(self) -> str:
251
105
  """
@@ -280,32 +134,6 @@ class Database(DatabaseBase):
280
134
  return driver
281
135
 
282
136
 
283
- @property
284
- def mode(self) -> Literal['server', 'file', 'memory']:
285
- """
286
- Database store mode.
287
-
288
- Returns
289
- -------
290
- Mode.
291
- """
292
-
293
- # Judge.
294
- if (
295
- self.username is not None
296
- and self.password is not None
297
- and self.host is not None
298
- and self.port is not None
299
- ):
300
- value = 'server'
301
- elif self.database not in (None, ':memory:'):
302
- value = 'file'
303
- else:
304
- value = 'memory'
305
-
306
- return value
307
-
308
-
309
137
  @property
310
138
  def url(self) -> str:
311
139
  """
@@ -317,21 +145,8 @@ class Database(DatabaseBase):
317
145
  """
318
146
 
319
147
  # Generate URL.
320
-
321
- ## Server.
322
- if self.mode == 'server':
323
- password = urllib_quote(self.password)
324
- url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}'
325
- if self.database is not None:
326
- url_ = f'{url_}/{self.database}'
327
-
328
- ## File.
329
- elif self.mode == 'file':
330
- url_ = f'sqlite:///{self.database}'
331
-
332
- ## Memory.
333
- else:
334
- url_ = f'sqlite:///:memory:'
148
+ password = urllib_quote(self.password)
149
+ url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
335
150
 
336
151
  # Add Server parameter.
337
152
  if self.query != {}:
@@ -356,20 +171,14 @@ class Database(DatabaseBase):
356
171
  """
357
172
 
358
173
  # Handle parameter.
359
- if self.mode == 'memory':
360
- engine_params = {
361
- 'url': self.url,
362
- 'pool_recycle': self.pool_recycle
363
- }
364
- else:
365
- engine_params = {
366
- 'url': self.url,
367
- 'pool_size': self.pool_size,
368
- 'max_overflow': self.max_overflow,
369
- 'pool_timeout': self.pool_timeout,
370
- 'pool_recycle': self.pool_recycle,
371
- 'connect_args': {'client_flag': MULTI_STATEMENTS}
372
- }
174
+ engine_params = {
175
+ 'url': self.url,
176
+ 'pool_size': self.pool_size,
177
+ 'max_overflow': self.max_overflow,
178
+ 'pool_timeout': self.pool_timeout,
179
+ 'pool_recycle': self.pool_recycle,
180
+ 'connect_args': {'client_flag': MULTI_STATEMENTS}
181
+ }
373
182
 
374
183
  # Create Engine.
375
184
  engine = sqlalchemy_create_engine(**engine_params)
@@ -378,7 +187,7 @@ class Database(DatabaseBase):
378
187
 
379
188
 
380
189
  @property
381
- def count(self) -> tuple[int, int]:
190
+ def count_conn(self) -> tuple[int, int]:
382
191
  """
383
192
  Count number of keep open and allowed overflow connection.
384
193
 
@@ -387,1182 +196,18 @@ class Database(DatabaseBase):
387
196
  Number of keep open and allowed overflow connection.
388
197
  """
389
198
 
390
- # Handle parameter.
391
- if hasattr(self, 'engine'):
392
- rdatabase = self
393
- else:
394
- rdatabase: Database = self.rdatabase
395
-
396
199
  # Count.
397
- _overflow = rdatabase.engine.pool._overflow
200
+ _overflow = self.engine.pool._overflow
398
201
  if _overflow < 0:
399
- keep_n = rdatabase.pool_size + _overflow
202
+ keep_n = self.pool_size + _overflow
400
203
  overflow_n = 0
401
204
  else:
402
- keep_n = rdatabase.pool_size
205
+ keep_n = self.pool_size
403
206
  overflow_n = _overflow
404
207
 
405
208
  return keep_n, overflow_n
406
209
 
407
210
 
408
- def handle_sql(self, sql: str | TextClause) -> TextClause:
409
- """
410
- Handle SQL.
411
-
412
- Parameters
413
- ----------
414
- sql : SQL in method `sqlalchemy.text` format, or TextClause object.
415
-
416
- Returns
417
- -------
418
- TextClause instance.
419
- """
420
-
421
- # Handle parameter.
422
- if type(sql) == TextClause:
423
- sql = sql.text
424
-
425
- # Handle.
426
- sql = sql.strip()
427
- if sql[-1] != ';':
428
- sql += ';'
429
- sql = sqlalchemy_text(sql)
430
-
431
- return sql
432
-
433
-
434
- def handle_data(
435
- self,
436
- data: list[dict],
437
- sql: str | TextClause,
438
- ) -> list[dict]:
439
- """
440
- Handle data based on the content of SQL.
441
-
442
- Parameters
443
- ----------
444
- data : Data set for filling.
445
- sql : SQL in method `sqlalchemy.text` format, or TextClause object.
446
-
447
- Returns
448
- -------
449
- Filled data.
450
- """
451
-
452
- # Handle parameter.
453
- if type(sql) == TextClause:
454
- sql = sql.text
455
-
456
- # Extract keys.
457
- pattern = '(?<!\\\\):(\\w+)'
458
- sql_keys = findall(pattern, sql)
459
-
460
- # Extract keys of syntax "in".
461
- pattern = '[iI][nN]\\s+(?<!\\\\):(\\w+)'
462
- sql_keys_in = findall(pattern, sql)
463
-
464
- # Loop.
465
- for row in data:
466
- if row == {}:
467
- continue
468
- for key in sql_keys:
469
- value = row.get(key)
470
-
471
- # Empty string.
472
- if value == '':
473
- value = None
474
-
475
- # Convert.
476
- elif (
477
- type(value) in (list, dict)
478
- and key not in sql_keys_in
479
- ):
480
- value = to_json(value)
481
-
482
- # Enum.
483
- elif isinstance(type(value), EnumType):
484
- value = value.value
485
-
486
- row[key] = value
487
-
488
- return data
489
-
490
-
491
- def get_syntax(self, sql: str | TextClause) -> list[str]:
492
- """
493
- Extract SQL syntax type for each segment form SQL.
494
-
495
- Parameters
496
- ----------
497
- sql : SQL text or TextClause object.
498
-
499
- Returns
500
- -------
501
- SQL syntax type for each segment.
502
- """
503
-
504
- # Handle parameter.
505
- if type(sql) == TextClause:
506
- sql = sql.text
507
-
508
- # Extract.
509
- syntax = [
510
- search('[a-zA-Z]+', sql_part).upper()
511
- for sql_part in sql.split(';')
512
- if sql_part != ''
513
- ]
514
-
515
- return syntax
516
-
517
-
518
- def is_multi_sql(self, sql: str | TextClause) -> bool:
519
- """
520
- Judge whether it is multi segment SQL.
521
-
522
- Parameters
523
- ----------
524
- sql : SQL text or TextClause object.
525
-
526
- Returns
527
- -------
528
- Judgment result.
529
- """
530
-
531
- # Handle parameter.
532
- if type(sql) == TextClause:
533
- sql = sql.text
534
-
535
- # Judge.
536
- if ';' in sql.rstrip()[:-1]:
537
- return True
538
- return False
539
-
540
-
541
- def executor_report(
542
- self,
543
- connection: Connection,
544
- sql: TextClause,
545
- data: list[dict]
546
- ) -> Result:
547
- """
548
- SQL executor and report SQL execute information
549
-
550
- Parameters
551
- ----------
552
- connection : Connection object.
553
- sql : TextClause object.
554
- data : Data set for filling.
555
-
556
- Returns
557
- -------
558
- Result object.
559
- """
560
-
561
- # Execute.
562
- execute = wrap_runtime(connection.execute, to_return=True)
563
- result, report_runtime, *_ = execute(sql, data)
564
-
565
- # Report.
566
- report_info = (
567
- f'{report_runtime}\n'
568
- f'Row Count: {result.rowcount}'
569
- )
570
- sqls = [
571
- sql_part.strip()
572
- for sql_part in sql.text.split(';')
573
- if sql_part != ''
574
- ]
575
- if data == []:
576
- echo(report_info, *sqls, title='SQL')
577
- else:
578
- echo(report_info, *sqls, data, title='SQL')
579
-
580
- return result
581
-
582
-
583
- def executor(
584
- self,
585
- sql: TextClause,
586
- data: list[dict],
587
- report: bool
588
- ) -> Result:
589
- """
590
- SQL executor.
591
-
592
- Parameters
593
- ----------
594
- sql : TextClause object.
595
- data : Data set for filling.
596
- report : Whether report SQL execute information.
597
-
598
- Returns
599
- -------
600
- Result object.
601
- """
602
-
603
- # Create connection.
604
- with self.engine.connect() as connection:
605
-
606
- # Create transaction.
607
- with connection.begin():
608
-
609
- # Execute.
610
-
611
- ## Report.
612
- if report:
613
- result = self.executor_report(connection, sql, data)
614
-
615
- ## Not report.
616
- else:
617
- result = connection.execute(sql, data)
618
-
619
- return result
620
-
621
-
622
- def execute(
623
- self,
624
- sql: str | TextClause,
625
- data: TableData | None = None,
626
- report: bool | None = None,
627
- **kwdata: Any
628
- ) -> Result:
629
- """
630
- Execute SQL.
631
-
632
- Parameters
633
- ----------
634
- sql : SQL in method `sqlalchemy.text` format, or `TextClause` object.
635
- data : Data set for filling.
636
- report : Whether report SQL execute information.
637
- - `None`: Use attribute `default_report`.
638
- - `bool`: Use this value.
639
- kwdata : Keyword parameters for filling.
640
-
641
- Returns
642
- -------
643
- Result object.
644
- """
645
-
646
- # Handle parameter by priority.
647
- report = get_first_notnone(report, self.default_report)
648
-
649
- # Handle parameter.
650
- sql = self.handle_sql(sql)
651
- if data is None:
652
- if kwdata == {}:
653
- data = []
654
- else:
655
- data = [kwdata]
656
- else:
657
- data_table = Table(data)
658
- data = data_table.to_table()
659
- for row in data:
660
- row.update(kwdata)
661
- data = self.handle_data(data, sql)
662
-
663
- # Execute.
664
- result = self.executor(sql, data, report)
665
-
666
- return result
667
-
668
-
669
- def execute_select(
670
- self,
671
- path: str | tuple[str, str],
672
- fields: str | Iterable[str] | None = None,
673
- where: str | None = None,
674
- group: str | None = None,
675
- having: str | None = None,
676
- order: str | None = None,
677
- limit: int | str | tuple[int, int] | None = None,
678
- report: bool | None = None,
679
- **kwdata: Any
680
- ) -> Result:
681
- """
682
- Execute select SQL.
683
-
684
- Parameters
685
- ----------
686
- path : Table name, can contain database name, otherwise use `self.database`.
687
- - `str`: Automatic extract database name and table name.
688
- - `tuple[str, str]`: Database name and table name.
689
- fields : Select clause content.
690
- - `None`: Is `SELECT *`.
691
- - `str`: Join as `SELECT str`.
692
- - `Iterable[str]`, Join as `SELECT ``str``: ...`.
693
- `str and first character is ':'`: Use this syntax.
694
- `str`: Use this field.
695
- where : Clause `WHERE` content, join as `WHERE str`.
696
- group : Clause `GROUP BY` content, join as `GROUP BY str`.
697
- having : Clause `HAVING` content, join as `HAVING str`.
698
- order : Clause `ORDER BY` content, join as `ORDER BY str`.
699
- limit : Clause `LIMIT` content.
700
- - `int | str`: Join as `LIMIT int/str`.
701
- - `tuple[int, int]`: Join as `LIMIT int, int`.
702
- report : Whether report SQL execute information.
703
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
704
- - `int`: Use this value.
705
- kwdata : Keyword parameters for filling.
706
-
707
- Returns
708
- -------
709
- Result object.
710
-
711
- Examples
712
- --------
713
- Parameter `fields`.
714
- >>> fields = ['id', ':`id` + 1 AS `id_`']
715
- >>> result = Database.execute_select('database.table', fields)
716
- >>> print(result.to_table())
717
- [{'id': 1, 'id_': 2}, ...]
718
-
719
- Parameter `kwdata`.
720
- >>> fields = '`id`, `id` + :value AS `id_`'
721
- >>> result = Database.execute_select('database.table', fields, value=1)
722
- >>> print(result.to_table())
723
- [{'id': 1, 'id_': 2}, ...]
724
- """
725
-
726
- # Handle parameter.
727
- database, table, _ = self.extract_path(path)
728
-
729
- # Generate SQL.
730
- sql_list = []
731
-
732
- ## Part 'SELECT' syntax.
733
- if fields is None:
734
- fields = '*'
735
- elif type(fields) != str:
736
- fields = ', '.join(
737
- [
738
- field[1:]
739
- if (
740
- field.startswith(':')
741
- and field != ':'
742
- )
743
- else f'`{field}`'
744
- for field in fields
745
- ]
746
- )
747
- sql_select = f'SELECT {fields}'
748
- sql_list.append(sql_select)
749
-
750
- ## Part 'FROM' syntax.
751
- sql_from = f'FROM `{database}`.`{table}`'
752
- sql_list.append(sql_from)
753
-
754
- ## Part 'WHERE' syntax.
755
- if where is not None:
756
- sql_where = f'WHERE {where}'
757
- sql_list.append(sql_where)
758
-
759
- ## Part 'GROUP BY' syntax.
760
- if group is not None:
761
- sql_group = f'GROUP BY {group}'
762
- sql_list.append(sql_group)
763
-
764
- ## Part 'GROUP BY' syntax.
765
- if having is not None:
766
- sql_having = f'HAVING {having}'
767
- sql_list.append(sql_having)
768
-
769
- ## Part 'ORDER BY' syntax.
770
- if order is not None:
771
- sql_order = f'ORDER BY {order}'
772
- sql_list.append(sql_order)
773
-
774
- ## Part 'LIMIT' syntax.
775
- if limit is not None:
776
- if type(limit) in (str, int):
777
- sql_limit = f'LIMIT {limit}'
778
- else:
779
- if len(limit) == 2:
780
- sql_limit = f'LIMIT {limit[0]}, {limit[1]}'
781
- else:
782
- throw(ValueError, limit)
783
- sql_list.append(sql_limit)
784
-
785
- ## Join sql part.
786
- sql = '\n'.join(sql_list)
787
-
788
- # Execute SQL.
789
- result = self.execute(sql, report=report, **kwdata)
790
-
791
- return result
792
-
793
-
794
- def execute_insert(
795
- self,
796
- path: str | tuple[str, str],
797
- data: TableData,
798
- duplicate: Literal['ignore', 'update'] | Container[str] | None = None,
799
- report: bool | None = None,
800
- **kwdata: Any
801
- ) -> Result:
802
- """
803
- Insert the data of table in the datebase.
804
-
805
- Parameters
806
- ----------
807
- path : Table name, can contain database name, otherwise use `self.database`.
808
- - `str`: Automatic extract database name and table name.
809
- - `tuple[str, str]`: Database name and table name.
810
- data : Insert data.
811
- duplicate : Handle method when constraint error.
812
- - `None`: Not handled.
813
- - `ignore`: Use `UPDATE IGNORE INTO` clause.
814
- - `update`: Use `ON DUPLICATE KEY UPDATE` clause and update all fields.
815
- - `Container[str]`: Use `ON DUPLICATE KEY UPDATE` clause and update this fields.
816
- report : Whether report SQL execute information.
817
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
818
- - `int`: Use this value.
819
- kwdata : Keyword parameters for filling.
820
- - `str and first character is ':'`: Use this syntax.
821
- - `Any`: Use this value.
822
-
823
- Returns
824
- -------
825
- Result object.
826
-
827
- Examples
828
- --------
829
- Parameter `data` and `kwdata`.
830
- >>> data = [{'key': 'a'}, {'key': 'b'}]
831
- >>> kwdata = {'value1': 1, 'value2': ':(SELECT 2)'}
832
- >>> result = Database.execute_insert('database.table', data, **kwdata)
833
- >>> print(result.rowcount)
834
- 2
835
- >>> result = Database.execute_select('database.table')
836
- >>> print(result.to_table())
837
- [{'key': 'a', 'value1': 1, 'value2': 2}, {'key': 'b', 'value1': 1, 'value2': 2}]
838
- """
839
-
840
- # Handle parameter.
841
- database, table, _ = self.extract_path(path)
842
-
843
- # Handle parameter.
844
-
845
- ## Data.
846
- data_table = Table(data)
847
- data = data_table.to_table()
848
-
849
- ## Check.
850
- if data in ([], [{}]):
851
- throw(ValueError, data)
852
-
853
- ## Keyword data.
854
- kwdata_method = {}
855
- kwdata_replace = {}
856
- for key, value in kwdata.items():
857
- if (
858
- type(value) == str
859
- and value.startswith(':')
860
- and value != ':'
861
- ):
862
- kwdata_method[key] = value[1:]
863
- else:
864
- kwdata_replace[key] = value
865
-
866
- # Generate SQL.
867
-
868
- ## Part 'fields' syntax.
869
- fields_replace = {
870
- field
871
- for row in data
872
- for field in row
873
- }
874
- fields_replace = {
875
- field
876
- for field in fields_replace
877
- if field not in kwdata
878
- }
879
- sql_fields_list = (
880
- *kwdata_method,
881
- *kwdata_replace,
882
- *fields_replace
883
- )
884
- sql_fields = ', '.join(
885
- [
886
- f'`{field}`'
887
- for field in sql_fields_list
888
- ]
889
- )
890
-
891
- ## Part 'values' syntax.
892
- sql_values_list = (
893
- *kwdata_method.values(),
894
- *[
895
- ':' + field
896
- for field in (
897
- *kwdata_replace,
898
- *fields_replace
899
- )
900
- ]
901
- )
902
- sql_values = ', '.join(sql_values_list)
903
-
904
- ## Join sql part.
905
- match duplicate:
906
-
907
- ### Not handle.
908
- case None:
909
- sql = (
910
- f'INSERT INTO `{database}`.`{table}`({sql_fields})\n'
911
- f'VALUES({sql_values})'
912
- )
913
-
914
- ### Ignore.
915
- case 'ignore':
916
- sql = (
917
- f'INSERT IGNORE INTO `{database}`.`{table}`({sql_fields})\n'
918
- f'VALUES({sql_values})'
919
- )
920
-
921
- ### Update.
922
- case _:
923
- sql_fields_list_update = sql_fields_list
924
- if duplicate != 'update':
925
- sql_fields_list_update = [
926
- field
927
- for field in sql_fields_list
928
- if field in duplicate
929
- ]
930
- update_content = ',\n '.join(
931
- [
932
- f'`{field}` = VALUES(`{field}`)'
933
- for field in sql_fields_list_update
934
- ]
935
- )
936
- sql = (
937
- f'INSERT INTO `{database}`.`{table}`({sql_fields})\n'
938
- f'VALUES({sql_values})\n'
939
- 'ON DUPLICATE KEY UPDATE\n'
940
- f' {update_content}'
941
- )
942
-
943
- # Execute SQL.
944
- result = self.execute(sql, data, report, **kwdata_replace)
945
-
946
- return result
947
-
948
-
949
- def execute_update(
950
- self,
951
- path: str | tuple[str, str],
952
- data: TableData,
953
- where_fields: str | Iterable[str] | None = None,
954
- report: bool | None = None,
955
- **kwdata: Any
956
- ) -> Result:
957
- """
958
- Update the data of table in the datebase.
959
-
960
- Parameters
961
- ----------
962
- path : Table name, can contain database name, otherwise use `self.database`.
963
- - `str`: Automatic extract database name and table name.
964
- - `tuple[str, str]`: Database name and table name.
965
- data : Update data, clause `SET` and `WHERE` and `ORDER BY` and `LIMIT` content.
966
- - `Key`: Table field.
967
- `literal['order']`: Clause `ORDER BY` content, join as `ORDER BY str`.
968
- `literal['limit']`: Clause `LIMIT` content, join as `LIMIT str`.
969
- `Other`: Clause `SET` and `WHERE` content.
970
- - `Value`: Table value.
971
- `list | tuple`: Join as `field IN :str`.
972
- `Any`: Join as `field = :str`.
973
- where_fields : Clause `WHERE` content fields.
974
- - `None`: The first key value pair of each item is judged.
975
- - `str`: This key value pair of each item is judged.
976
- - `Iterable[str]`: Multiple judged, `and`: relationship.
977
- report : Whether report SQL execute information.
978
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
979
- - `int`: Use this value.
980
- kwdata : Keyword parameters for filling.
981
- - `str and first character is ':'`: Use this syntax.
982
- - `Any`: Use this value.
983
-
984
- Returns
985
- -------
986
- Result object.
987
-
988
- Examples
989
- --------
990
- Parameter `data` and `kwdata`.
991
- >>> data = [{'key': 'a'}, {'key': 'b'}]
992
- >>> kwdata = {'value': 1, 'name': ':`key`'}
993
- >>> result = Database.execute_update('database.table', data, **kwdata)
994
- >>> print(result.rowcount)
995
- 2
996
- >>> result = Database.execute_select('database.table')
997
- >>> print(result.to_table())
998
- [{'key': 'a', 'value': 1, 'name': 'a'}, {'key': 'b', 'value': 1, 'name': 'b'}]
999
- """
1000
-
1001
- # Handle parameter.
1002
- database, table, _ = self.extract_path(path)
1003
-
1004
- # Handle parameter.
1005
-
1006
- ## Data.
1007
- data_table = Table(data)
1008
- data = data_table.to_table()
1009
-
1010
- ## Check.
1011
- if data in ([], [{}]):
1012
- throw(ValueError, data)
1013
-
1014
- ## Keyword data.
1015
- kwdata_method = {}
1016
- kwdata_replace = {}
1017
- for key, value in kwdata.items():
1018
- if (
1019
- type(value) == str
1020
- and value.startswith(':')
1021
- and value != ':'
1022
- ):
1023
- kwdata_method[key] = value[1:]
1024
- else:
1025
- kwdata_replace[key] = value
1026
- sql_set_list_kwdata = [
1027
- f'`{key}` = {value}'
1028
- for key, value in kwdata_method.items()
1029
- ]
1030
- sql_set_list_kwdata.extend(
1031
- [
1032
- f'`{key}` = :{key}'
1033
- for key in kwdata_replace
1034
- ]
1035
- )
1036
-
1037
- # Generate SQL.
1038
- data_flatten = kwdata_replace
1039
- if where_fields is None:
1040
- no_where = True
1041
- else:
1042
- no_where = False
1043
- if type(where_fields) == str:
1044
- where_fields = [where_fields]
1045
- sqls_list = []
1046
- sql_update = f'UPDATE `{database}`.`{table}`'
1047
- for index, row in enumerate(data):
1048
- sql_parts = [sql_update]
1049
- for key, value in row.items():
1050
- if key in ('order', 'limit'):
1051
- continue
1052
- index_key = f'{index}_{key}'
1053
- data_flatten[index_key] = value
1054
- if no_where:
1055
- for key in row:
1056
- where_fields = [key]
1057
- break
1058
-
1059
- ## Part 'SET' syntax.
1060
- sql_set_list = sql_set_list_kwdata.copy()
1061
- sql_set_list.extend(
1062
- [
1063
- f'`{key}` = :{index}_{key}'
1064
- for key in row
1065
- if (
1066
- key not in where_fields
1067
- and key not in kwdata
1068
- and key not in ('order', 'limit')
1069
- )
1070
- ]
1071
- )
1072
- sql_set = 'SET ' + ',\n '.join(sql_set_list)
1073
- sql_parts.append(sql_set)
1074
-
1075
- ## Part 'WHERE' syntax.
1076
- sql_where_list = []
1077
- for field in where_fields:
1078
- index_field = f'{index}_{field}'
1079
- index_value = data_flatten[index_field]
1080
- if type(index_value) in (list, tuple):
1081
- sql_where_part = f'`{field}` IN :{index_field}'
1082
- else:
1083
- sql_where_part = f'`{field}` = :{index_field}'
1084
- sql_where_list.append(sql_where_part)
1085
- sql_where = 'WHERE ' + '\n AND '.join(sql_where_list)
1086
- sql_parts.append(sql_where)
1087
-
1088
- ## Part 'ORDER BY' syntax.
1089
- order = row.get('order')
1090
- if order is not None:
1091
- sql_order = f'ORDER BY {order}'
1092
- sql_parts.append(sql_order)
1093
-
1094
- ## Part 'LIMIT' syntax.
1095
- limit = row.get('limit')
1096
- if limit is not None:
1097
- sql_limit = f'LIMIT {limit}'
1098
- sql_parts.append(sql_limit)
1099
-
1100
- ## Join sql part.
1101
- sql = '\n'.join(sql_parts)
1102
- sqls_list.append(sql)
1103
-
1104
- ## Join sqls.
1105
- sqls = ';\n'.join(sqls_list)
1106
-
1107
- # Execute SQL.
1108
- result = self.execute(sqls, data_flatten, report)
1109
-
1110
- return result
1111
-
1112
-
1113
- def execute_delete(
1114
- self,
1115
- path: str | tuple[str, str],
1116
- where: str | None = None,
1117
- order: str | None = None,
1118
- limit: int | str | None = None,
1119
- report: bool | None = None,
1120
- **kwdata: Any
1121
- ) -> Result:
1122
- """
1123
- Delete the data of table in the datebase.
1124
-
1125
- Parameters
1126
- ----------
1127
- path : Table name, can contain database name, otherwise use `self.database`.
1128
- - `str`: Automatic extract database name and table name.
1129
- - `tuple[str, str]`: Database name and table name.
1130
- where : Clause `WHERE` content, join as `WHERE str`.
1131
- order : Clause `ORDER BY` content, join as `ORDER BY str`.
1132
- limit : Clause `LIMIT` content, join as `LIMIT int/str`.
1133
- report : Whether report SQL execute information.
1134
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
1135
- - `int`: Use this value.
1136
- kwdata : Keyword parameters for filling.
1137
-
1138
- Returns
1139
- -------
1140
- Result object.
1141
-
1142
- Examples
1143
- --------
1144
- Parameter `where` and `kwdata`.
1145
- >>> where = '`id` IN :ids'
1146
- >>> ids = (1, 2)
1147
- >>> result = Database.execute_delete('database.table', where, ids=ids)
1148
- >>> print(result.rowcount)
1149
- 2
1150
- """
1151
-
1152
- # Handle parameter.
1153
- database, table, _ = self.extract_path(path)
1154
-
1155
- # Generate SQL.
1156
- sqls = []
1157
-
1158
- ## Part 'DELETE' syntax.
1159
- sql_delete = f'DELETE FROM `{database}`.`{table}`'
1160
- sqls.append(sql_delete)
1161
-
1162
- ## Part 'WHERE' syntax.
1163
- if where is not None:
1164
- sql_where = f'WHERE {where}'
1165
- sqls.append(sql_where)
1166
-
1167
- ## Part 'ORDER BY' syntax.
1168
- if order is not None:
1169
- sql_order = f'ORDER BY {order}'
1170
- sqls.append(sql_order)
1171
-
1172
- ## Part 'LIMIT' syntax.
1173
- if limit is not None:
1174
- sql_limit = f'LIMIT {limit}'
1175
- sqls.append(sql_limit)
1176
-
1177
- ## Join sqls.
1178
- sqls = '\n'.join(sqls)
1179
-
1180
- # Execute SQL.
1181
- result = self.execute(sqls, report=report, **kwdata)
1182
-
1183
- return result
1184
-
1185
-
1186
- def execute_copy(
1187
- self,
1188
- path: str | tuple[str, str],
1189
- where: str | None = None,
1190
- limit: int | str | tuple[int, int] | None = None,
1191
- report: bool | None = None,
1192
- **kwdata: Any
1193
- ) -> Result:
1194
- """
1195
- Copy record of table in the datebase.
1196
-
1197
- Parameters
1198
- ----------
1199
- path : Table name, can contain database name, otherwise use `self.database`.
1200
- - `str`: Automatic extract database name and table name.
1201
- - `tuple[str, str]`: Database name and table name.
1202
- where : Clause `WHERE` content, join as `WHERE str`.
1203
- limit : Clause `LIMIT` content.
1204
- - `int | str`: Join as `LIMIT int/str`.
1205
- - `tuple[int, int]`: Join as `LIMIT int, int`.
1206
- report : Whether report SQL execute information.
1207
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
1208
- - `int`: Use this value.
1209
- kwdata : Keyword parameters for filling.
1210
- - `In 'WHERE' syntax`: Fill 'WHERE' syntax.
1211
- - `Not in 'WHERE' syntax`: Fill 'INSERT' and 'SELECT' syntax.
1212
- `str and first character is ':'`: Use this syntax.
1213
- `Any`: Use this value.
1214
-
1215
- Returns
1216
- -------
1217
- Result object.
1218
-
1219
- Examples
1220
- --------
1221
- Parameter `where` and `kwdata`.
1222
- >>> where = '`id` IN :ids'
1223
- >>> ids = (1, 2, 3)
1224
- >>> result = Database.execute_copy('database.table', where, 2, ids=ids, id=None, time=':NOW()')
1225
- >>> print(result.rowcount)
1226
- 2
1227
- """
1228
-
1229
- # Handle parameter.
1230
- database, table, _ = self.extract_path(path)
1231
- table_info: list[dict] = self.info(database)(table)()
1232
-
1233
- ## SQLite.
1234
- if self.backend == 'sqlite':
1235
- field_key = 'name'
1236
-
1237
- ## Other.
1238
- else:
1239
- field_key = 'COLUMN_NAME'
1240
-
1241
- fields = [
1242
- row[field_key]
1243
- for row in table_info
1244
- ]
1245
- pattern = '(?<!\\\\):(\\w+)'
1246
- if type(where) == str:
1247
- where_keys = findall(pattern, where)
1248
- else:
1249
- where_keys = ()
1250
-
1251
- # Generate SQL.
1252
- sqls = []
1253
-
1254
- ## Part 'INSERT' syntax.
1255
- sql_fields = ', '.join(
1256
- f'`{field}`'
1257
- for field in fields
1258
- if field not in kwdata
1259
- )
1260
- if kwdata != {}:
1261
- sql_fields_kwdata = ', '.join(
1262
- f'`{field}`'
1263
- for field in kwdata
1264
- if field not in where_keys
1265
- )
1266
- sql_fields_filter = filter(
1267
- lambda sql: sql != '',
1268
- (
1269
- sql_fields,
1270
- sql_fields_kwdata
1271
- )
1272
- )
1273
- sql_fields = ', '.join(sql_fields_filter)
1274
- sql_insert = f'INSERT INTO `{database}`.`{table}`({sql_fields})'
1275
- sqls.append(sql_insert)
1276
-
1277
- ## Part 'SELECT' syntax.
1278
- sql_values = ', '.join(
1279
- f'`{field}`'
1280
- for field in fields
1281
- if field not in kwdata
1282
- )
1283
- if kwdata != {}:
1284
- sql_values_kwdata = ', '.join(
1285
- value[1:]
1286
- if (
1287
- type(value) == str
1288
- and value.startswith(':')
1289
- and value != ':'
1290
- )
1291
- else f':{field}'
1292
- for field, value in kwdata.items()
1293
- if field not in where_keys
1294
- )
1295
- sql_values_filter = filter(
1296
- lambda sql: sql != '',
1297
- (
1298
- sql_values,
1299
- sql_values_kwdata
1300
- )
1301
- )
1302
- sql_values = ', '.join(sql_values_filter)
1303
- sql_select = (
1304
- f'SELECT {sql_values}\n'
1305
- f'FROM `{database}`.`{table}`'
1306
- )
1307
- sqls.append(sql_select)
1308
-
1309
- ## Part 'WHERE' syntax.
1310
- if where is not None:
1311
- sql_where = f'WHERE {where}'
1312
- sqls.append(sql_where)
1313
-
1314
- ## Part 'LIMIT' syntax.
1315
- if limit is not None:
1316
- if type(limit) in (str, int):
1317
- sql_limit = f'LIMIT {limit}'
1318
- else:
1319
- if len(limit) == 2:
1320
- sql_limit = f'LIMIT {limit[0]}, {limit[1]}'
1321
- else:
1322
- throw(ValueError, limit)
1323
- sqls.append(sql_limit)
1324
-
1325
- ## Join.
1326
- sql = '\n'.join(sqls)
1327
-
1328
- # Execute SQL.
1329
- result = self.execute(sql, report=report, **kwdata)
1330
-
1331
- return result
1332
-
1333
-
1334
- def execute_count(
1335
- self,
1336
- path: str | tuple[str, str],
1337
- where: str | None = None,
1338
- report: bool | None = None,
1339
- **kwdata: Any
1340
- ) -> int:
1341
- """
1342
- Count records.
1343
-
1344
- Parameters
1345
- ----------
1346
- path : Table name, can contain database name, otherwise use `self.database`.
1347
- - `str`: Automatic extract database name and table name.
1348
- - `tuple[str, str]`: Database name and table name.
1349
- where : Match condition, `WHERE` clause content, join as `WHERE str`.
1350
- - `None`: Match all.
1351
- - `str`: Match condition.
1352
- report : Whether report SQL execute information.
1353
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
1354
- - `int`: Use this value.
1355
- kwdata : Keyword parameters for filling.
1356
-
1357
- Returns
1358
- -------
1359
- Record count.
1360
-
1361
- Examples
1362
- --------
1363
- Parameter `where` and `kwdata`.
1364
- >>> where = '`id` IN :ids'
1365
- >>> ids = (1, 2)
1366
- >>> result = Database.execute_count('database.table', where, ids=ids)
1367
- >>> print(result)
1368
- 2
1369
- """
1370
-
1371
- # Handle parameter.
1372
- database, table, _ = self.extract_path(path)
1373
-
1374
- # Execute.
1375
- result = self.execute_select((database, table), '1', where=where, report=report, **kwdata)
1376
- count = len(tuple(result))
1377
-
1378
- return count
1379
-
1380
-
1381
- def execute_exist(
1382
- self,
1383
- path: str | tuple[str, str],
1384
- where: str | None = None,
1385
- report: bool | None = None,
1386
- **kwdata: Any
1387
- ) -> bool:
1388
- """
1389
- Judge the exist of record.
1390
-
1391
- Parameters
1392
- ----------
1393
- path : Table name, can contain database name, otherwise use `self.database`.
1394
- - `str`: Automatic extract database name and table name.
1395
- - `tuple[str, str]`: Database name and table name.
1396
- where : Match condition, `WHERE` clause content, join as `WHERE str`.
1397
- - `None`: Match all.
1398
- - `str`: Match condition.
1399
- report : Whether report SQL execute information.
1400
- - `None`, Use attribute `report_execute_info`: of object `ROption`.
1401
- - `int`: Use this value.
1402
- kwdata : Keyword parameters for filling.
1403
-
1404
- Returns
1405
- -------
1406
- Judged result.
1407
-
1408
- Examples
1409
- --------
1410
- Parameter `where` and `kwdata`.
1411
- >>> data = [{'id': 1}]
1412
- >>> Database.execute_insert('database.table', data)
1413
- >>> where = '`id` = :id_'
1414
- >>> id_ = 1
1415
- >>> result = Database.execute_exist('database.table', where, id_=id_)
1416
- >>> print(result)
1417
- True
1418
- """
1419
-
1420
- # Handle parameter.
1421
- database, table, _ = self.extract_path(path)
1422
-
1423
- # Execute.
1424
- result = self.execute_count(path, where, report, **kwdata)
1425
-
1426
- # Judge.
1427
- judge = result != 0
1428
-
1429
- return judge
1430
-
1431
-
1432
- def execute_generator(
1433
- self,
1434
- sql: str | TextClause,
1435
- data: TableData,
1436
- report: bool | None = None,
1437
- **kwdata: Any
1438
- ) -> Generator[Result, Any, None]:
1439
- """
1440
- Return a generator that can execute SQL.
1441
-
1442
- Parameters
1443
- ----------
1444
- sql : SQL in method `sqlalchemy.text` format, or `TextClause` object.
1445
- data : Data set for filling.
1446
- report : Whether report SQL execute information.
1447
- - `None`: Use attribute `default_report`.
1448
- - `bool`: Use this value.
1449
- kwdata : Keyword parameters for filling.
1450
-
1451
- Returns
1452
- -------
1453
- Generator.
1454
- """
1455
-
1456
- # Instance.
1457
- generator = Generator(
1458
- self.execute,
1459
- sql=sql,
1460
- report=report,
1461
- **kwdata
1462
- )
1463
-
1464
- # Add.
1465
- for row in data:
1466
- generator(**row)
1467
-
1468
- return generator.generator
1469
-
1470
-
1471
- def connect(self):
1472
- """
1473
- Build `DatabaseConnection` instance.
1474
-
1475
- Returns
1476
- -------
1477
- Database connection instance.
1478
- """
1479
-
1480
- # Import.
1481
- from .rconn import DatabaseConnection
1482
-
1483
- # Build.
1484
- dbconnection = DatabaseConnection(
1485
- self.engine.connect(),
1486
- self
1487
- )
1488
-
1489
- return dbconnection
1490
-
1491
-
1492
- @property
1493
- def exe(self):
1494
- """
1495
- Build `database path` instance.
1496
-
1497
- Returns
1498
- -------
1499
- Instance.
1500
-
1501
- Examples
1502
- --------
1503
- Execute.
1504
- >>> sql = 'select :value'
1505
- >>> result = DatabaseExecute(sql, value=1)
1506
-
1507
- Select.
1508
- >>> field = ['id', 'value']
1509
- >>> where = '`id` = ids'
1510
- >>> ids = (1, 2)
1511
- >>> result = DatabaseExecute.database.table(field, where, ids=ids)
1512
-
1513
- Insert.
1514
- >>> data = [{'id': 1}, {'id': 2}]
1515
- >>> duplicate = 'ignore'
1516
- >>> result = DatabaseExecute.database.table + data
1517
- >>> result = DatabaseExecute.database.table + (data, duplicate)
1518
- >>> result = DatabaseExecute.database.table + {'data': data, 'duplicate': duplicate}
1519
-
1520
- Update.
1521
- >>> data = [{'name': 'a', 'id': 1}, {'name': 'b', 'id': 2}]
1522
- >>> where_fields = 'id'
1523
- >>> result = DatabaseExecute.database.table & data
1524
- >>> result = DatabaseExecute.database.table & (data, where_fields)
1525
- >>> result = DatabaseExecute.database.table & {'data': data, 'where_fields': where_fields}
1526
-
1527
- Delete.
1528
- >>> where = '`id` IN (1, 2)'
1529
- >>> report = True
1530
- >>> result = DatabaseExecute.database.table - where
1531
- >>> result = DatabaseExecute.database.table - (where, report)
1532
- >>> result = DatabaseExecute.database.table - {'where': where, 'report': report}
1533
-
1534
- Copy.
1535
- >>> where = '`id` IN (1, 2)'
1536
- >>> limit = 1
1537
- >>> result = DatabaseExecute.database.table * where
1538
- >>> result = DatabaseExecute.database.table * (where, limit)
1539
- >>> result = DatabaseExecute.database.table * {'where': where, 'limit': limit}
1540
-
1541
- Exist.
1542
- >>> where = '`id` IN (1, 2)'
1543
- >>> report = True
1544
- >>> result = where in DatabaseExecute.database.table
1545
- >>> result = (where, report) in DatabaseExecute.database.table
1546
- >>> result = {'where': where, 'report': report} in DatabaseExecute.database.table
1547
-
1548
- Count.
1549
- >>> result = len(DatabaseExecute.database.table)
1550
-
1551
- Default database.
1552
- >>> field = ['id', 'value']
1553
- >>> engine = Database(**server, database)
1554
- >>> result = engine.exe.table()
1555
- """
1556
-
1557
- # Import.
1558
- from .rexec import DatabaseExecute
1559
-
1560
- # Build.
1561
- dbexecute = DatabaseExecute(self)
1562
-
1563
- return dbexecute
1564
-
1565
-
1566
211
  def schema(self, filter_default: bool = True) -> dict[str, dict[str, list[str]]]:
1567
212
  """
1568
213
  Get schemata of databases and tables and columns.
@@ -1576,11 +221,6 @@ class Database(DatabaseBase):
1576
221
  Schemata of databases and tables and columns.
1577
222
  """
1578
223
 
1579
- # Check.
1580
- if self.backend == 'sqlite':
1581
- text = 'not suitable for SQLite databases'
1582
- throw(AssertionError, text=text)
1583
-
1584
224
  # Handle parameter.
1585
225
  filter_db = (
1586
226
  'information_schema',
@@ -1632,12 +272,70 @@ class Database(DatabaseBase):
1632
272
  column_list.append(column)
1633
273
 
1634
274
  ## Add empty database.
1635
- for database_name in database_names:
1636
- schema_dict[database_name] = None
275
+ for name in database_names:
276
+ schema_dict[name] = None
1637
277
 
1638
278
  return schema_dict
1639
279
 
1640
280
 
281
+ def connect(self, autocommit: bool = False):
282
+ """
283
+ Build `DatabaseConnection` instance.
284
+
285
+ Parameters
286
+ ----------
287
+ autocommit: Whether automatic commit connection.
288
+
289
+ Returns
290
+ -------
291
+ Database connection instance.
292
+ """
293
+
294
+ # Import.
295
+ from .rconn import DatabaseConnection
296
+
297
+ # Build.
298
+ conn = DatabaseConnection(self, autocommit)
299
+
300
+ return conn
301
+
302
+
303
+ @property
304
+ def execute(self):
305
+ """
306
+ Build `DatabaseExecute` instance.
307
+
308
+ Returns
309
+ -------
310
+ Instance.
311
+ """
312
+
313
+ # Build.
314
+ dbconn = self.connect(True)
315
+ exec = dbconn.execute
316
+
317
+ return exec
318
+
319
+
320
+ @property
321
+ def orm(self):
322
+ """
323
+ Build `DatabaseORM` instance.
324
+
325
+ Returns
326
+ -------
327
+ Instance.
328
+ """
329
+
330
+ # Import.
331
+ from .rorm import DatabaseORM
332
+
333
+ # Build.
334
+ orm = DatabaseORM(self)
335
+
336
+ return orm
337
+
338
+
1641
339
  @property
1642
340
  def info(self):
1643
341
  """
@@ -1645,7 +343,7 @@ class Database(DatabaseBase):
1645
343
 
1646
344
  Returns
1647
345
  -------
1648
- Database schema information instance.
346
+ Instance.
1649
347
 
1650
348
  Examples
1651
349
  --------
@@ -1684,7 +382,7 @@ class Database(DatabaseBase):
1684
382
 
1685
383
  Returns
1686
384
  -------
1687
- Database build instance.
385
+ Instance.
1688
386
  """
1689
387
 
1690
388
  # Import.
@@ -1703,7 +401,7 @@ class Database(DatabaseBase):
1703
401
 
1704
402
  Returns
1705
403
  -------
1706
- Database file instance.
404
+ Instance.
1707
405
  """
1708
406
 
1709
407
  # Import.
@@ -1722,7 +420,7 @@ class Database(DatabaseBase):
1722
420
 
1723
421
  Returns
1724
422
  -------
1725
- Database file instance.
423
+ Instance.
1726
424
  """
1727
425
 
1728
426
  # Import.
@@ -1741,7 +439,7 @@ class Database(DatabaseBase):
1741
439
 
1742
440
  Returns
1743
441
  -------
1744
- Database file instance.
442
+ Instance.
1745
443
  """
1746
444
 
1747
445
  # Import.
@@ -1756,108 +454,79 @@ class Database(DatabaseBase):
1756
454
  @property
1757
455
  def status(self):
1758
456
  """
1759
- Build `DatabaseParametersStatus` or `DatabaseParametersPragma` instance.
457
+ Build `DatabaseParametersStatus` instance.
1760
458
 
1761
459
  Returns
1762
460
  -------
1763
- Database status parameters instance.
461
+ Instance.
1764
462
  """
1765
463
 
1766
464
  # Import.
1767
- from .rparam import DatabaseParametersStatus, DatabaseParametersPragma
465
+ from .rparam import DatabaseParametersStatus
1768
466
 
1769
467
  # Build.
468
+ dbps = DatabaseParametersStatus(self, False)
1770
469
 
1771
- ## SQLite.
1772
- if self.backend == 'sqlite':
1773
- dbp = DatabaseParametersPragma(self)
1774
-
1775
- ## Other.
1776
- else:
1777
- dbp = DatabaseParametersStatus(self, False)
1778
-
1779
- return dbp
470
+ return dbps
1780
471
 
1781
472
 
1782
473
  @property
1783
474
  def global_status(self):
1784
475
  """
1785
- Build `DatabaseParametersStatus` or `DatabaseParametersPragma` instance.
476
+ Build global `DatabaseParametersStatus` instance.
1786
477
 
1787
478
  Returns
1788
479
  -------
1789
- Global database status parameters instance.
480
+ Instance.
1790
481
  """
1791
482
 
1792
483
  # Import.
1793
- from .rparam import DatabaseParametersStatus, DatabaseParametersPragma
484
+ from .rparam import DatabaseParametersStatus
1794
485
 
1795
486
  # Build.
487
+ dbps = DatabaseParametersStatus(self, True)
1796
488
 
1797
- ## SQLite.
1798
- if self.backend == 'sqlite':
1799
- dbp = DatabaseParametersPragma(self)
1800
-
1801
- ## Other.
1802
- else:
1803
- dbp = DatabaseParametersStatus(self, True)
1804
-
1805
- return dbp
489
+ return dbps
1806
490
 
1807
491
 
1808
492
  @property
1809
493
  def variables(self):
1810
494
  """
1811
- Build `DatabaseParametersVariable` or `DatabaseParametersPragma` instance.
495
+ Build `DatabaseParametersVariable` instance.
1812
496
 
1813
497
  Returns
1814
498
  -------
1815
- Database variable parameters instance.
499
+ Instance.
1816
500
  """
1817
501
 
1818
502
  # Import.
1819
- from .rparam import DatabaseParametersVariable, DatabaseParametersPragma
503
+ from .rparam import DatabaseParametersVariable
1820
504
 
1821
505
  # Build.
506
+ dbpv = DatabaseParametersVariable(self, False)
1822
507
 
1823
- ## SQLite.
1824
- if self.backend == 'sqlite':
1825
- dbp = DatabaseParametersPragma(self)
1826
-
1827
- ## Other.
1828
- else:
1829
- dbp = DatabaseParametersVariable(self, False)
1830
-
1831
- return dbp
508
+ return dbpv
1832
509
 
1833
510
 
1834
511
  @property
1835
512
  def global_variables(self):
1836
513
  """
1837
- Build global `database variable parameters` instance.
514
+ Build global `DatabaseParametersVariable` instance.
1838
515
 
1839
516
  Returns
1840
517
  -------
1841
- Global database variable parameters instance.
518
+ Instance.
1842
519
  """
1843
520
 
1844
521
  # Import.
1845
- from .rparam import DatabaseParametersVariable, DatabaseParametersPragma
522
+ from .rparam import DatabaseParametersVariable
1846
523
 
1847
524
  # Build.
1848
525
 
1849
526
  ## SQLite.
1850
- if self.backend == 'sqlite':
1851
- dbp = DatabaseParametersPragma(self)
527
+ dbpv = DatabaseParametersVariable(self, True)
1852
528
 
1853
- ## Other.
1854
- else:
1855
- dbp = DatabaseParametersVariable(self, True)
1856
-
1857
- return dbp
1858
-
1859
-
1860
- __call__ = execute
529
+ return dbpv
1861
530
 
1862
531
 
1863
532
  def __str__(self) -> str:
@@ -1865,16 +534,6 @@ class Database(DatabaseBase):
1865
534
  Return connection information text.
1866
535
  """
1867
536
 
1868
- # Handle parameter.
1869
- if hasattr(self, 'engine'):
1870
- attr_dict = self.__dict__
1871
- else:
1872
- rdatabase: Database = self.rdatabase
1873
- attr_dict = {
1874
- **self.__dict__,
1875
- **rdatabase.__dict__
1876
- }
1877
-
1878
537
  # Generate.
1879
538
  filter_key = (
1880
539
  'engine',
@@ -1884,10 +543,10 @@ class Database(DatabaseBase):
1884
543
  )
1885
544
  info = {
1886
545
  key: value
1887
- for key, value in attr_dict.items()
546
+ for key, value in self.__dict__.items()
1888
547
  if key not in filter_key
1889
548
  }
1890
- info['count'] = self.count
549
+ info['count'] = self.count_conn
1891
550
  text = join_data_text(info)
1892
551
 
1893
552
  return text