reydb 1.2.1__py3-none-any.whl → 1.2.3__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/rbuild.py CHANGED
@@ -121,7 +121,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
121
121
  Field set SQL.
122
122
  """
123
123
 
124
- # Handle parameter.
124
+ # Set parameter.
125
125
 
126
126
  ## Constraint.
127
127
  constraint = ' ' + constraint
@@ -175,7 +175,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
175
175
  Index set SQL.
176
176
  """
177
177
 
178
- # Handle parameter.
178
+ # Set parameter.
179
179
  if fields.__class__ == str:
180
180
  fields = [fields]
181
181
  match type_:
@@ -275,7 +275,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
275
275
  SQL.
276
276
  """
277
277
 
278
- # Handle parameter.
278
+ # Set parameter.
279
279
  if type(path) == str:
280
280
  database, table = self.db.database, path
281
281
  else:
@@ -363,7 +363,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
363
363
  SQL.
364
364
  """
365
365
 
366
- # Handle parameter.
366
+ # Set parameter.
367
367
  if type(path) == str:
368
368
  database, table = self.db.database, path
369
369
  else:
@@ -478,7 +478,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
478
478
  SQL.
479
479
  """
480
480
 
481
- # Handle parameter.
481
+ # Set parameter.
482
482
  if type(path) == str:
483
483
  database, table = self.db.database, path
484
484
  else:
@@ -509,7 +509,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
509
509
  SQL.
510
510
  """
511
511
 
512
- # Handle parameter.
512
+ # Set parameter.
513
513
  if type(path) == str:
514
514
  database, table = self.db.database, path
515
515
  else:
@@ -616,7 +616,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
616
616
  SQL.
617
617
  """
618
618
 
619
- # Handle parameter.
619
+ # Set parameter.
620
620
  if type(path) == str:
621
621
  database, table = self.db.database, path
622
622
  else:
@@ -704,7 +704,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
704
704
  SQL.
705
705
  """
706
706
 
707
- # Handle parameter.
707
+ # Set parameter.
708
708
  if type(path) == str:
709
709
  database, table = self.db.database, path
710
710
  else:
@@ -792,7 +792,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
792
792
  SQL.
793
793
  """
794
794
 
795
- # Handle parameter.
795
+ # Set parameter.
796
796
  if type(path) == str:
797
797
  database, table = self.db.database, path
798
798
  else:
@@ -886,7 +886,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
886
886
  SQL.
887
887
  """
888
888
 
889
- # Handle parameter.
889
+ # Set parameter.
890
890
  if type(path) == str:
891
891
  database, table = self.db.database, path
892
892
  else:
@@ -917,7 +917,7 @@ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
917
917
  SQL.
918
918
  """
919
919
 
920
- # Handle parameter.
920
+ # Set parameter.
921
921
  if type(path) == str:
922
922
  database, table = self.db.database, path
923
923
  else:
@@ -1104,7 +1104,7 @@ class DatabaseBuild(DatabaseBuildSuper['rdb.Database']):
1104
1104
  skip : Whether skip existing table.
1105
1105
  """
1106
1106
 
1107
- # Handle parameter.
1107
+ # Set parameter.
1108
1108
  databases = databases or []
1109
1109
  tables = tables or []
1110
1110
  views = views or []
@@ -1187,6 +1187,227 @@ class DatabaseBuild(DatabaseBuildSuper['rdb.Database']):
1187
1187
 
1188
1188
  ### Execute.
1189
1189
  self.db.execute(sql)
1190
+
1191
+ ## Report.
1192
+ text = f"Table '{table}' of database '{database}' build completed."
1193
+ print(text)
1194
+ refresh_schema = True
1195
+
1196
+ # Refresh schema.
1197
+ if refresh_schema:
1198
+ self.db.schema()
1199
+
1200
+ # View.
1201
+ for params in views:
1202
+ path = params['path']
1203
+ if type(path) == str:
1204
+ database, table = self.db.database, path
1205
+ else:
1206
+ database, table = path
1207
+
1208
+ ## Exist.
1209
+ if (
1210
+ skip
1211
+ and self.db.schema.exist(database, table)
1212
+ ):
1213
+ continue
1214
+
1215
+ ## SQL.
1216
+ sql = self.get_sql_create_view(**params)
1217
+
1218
+ ## Confirm.
1219
+ if ask:
1220
+ self.input_confirm_build(sql)
1221
+
1222
+ ## Execute.
1223
+ self.db.execute(sql)
1224
+
1225
+ ## Report.
1226
+ text = f"View '{table}' of database '{database}' build completed."
1227
+ print(text)
1228
+
1229
+ # View stats.
1230
+ for params in views_stats:
1231
+ path = params['path']
1232
+ if type(path) == str:
1233
+ database, table = self.db.database, path
1234
+ else:
1235
+ database, table = path
1236
+
1237
+ ## Exist.
1238
+ if (
1239
+ skip
1240
+ and self.db.schema.exist(database, table)
1241
+ ):
1242
+ continue
1243
+
1244
+ ## SQL.
1245
+ sql = self.get_sql_create_view_stats(**params)
1246
+
1247
+ ## Confirm.
1248
+ if ask:
1249
+ self.input_confirm_build(sql)
1250
+
1251
+ ## Execute.
1252
+ self.db.execute(sql)
1253
+
1254
+ ## Report.
1255
+ text = f"View '{table}' of database '{database}' build completed."
1256
+ print(text)
1257
+
1258
+
1259
+ __call__ = build
1260
+
1261
+
1262
+ class DatabaseBuildAsync(DatabaseBuildSuper['rdb.DatabaseAsync']):
1263
+ """
1264
+ Asynchronous database build type.
1265
+ """
1266
+
1267
+
1268
+ async def create_orm_table(
1269
+ self,
1270
+ *models: Type[DatabaseORMModel] | DatabaseORMModel,
1271
+ skip: bool = False
1272
+ ) -> None:
1273
+ """
1274
+ Asynchronous create tables by ORM model.
1275
+
1276
+ Parameters
1277
+ ----------
1278
+ models : ORM model instances.
1279
+ skip : Whether skip existing table.
1280
+ """
1281
+
1282
+ # Create.
1283
+ await self.db.orm.create(*models, skip=skip)
1284
+
1285
+
1286
+ async def drop_orm_table(
1287
+ self,
1288
+ *models: Type[DatabaseORMModel] | DatabaseORMModel,
1289
+ skip: bool = False
1290
+ ) -> None:
1291
+ """
1292
+ Asynchronous delete tables by model.
1293
+
1294
+ Parameters
1295
+ ----------
1296
+ models : ORM model instances.
1297
+ skip : Skip not exist table.
1298
+ """
1299
+
1300
+ # Drop.
1301
+ await self.db.orm.drop(*models, skip=skip)
1302
+
1303
+
1304
+ async def build(
1305
+ self,
1306
+ databases: list[dict] | None = None,
1307
+ tables: list[dict] | None = None,
1308
+ tables_orm: list[Type[DatabaseORMModel]] | None = None,
1309
+ views: list[dict] | None = None,
1310
+ views_stats: list[dict] | None = None,
1311
+ ask: bool = True,
1312
+ skip: bool = False
1313
+ ) -> None:
1314
+ """
1315
+ Asynchronous build databases or tables.
1316
+
1317
+ Parameters
1318
+ ----------
1319
+ databases : Database build parameters, equivalent to the parameters of method `self.create_database`.
1320
+ tables : Tables build parameters, equivalent to the parameters of method `self.create_table`.
1321
+ views : Views build parameters, equivalent to the parameters of method `self.create_view`.
1322
+ views_stats : Views stats build parameters, equivalent to the parameters of method `self.create_view_stats`.
1323
+ ask : Whether ask confirm execute.
1324
+ skip : Whether skip existing table.
1325
+ """
1326
+
1327
+ # Set parameter.
1328
+ databases = databases or []
1329
+ tables = tables or []
1330
+ tables_orm = tables_orm or []
1331
+ views = views or []
1332
+ views_stats = views_stats or []
1333
+ refresh_schema = False
1334
+
1335
+ # Database.
1336
+ for params in databases:
1337
+ database = params['name']
1338
+
1339
+ ## Exist.
1340
+ if (
1341
+ skip
1342
+ and await self.db.schema.exist(database)
1343
+ ):
1344
+ continue
1345
+
1346
+ ## SQL.
1347
+ sql = self.get_sql_create_database(**params)
1348
+
1349
+ ## Confirm.
1350
+ if ask:
1351
+ self.input_confirm_build(sql)
1352
+
1353
+ ## Execute.
1354
+ await self.db.execute(sql)
1355
+
1356
+ ## Report.
1357
+ text = f"Database '{database}' build completed."
1358
+ print(text)
1359
+
1360
+ # Table.
1361
+ for params in tables:
1362
+
1363
+ ## ORM.
1364
+ if (
1365
+ is_instance(params)
1366
+ and isinstance(params, DatabaseORMModel)
1367
+ or issubclass(params, DatabaseORMModel)
1368
+ ):
1369
+ database = self.db.database
1370
+ table = params._table().name
1371
+
1372
+ ## Exist.
1373
+ if (
1374
+ skip
1375
+ and await self.db.schema.exist(self.db.database, table)
1376
+ ):
1377
+ continue
1378
+
1379
+ ## Confirm.
1380
+ if ask:
1381
+ text = self.get_orm_table_text(params)
1382
+ self.input_confirm_build(text)
1383
+
1384
+ ## Execute.
1385
+ await self.create_orm_table(params)
1386
+
1387
+ ## Parameter.
1388
+ else:
1389
+ path: str | tuple[str, str] = params['path']
1390
+ if type(path) == str:
1391
+ database, table = self.db.database, path
1392
+ else:
1393
+ database, table = path
1394
+
1395
+ ### Exist.
1396
+ if (
1397
+ skip
1398
+ and await self.db.schema.exist(database, table)
1399
+ ):
1400
+ continue
1401
+
1402
+ ### SQL.
1403
+ sql = self.get_sql_create_table(**params)
1404
+
1405
+ ### Confirm.
1406
+ if ask:
1407
+ self.input_confirm_build(sql)
1408
+
1409
+ ### Execute.
1410
+ await self.db.execute(sql)
1190
1411
  refresh_schema = True
1191
1412
 
1192
1413
  ## Report.
@@ -1197,6 +1418,1265 @@ class DatabaseBuild(DatabaseBuildSuper['rdb.Database']):
1197
1418
  if refresh_schema:
1198
1419
  self.db.schema()
1199
1420
 
1421
+ # View.
1422
+ for params in views:
1423
+ path = params['path']
1424
+ if type(path) == str:
1425
+ database, table = self.db.database, path
1426
+ else:
1427
+ database, table = path
1428
+
1429
+ ## Exist.
1430
+ if (
1431
+ skip
1432
+ and await self.db.schema.exist(database, table)
1433
+ ):
1434
+ continue
1435
+
1436
+ ## SQL.
1437
+ sql = self.get_sql_create_view(**params)
1438
+
1439
+ ## Confirm.
1440
+ if ask:
1441
+ self.input_confirm_build(sql)
1442
+
1443
+ ## Execute.
1444
+ await self.db.execute(sql)
1445
+
1446
+ ## Report.
1447
+ text = f"View '{table}' of database '{database}' build completed."
1448
+ print(text)
1449
+
1450
+ # View stats.
1451
+ for params in views_stats:
1452
+ path = params['path']
1453
+ if type(path) == str:
1454
+ database, table = self.db.database, path
1455
+ else:
1456
+ database, table = path
1457
+
1458
+ ## Exist.
1459
+ if (
1460
+ skip
1461
+ and await self.db.schema.exist(database, table)
1462
+ ):
1463
+ continue
1464
+
1465
+ ## SQL.
1466
+ sql = self.get_sql_create_view_stats(**params)
1467
+
1468
+ ## Confirm.
1469
+ if ask:
1470
+ self.input_confirm_build(sql)
1471
+
1472
+ ## Execute.
1473
+ await self.db.execute(sql)
1474
+
1475
+ ## Report.
1476
+ text = f"View '{table}' of database '{database}' build completed."
1477
+ print(text)
1478
+
1479
+
1480
+ __call__ = build
1481
+ # !/usr/bin/env python
1482
+ # -*- coding: utf-8 -*-
1483
+
1484
+ """
1485
+ @Time : 2023-10-14 23:05:35
1486
+ @Author : Rey
1487
+ @Contact : reyxbo@163.com
1488
+ @Explain : Database build methods.
1489
+ """
1490
+
1491
+
1492
+ from typing import TypedDict, NotRequired, Literal, Type, TypeVar, Generic
1493
+ from copy import deepcopy
1494
+ from reykit.rbase import throw, is_instance
1495
+ from reykit.rstdout import ask
1496
+
1497
+ from . import rdb
1498
+ from .rbase import DatabaseBase
1499
+ from .rorm import DatabaseORMModel
1500
+
1501
+
1502
+ __all__ = (
1503
+ 'DatabaseBuildSuper',
1504
+ 'DatabaseBuild',
1505
+ 'DatabaseBuildAsync'
1506
+ )
1507
+
1508
+
1509
+ FieldSet = TypedDict(
1510
+ 'FieldSet',
1511
+ {
1512
+ 'name': str,
1513
+ 'type': str,
1514
+ 'constraint': NotRequired[str | None],
1515
+ 'comment': NotRequired[str | None],
1516
+ 'position': NotRequired[Literal['first'] | str | None]
1517
+ }
1518
+ )
1519
+ type IndexType = Literal['noraml', 'unique', 'fulltext', 'spatial']
1520
+ IndexSet = TypedDict(
1521
+ 'IndexSet',
1522
+ {
1523
+ 'name': str,
1524
+ 'fields' : str | list[str],
1525
+ 'type': IndexType,
1526
+ 'comment': NotRequired[str | None]
1527
+ }
1528
+ )
1529
+ DatabaseT = TypeVar('DatabaseT', 'rdb.Database', 'rdb.DatabaseAsync')
1530
+
1531
+
1532
+ class DatabaseBuildSuper(DatabaseBase, Generic[DatabaseT]):
1533
+ """
1534
+ Database build super type.
1535
+ """
1536
+
1537
+
1538
+ def __init__(self, db: DatabaseT) -> None:
1539
+ """
1540
+ Build instance attributes.
1541
+
1542
+ Parameters
1543
+ ----------
1544
+ db: Database instance.
1545
+ """
1546
+
1547
+ # Set attribute.
1548
+ self.db = db
1549
+
1550
+
1551
+ def get_sql_create_database(
1552
+ self,
1553
+ name: str,
1554
+ character: str = 'utf8mb4',
1555
+ collate: str = 'utf8mb4_0900_ai_ci'
1556
+ ) -> str:
1557
+ """
1558
+ Get SQL of create database.
1559
+
1560
+ Parameters
1561
+ ----------
1562
+ name : Database name.
1563
+ character : Character set.
1564
+ collate : Collate rule.
1565
+ execute : Whether directly execute.
1566
+
1567
+ Returns
1568
+ -------
1569
+ SQL.
1570
+ """
1571
+
1572
+ # Generate.
1573
+ sql = f'CREATE DATABASE `{name}` CHARACTER SET {character} COLLATE {collate}'
1574
+
1575
+ return sql
1576
+
1577
+
1578
+ def __get_field_sql(
1579
+ self,
1580
+ name: str,
1581
+ type_: str,
1582
+ constraint: str = 'DEFAULT NULL',
1583
+ comment: str | None = None,
1584
+ position: str | None = None,
1585
+ old_name: str | None = None
1586
+ ) -> str:
1587
+ """
1588
+ Get a field set SQL.
1589
+
1590
+ Parameters
1591
+ ----------
1592
+ name : Field name.
1593
+ type_ : Field type.
1594
+ constraint : Field constraint.
1595
+ comment : Field comment.
1596
+ position : Field position.
1597
+ old_name : Field old name.
1598
+
1599
+ Returns
1600
+ -------
1601
+ Field set SQL.
1602
+ """
1603
+
1604
+ # Set parameter.
1605
+
1606
+ ## Constraint.
1607
+ constraint = ' ' + constraint
1608
+
1609
+ ## Comment.
1610
+ if comment is None:
1611
+ comment = ''
1612
+ else:
1613
+ comment = f" COMMENT '{comment}'"
1614
+
1615
+ ## Position.
1616
+ match position:
1617
+ case None:
1618
+ position = ''
1619
+ case 'first':
1620
+ position = ' FIRST'
1621
+ case _:
1622
+ position = f' AFTER `{position}`'
1623
+
1624
+ ## Old name.
1625
+ if old_name is None:
1626
+ old_name = ''
1627
+ else:
1628
+ old_name = f'`{old_name}` '
1629
+
1630
+ # Generate.
1631
+ sql = f'{old_name}`{name}` {type_}{constraint}{comment}{position}'
1632
+
1633
+ return sql
1634
+
1635
+
1636
+ def __get_index_sql(
1637
+ self,
1638
+ name: str,
1639
+ fields: str | list[str],
1640
+ type_: IndexType,
1641
+ comment: str | None = None
1642
+ ) -> str:
1643
+ """
1644
+ Get a index set SQL.
1645
+
1646
+ Parameters
1647
+ ----------
1648
+ name : Index name.
1649
+ fields : Index fileds.
1650
+ type\\_ : Index type.
1651
+ comment : Index comment.
1652
+
1653
+ Returns
1654
+ -------
1655
+ Index set SQL.
1656
+ """
1657
+
1658
+ # Set parameter.
1659
+ if fields.__class__ == str:
1660
+ fields = [fields]
1661
+ match type_:
1662
+ case 'noraml':
1663
+ type_ = 'KEY'
1664
+ method = ' USING BTREE'
1665
+ case 'unique':
1666
+ type_ = 'UNIQUE KEY'
1667
+ method = ' USING BTREE'
1668
+ case 'fulltext':
1669
+ type_ = 'FULLTEXT KEY'
1670
+ method = ''
1671
+ case 'spatial':
1672
+ type_ = 'SPATIAL KEY'
1673
+ method = ''
1674
+ case _:
1675
+ throw(ValueError, type_)
1676
+ if comment in (None, ''):
1677
+ comment = ''
1678
+ else:
1679
+ comment = f" COMMENT '{comment}'"
1680
+
1681
+ # Generate.
1682
+
1683
+ ## Fields.
1684
+ sql_fields = ', '.join(
1685
+ [
1686
+ f'`{field}`'
1687
+ for field in fields
1688
+ ]
1689
+ )
1690
+
1691
+ ## Join.
1692
+ sql = f'{type_} `{name}` ({sql_fields}){method}{comment}'
1693
+
1694
+ return sql
1695
+
1696
+
1697
+ def get_sql_create_table(
1698
+ self,
1699
+ path: str | tuple[str, str],
1700
+ fields: FieldSet | list[FieldSet],
1701
+ primary: str | list[str] | None = None,
1702
+ indexes: IndexSet | list[IndexSet] | None = None,
1703
+ engine: str = 'InnoDB',
1704
+ increment: int = 1,
1705
+ charset: str = 'utf8mb4',
1706
+ collate: str = 'utf8mb4_0900_ai_ci',
1707
+ comment: str | None = None
1708
+ ) -> str:
1709
+ """
1710
+ Get SQL of create table.
1711
+
1712
+ Parameters
1713
+ ----------
1714
+ path : Path.
1715
+ - `str`: Table name.
1716
+ - `tuple[str, str]`: Database name and table name.
1717
+ fields : Fields set table.
1718
+ - `Key 'name'`: Field name, required.
1719
+ - `Key 'type'`: Field type, required.
1720
+ - `Key 'constraint'`: Field constraint.
1721
+ `Empty or None`: Use 'DEFAULT NULL'.
1722
+ `str`: Use this value.
1723
+ - `Key 'comment'`: Field comment.
1724
+ `Empty or None`: Not comment.
1725
+ `str`: Use this value.
1726
+ - `Key 'position'`: Field position.
1727
+ `None`: Last.
1728
+ `Literal['first']`: First.
1729
+ `str`: After this field.
1730
+ primary : Primary key fields.
1731
+ - `str`: One field.
1732
+ - `list[str]`: Multiple fileds.
1733
+ indexes : Index set table.
1734
+ - `Key 'name'`: Index name, required.
1735
+ - `Key 'fields'`: Index fields, required.
1736
+ `str`: One field.
1737
+ `list[str]`: Multiple fileds.
1738
+ - `Key 'type'`: Index type.
1739
+ `Literal['noraml']`: Noraml key.
1740
+ `Literal['unique']`: Unique key.
1741
+ `Literal['fulltext']`: Full text key.
1742
+ `Literal['spatial']`: Spatial key.
1743
+ - `Key 'comment'`: Field comment.
1744
+ `Empty or None`: Not comment.
1745
+ `str`: Use this value.
1746
+ engine : Engine type.
1747
+ increment : Automatic Increment start value.
1748
+ charset : Charset type.
1749
+ collate : Collate type.
1750
+ comment : Table comment.
1751
+ execute : Whether directly execute.
1752
+
1753
+ Returns
1754
+ -------
1755
+ SQL.
1756
+ """
1757
+
1758
+ # Set parameter.
1759
+ if type(path) == str:
1760
+ database, table = self.db.database, path
1761
+ else:
1762
+ database, table = path
1763
+ if fields.__class__ == dict:
1764
+ fields = [fields]
1765
+ if primary.__class__ == str:
1766
+ primary = [primary]
1767
+ if primary in ([], ['']):
1768
+ primary = None
1769
+ if indexes.__class__ == dict:
1770
+ indexes = [indexes]
1771
+
1772
+ ## Compatible dictionary key name.
1773
+ fields = deepcopy(fields)
1774
+ for row in fields:
1775
+ row['type_'] = row.pop('type')
1776
+ if indexes is not None:
1777
+ indexes = deepcopy(indexes)
1778
+ for row in indexes:
1779
+ row['type_'] = row.pop('type')
1780
+
1781
+ # Generate.
1782
+
1783
+ ## Fields.
1784
+ sql_fields = [
1785
+ self.__get_field_sql(**field)
1786
+ for field in fields
1787
+ ]
1788
+
1789
+ ## Primary.
1790
+ if primary is not None:
1791
+ keys = ', '.join(
1792
+ [
1793
+ f'`{key}`'
1794
+ for key in primary
1795
+ ]
1796
+ )
1797
+ sql_primary = f'PRIMARY KEY ({keys}) USING BTREE'
1798
+ sql_fields.append(sql_primary)
1799
+
1800
+ ## Indexes.
1801
+ if indexes is not None:
1802
+ sql_indexes = [
1803
+ self.__get_index_sql(**index)
1804
+ for index in indexes
1805
+ ]
1806
+ sql_fields.extend(sql_indexes)
1807
+
1808
+ ## Comment.
1809
+ if comment is None:
1810
+ sql_comment = ''
1811
+ else:
1812
+ sql_comment = f" COMMENT='{comment}'"
1813
+
1814
+ ## Join.
1815
+ sql_fields = ',\n '.join(sql_fields)
1816
+ sql = (
1817
+ f'CREATE TABLE `{database}`.`{table}`(\n'
1818
+ f' {sql_fields}\n'
1819
+ f') ENGINE={engine} AUTO_INCREMENT={increment} CHARSET={charset} COLLATE={collate}{sql_comment}'
1820
+ )
1821
+
1822
+ return sql
1823
+
1824
+
1825
+ def get_sql_create_view(
1826
+ self,
1827
+ path: str | tuple[str, str],
1828
+ select: str
1829
+ ) -> str:
1830
+ """
1831
+ Get SQL of create view.
1832
+
1833
+ Parameters
1834
+ ----------
1835
+ path : Path.
1836
+ - `str`: Table name.
1837
+ - `tuple[str, str]`: Database name and table name.
1838
+ select : View select SQL.
1839
+ execute : Whether directly execute.
1840
+
1841
+ Returns
1842
+ -------
1843
+ SQL.
1844
+ """
1845
+
1846
+ # Set parameter.
1847
+ if type(path) == str:
1848
+ database, table = self.db.database, path
1849
+ else:
1850
+ database, table = path
1851
+
1852
+ # Generate SQL.
1853
+ select = select.replace('\n', '\n ')
1854
+ sql = f'CREATE VIEW `{database}`.`{table}` AS (\n {select}\n)'
1855
+
1856
+ return sql
1857
+
1858
+
1859
+ def get_sql_create_view_stats(
1860
+ self,
1861
+ path: str | tuple[str, str],
1862
+ items: list[dict]
1863
+ ) -> str:
1864
+ """
1865
+ Get SQL of create stats view.
1866
+
1867
+ Parameters
1868
+ ----------
1869
+ path : Path.
1870
+ - `str`: Table name.
1871
+ - `tuple[str, str]`: Database name and table name.
1872
+ items : Items set table.
1873
+ - `Key 'name'`: Item name, required.
1874
+ - `Key 'select'`: Item select SQL, must only return one value, required.
1875
+ - `Key 'comment'`: Item comment.
1876
+ execute : Whether directly execute.
1877
+
1878
+ Returns
1879
+ -------
1880
+ SQL.
1881
+ """
1882
+
1883
+ # Check.
1884
+ if items == []:
1885
+ throw(ValueError, items)
1886
+
1887
+ # Generate select SQL.
1888
+ item_first = items[0]
1889
+ select_first = "SELECT '%s' AS `item`,\n(\n %s\n) AS `value`,\n%s AS `comment`" % (
1890
+ item_first['name'],
1891
+ item_first['select'].replace('\n', '\n '),
1892
+ (
1893
+ 'NULL'
1894
+ if 'comment' not in item_first
1895
+ else "'%s'" % item_first['comment']
1896
+ )
1897
+ )
1898
+ selects = [
1899
+ "SELECT '%s',\n(\n %s\n),\n%s" % (
1900
+ item['name'],
1901
+ item['select'].replace('\n', '\n '),
1902
+ (
1903
+ 'NULL'
1904
+ if 'comment' not in item
1905
+ else "'%s'" % item['comment']
1906
+ )
1907
+ )
1908
+ for item in items[1:]
1909
+ ]
1910
+ selects[0:0] = [select_first]
1911
+ select = '\nUNION\n'.join(selects)
1912
+
1913
+ # Create.
1914
+ sql = self.get_sql_create_view(path, select)
1915
+
1916
+ return sql
1917
+
1918
+
1919
+ def get_sql_drop_database(
1920
+ self,
1921
+ database: str
1922
+ ) -> str:
1923
+ """
1924
+ Get SQL of drop database.
1925
+
1926
+ Parameters
1927
+ ----------
1928
+ database : Database name.
1929
+ execute : Whether directly execute.
1930
+
1931
+ Returns
1932
+ -------
1933
+ SQL.
1934
+ """
1935
+
1936
+ # Generate.
1937
+ sql = f'DROP DATABASE `{database}`'
1938
+
1939
+ return sql
1940
+
1941
+
1942
+ def get_sql_drop_table(
1943
+ self,
1944
+ path: str | tuple[str, str]
1945
+ ) -> str:
1946
+ """
1947
+ Get SQL of drop table.
1948
+
1949
+ Parameters
1950
+ ----------
1951
+ path : Path.
1952
+ - `str`: Table name.
1953
+ - `tuple[str, str]`: Database name and table name.
1954
+ execute : Whether directly execute.
1955
+
1956
+ Returns
1957
+ -------
1958
+ SQL.
1959
+ """
1960
+
1961
+ # Set parameter.
1962
+ if type(path) == str:
1963
+ database, table = self.db.database, path
1964
+ else:
1965
+ database, table = path
1966
+
1967
+ # Generate.
1968
+ sql = f'DROP TABLE `{database}`.`{table}`'
1969
+
1970
+ return sql
1971
+
1972
+
1973
+ def get_sql_drop_view(
1974
+ self,
1975
+ path: str | tuple[str, str]
1976
+ ) -> str:
1977
+ """
1978
+ Get SQL of drop view.
1979
+
1980
+ Parameters
1981
+ ----------
1982
+ path : Path.
1983
+ - `str`: Table name.
1984
+ - `tuple[str, str]`: Database name and table name.
1985
+ execute : Whether directly execute.
1986
+
1987
+ Returns
1988
+ -------
1989
+ SQL.
1990
+ """
1991
+
1992
+ # Set parameter.
1993
+ if type(path) == str:
1994
+ database, table = self.db.database, path
1995
+ else:
1996
+ database, table = path
1997
+
1998
+ # Generate SQL.
1999
+ sql = 'DROP VIEW `%s`.`%s`' % (database, table)
2000
+
2001
+ return sql
2002
+
2003
+
2004
+ def get_sql_alter_database(
2005
+ self,
2006
+ database: str,
2007
+ character: str | None = None,
2008
+ collate: str | None = None
2009
+ ) -> str:
2010
+ """
2011
+ Get SQL of alter database.
2012
+
2013
+ Parameters
2014
+ ----------
2015
+ database : Database name.
2016
+ character : Character set.
2017
+ - `None`: Not alter.
2018
+ - `str`: Alter to this value.
2019
+ collate : Collate rule.
2020
+ - `None`: Not alter.
2021
+ - `str`: Alter to this value.
2022
+ execute : Whether directly execute.
2023
+
2024
+ Returns
2025
+ -------
2026
+ SQL.
2027
+ """
2028
+
2029
+ # Generate.
2030
+
2031
+ ## Character.
2032
+ if character is None:
2033
+ sql_character = ''
2034
+ else:
2035
+ sql_character = f' CHARACTER SET {character}'
2036
+
2037
+ ## Collate.
2038
+ if collate is None:
2039
+ sql_collate = ''
2040
+ else:
2041
+ sql_collate = f' COLLATE {collate}'
2042
+
2043
+ ## Join.
2044
+ sql = f'ALTER DATABASE `{database}`{sql_character}{sql_collate}'
2045
+
2046
+ return sql
2047
+
2048
+
2049
+ def get_sql_alter_table_add(
2050
+ self,
2051
+ path: str | tuple[str, str],
2052
+ fields: FieldSet | list[FieldSet] | None = None,
2053
+ primary: str | list[str] | None = None,
2054
+ indexes: IndexSet | list[IndexSet] | None = None
2055
+ ) -> str:
2056
+ """
2057
+ Get SQL of alter table add filed.
2058
+
2059
+ Parameters
2060
+ ----------
2061
+ path : Path.
2062
+ - `str`: Table name.
2063
+ - `tuple[str, str]`: Database name and table name.
2064
+ fields : Fields set table.
2065
+ - `Key 'name'`: Field name, required.
2066
+ - `Key 'type'`: Field type, required.
2067
+ - `Key 'constraint'`: Field constraint.
2068
+ `Empty or None`: Use 'DEFAULT NULL'.
2069
+ `str`: Use this value.
2070
+ - `Key 'comment'`: Field comment.
2071
+ `Empty or None`: Not comment.
2072
+ `str`: Use this value.
2073
+ - `Key 'position'`: Field position.
2074
+ `None`: Last.
2075
+ `Literal['first']`: First.
2076
+ `str`: After this field.
2077
+ primary : Primary key fields.
2078
+ - `str`: One field.
2079
+ - `list[str]`: Multiple fileds.
2080
+ indexes : Index set table.
2081
+ - `Key 'name'`: Index name, required.
2082
+ - `Key 'fields'`: Index fields, required.
2083
+ `str`: One field.
2084
+ `list[str]`: Multiple fileds.
2085
+ - `Key 'type'`: Index type.
2086
+ `Literal['noraml']`: Noraml key.
2087
+ `Literal['unique']`: Unique key.
2088
+ `Literal['fulltext']`: Full text key.
2089
+ `Literal['spatial']`: Spatial key.
2090
+ - `Key 'comment'`: Field comment.
2091
+ `Empty or None`: Not comment.
2092
+ `str`: Use this value.
2093
+
2094
+ Returns
2095
+ -------
2096
+ SQL.
2097
+ """
2098
+
2099
+ # Set parameter.
2100
+ if type(path) == str:
2101
+ database, table = self.db.database, path
2102
+ else:
2103
+ database, table = path
2104
+ if fields.__class__ == dict:
2105
+ fields = [fields]
2106
+ if primary.__class__ == str:
2107
+ primary = [primary]
2108
+ if primary in ([], ['']):
2109
+ primary = None
2110
+ if indexes.__class__ == dict:
2111
+ indexes = [indexes]
2112
+
2113
+ ## Compatible dictionary key name.
2114
+ fields = deepcopy(fields)
2115
+ for row in fields:
2116
+ row['type_'] = row.pop('type')
2117
+ if indexes is not None:
2118
+ indexes = deepcopy(indexes)
2119
+ for row in indexes:
2120
+ row['type_'] = row.pop('type')
2121
+
2122
+ # Generate.
2123
+ sql_content = []
2124
+
2125
+ ## Fields.
2126
+ if fields is not None:
2127
+ sql_fields = [
2128
+ 'COLUMN ' + self.__get_field_sql(**field)
2129
+ for field in fields
2130
+ ]
2131
+ sql_content.extend(sql_fields)
2132
+
2133
+ ## Primary.
2134
+ if primary is not None:
2135
+ keys = ', '.join(
2136
+ [
2137
+ f'`{key}`'
2138
+ for key in primary
2139
+ ]
2140
+ )
2141
+ sql_primary = f'PRIMARY KEY ({keys}) USING BTREE'
2142
+ sql_content.append(sql_primary)
2143
+
2144
+ ## Indexes.
2145
+ if indexes is not None:
2146
+ sql_indexes = [
2147
+ self.__get_index_sql(**index)
2148
+ for index in indexes
2149
+ ]
2150
+ sql_content.extend(sql_indexes)
2151
+
2152
+ ## Join.
2153
+ sql_content = ',\n ADD '.join(sql_content)
2154
+ sql = (
2155
+ f'ALTER TABLE `{database}`.`{table}`\n'
2156
+ f' ADD {sql_content}'
2157
+ )
2158
+
2159
+ return sql
2160
+
2161
+
2162
+ def get_sql_alter_table_drop(
2163
+ self,
2164
+ path: str | tuple[str, str],
2165
+ fields: str | list[str] | None = None,
2166
+ primary: bool = False,
2167
+ indexes: str | list[str] | None = None
2168
+ ) -> str:
2169
+ """
2170
+ Get SQL of alter table drop field.
2171
+
2172
+ Parameters
2173
+ ----------
2174
+ path : Path.
2175
+ - `str`: Table name.
2176
+ - `tuple[str, str]`: Database name and table name.
2177
+ fields : Delete fields name.
2178
+ primary : Whether delete primary key.
2179
+ indexes : Delete indexes name.
2180
+ execute : Whether directly execute.
2181
+
2182
+ Returns
2183
+ -------
2184
+ SQL.
2185
+ """
2186
+
2187
+ # Set parameter.
2188
+ if type(path) == str:
2189
+ database, table = self.db.database, path
2190
+ else:
2191
+ database, table = path
2192
+ if fields.__class__ == str:
2193
+ fields = [fields]
2194
+ if indexes.__class__ == str:
2195
+ indexes = [indexes]
2196
+
2197
+ # Generate.
2198
+ sql_content = []
2199
+
2200
+ ## Fields.
2201
+ if fields is not None:
2202
+ sql_fields = [
2203
+ 'COLUMN ' + field
2204
+ for field in fields
2205
+ ]
2206
+ sql_content.extend(sql_fields)
2207
+
2208
+ ## Primary.
2209
+ if primary:
2210
+ sql_primary = 'PRIMARY KEY'
2211
+ sql_content.append(sql_primary)
2212
+
2213
+ ## Indexes.
2214
+ if indexes is not None:
2215
+ sql_indexes = [
2216
+ 'INDEX ' + index
2217
+ for index in indexes
2218
+ ]
2219
+ sql_content.extend(sql_indexes)
2220
+
2221
+ ## Join.
2222
+ sql_content = ',\n DROP '.join(sql_content)
2223
+ sql = (
2224
+ f'ALTER TABLE `{database}`.`{table}`\n'
2225
+ f' DROP {sql_content}'
2226
+ )
2227
+
2228
+ return sql
2229
+
2230
+
2231
+ def get_sql_alter_table_change(
2232
+ self,
2233
+ path: str | tuple[str, str],
2234
+ fields: FieldSet | list[FieldSet] | None = None,
2235
+ rename: str | None = None,
2236
+ engine: str | None = None,
2237
+ increment: int | None = None,
2238
+ charset: str | None = None,
2239
+ collate: str | None = None
2240
+ ) -> str:
2241
+ """
2242
+ Get SQL of alter database.
2243
+
2244
+ Parameters
2245
+ ----------
2246
+ path : Path.
2247
+ - `str`: Table name.
2248
+ - `tuple[str, str]`: Database name and table name.
2249
+ fields : Fields set table.
2250
+ - `Key 'name'`: Field name, required.
2251
+ - `Key 'type'`: Field type, required.
2252
+ - `Key 'constraint'`: Field constraint.
2253
+ `Empty or None`: Use 'DEFAULT NULL'.
2254
+ `str`: Use this value.
2255
+ - `Key 'comment'`: Field comment.
2256
+ `Empty or None`: Not comment.
2257
+ `str`: Use this value.
2258
+ - `Key 'position'`: Field position.
2259
+ `None`: Last.
2260
+ `Literal['first']`: First.
2261
+ `str`: After this field.
2262
+ - `Key 'old_name'`: Field old name.
2263
+ rename : Table new name.
2264
+ engine : Engine type.
2265
+ increment : Automatic Increment start value.
2266
+ charset : Charset type.
2267
+ collate : Collate type.
2268
+ execute : Whether directly execute.
2269
+
2270
+ Returns
2271
+ -------
2272
+ SQL.
2273
+ """
2274
+
2275
+ # Set parameter.
2276
+ if type(path) == str:
2277
+ database, table = self.db.database, path
2278
+ else:
2279
+ database, table = path
2280
+ if fields.__class__ == dict:
2281
+ fields = [fields]
2282
+
2283
+ ## Compatible dictionary key name.
2284
+ fields = deepcopy(fields)
2285
+ for row in fields:
2286
+ row['type_'] = row.pop('type')
2287
+
2288
+ # Generate.
2289
+ sql_content = []
2290
+
2291
+ ## Rename.
2292
+ if rename is not None:
2293
+ sql_rename = f'RENAME `{database}`.`{rename}`'
2294
+ sql_content.append(sql_rename)
2295
+
2296
+ ## Fields.
2297
+ if fields is not None:
2298
+ sql_fields = [
2299
+ '%s %s' % (
2300
+ (
2301
+ 'MODIFY'
2302
+ if 'old_name' not in field
2303
+ else 'CHANGE'
2304
+ ),
2305
+ self.__get_field_sql(**field)
2306
+ )
2307
+ for field in fields
2308
+ ]
2309
+ sql_content.extend(sql_fields)
2310
+
2311
+ ## Attribute.
2312
+ sql_attr = []
2313
+
2314
+ ### Engine.
2315
+ if engine is not None:
2316
+ sql_engine = f'ENGINE={engine}'
2317
+ sql_attr.append(sql_engine)
2318
+
2319
+ ### Increment.
2320
+ if increment is not None:
2321
+ sql_increment = f'AUTO_INCREMENT={increment}'
2322
+ sql_attr.append(sql_increment)
2323
+
2324
+ ### Charset.
2325
+ if charset is not None:
2326
+ sql_charset = f'CHARSET={charset}'
2327
+ sql_attr.append(sql_charset)
2328
+
2329
+ ### Collate.
2330
+ if collate is not None:
2331
+ sql_collate = f'COLLATE={collate}'
2332
+ sql_attr.append(sql_collate)
2333
+
2334
+ if sql_attr != []:
2335
+ sql_attr = ' '.join(sql_attr)
2336
+ sql_content.append(sql_attr)
2337
+
2338
+ ## Join.
2339
+ sql_content = ',\n '.join(sql_content)
2340
+ sql = (
2341
+ f'ALTER TABLE `{database}`.`{table}`\n'
2342
+ f' {sql_content}'
2343
+ )
2344
+
2345
+ return sql
2346
+
2347
+
2348
+ def get_sql_alter_view(
2349
+ self,
2350
+ path: str | tuple[str, str],
2351
+ select: str
2352
+ ) -> str:
2353
+ """
2354
+ Get SQL of alter view.
2355
+
2356
+ Parameters
2357
+ ----------
2358
+ path : Path.
2359
+ - `str`: Table name.
2360
+ - `tuple[str, str]`: Database name and table name.
2361
+ select : View select SQL.
2362
+ execute : Whether directly execute.
2363
+
2364
+ Returns
2365
+ -------
2366
+ SQL.
2367
+ """
2368
+
2369
+ # Set parameter.
2370
+ if type(path) == str:
2371
+ database, table = self.db.database, path
2372
+ else:
2373
+ database, table = path
2374
+
2375
+ # Generate SQL.
2376
+ sql = 'ALTER VIEW `%s`.`%s` AS\n%s' % (database, table, select)
2377
+
2378
+ return sql
2379
+
2380
+
2381
+ def get_sql_truncate_table(
2382
+ self,
2383
+ path: str | tuple[str, str]
2384
+ ) -> str:
2385
+ """
2386
+ Get SQL of truncate table.
2387
+
2388
+ Parameters
2389
+ ----------
2390
+ path : Path.
2391
+ - `str`: Table name.
2392
+ - `tuple[str, str]`: Database name and table name.
2393
+ execute : Whether directly execute.
2394
+
2395
+ Returns
2396
+ -------
2397
+ SQL.
2398
+ """
2399
+
2400
+ # Set parameter.
2401
+ if type(path) == str:
2402
+ database, table = self.db.database, path
2403
+ else:
2404
+ database, table = path
2405
+
2406
+ # Generate.
2407
+ sql = f'TRUNCATE TABLE `{database}`.`{table}`'
2408
+
2409
+ return sql
2410
+
2411
+
2412
+ def input_confirm_build(
2413
+ self,
2414
+ sql: str
2415
+ ) -> None:
2416
+ """
2417
+ Print tip text, and confirm execute SQL. If reject, throw exception.
2418
+
2419
+ Parameters
2420
+ ----------
2421
+ sql : SQL.
2422
+ """
2423
+
2424
+ # Confirm.
2425
+ text = 'Do you want to execute SQL to build the database? Otherwise stop program. (y/n) '
2426
+ command = ask(
2427
+ sql,
2428
+ text,
2429
+ title='SQL',
2430
+ frame='top'
2431
+ )
2432
+
2433
+ # Check.
2434
+ while True:
2435
+ command = command.lower()
2436
+ match command:
2437
+
2438
+ ## Confirm.
2439
+ case 'y':
2440
+ break
2441
+
2442
+ ## Stop.
2443
+ case 'n':
2444
+ raise AssertionError('program stop')
2445
+
2446
+ ## Reenter.
2447
+ case _:
2448
+ text = 'Incorrect input, reenter. (y/n) '
2449
+ command = input(text)
2450
+
2451
+
2452
+ def get_orm_table_text(self, model: DatabaseORMModel) -> str:
2453
+ """
2454
+ Get table text from ORM model.
2455
+
2456
+ Parameters
2457
+ ----------
2458
+ model : ORM model instances.
2459
+
2460
+ Returns
2461
+ -------
2462
+ Table text.
2463
+ """
2464
+
2465
+ # Get.
2466
+ table = model._table()
2467
+ text = f'TABLE `{self.db.database}`.`{table}`'
2468
+ if 'mysql_charset' in table.kwargs:
2469
+ text += f" | CHARSET '{table.kwargs['mysql_charset']}'"
2470
+ if table.comment:
2471
+ text += f" | COMMENT '{table.comment}'"
2472
+
2473
+ ## Field.
2474
+ text += '\n' + '\n'.join(
2475
+ [
2476
+ f' FIELD `{column.name}` : {column.type}' + (
2477
+ ' | NOT NULL'
2478
+ if (
2479
+ not column.nullable
2480
+ or column.primary_key
2481
+ )
2482
+ else ' | NULL'
2483
+ ) + (
2484
+ ''
2485
+ if not column.primary_key
2486
+ else ' | KEY AUTO'
2487
+ if column.autoincrement
2488
+ else ' | KEY'
2489
+ ) + (
2490
+ f" | DEFAULT '{column.server_default.arg}'"
2491
+ if column.server_default
2492
+ else ''
2493
+ ) + (
2494
+ f" | COMMMENT '{column.comment}'"
2495
+ if column.comment
2496
+ else ''
2497
+ )
2498
+ for column in table.columns
2499
+ ]
2500
+ )
2501
+
2502
+ ## Index.
2503
+ if (table.indexes):
2504
+ text += '\n' + '\n'.join(
2505
+ [
2506
+ (
2507
+ ' UNIQUE'
2508
+ if index.unique
2509
+ else ' NORMAL'
2510
+ ) + f' INDEX `{index.name}` : ' + ', '.join(
2511
+ [
2512
+ f'`{column.name}`'
2513
+ for column in index.expressions
2514
+ ]
2515
+ )
2516
+ for index in table.indexes
2517
+ ]
2518
+ )
2519
+
2520
+ return text
2521
+
2522
+
2523
+ class DatabaseBuild(DatabaseBuildSuper['rdb.Database']):
2524
+ """
2525
+ Database build type.
2526
+ """
2527
+
2528
+
2529
+ def create_orm_table(
2530
+ self,
2531
+ *models: Type[DatabaseORMModel] | DatabaseORMModel,
2532
+ skip: bool = False
2533
+ ) -> None:
2534
+ """
2535
+ Create tables by ORM model.
2536
+
2537
+ Parameters
2538
+ ----------
2539
+ models : ORM model instances.
2540
+ skip : Whether skip existing table.
2541
+ """
2542
+
2543
+ # Create.
2544
+ self.db.orm.create(*models, skip=skip)
2545
+
2546
+
2547
+ def drop_orm_table(
2548
+ self,
2549
+ *models: Type[DatabaseORMModel] | DatabaseORMModel,
2550
+ skip: bool = False
2551
+ ) -> None:
2552
+ """
2553
+ Delete tables by model.
2554
+
2555
+ Parameters
2556
+ ----------
2557
+ models : ORM model instances.
2558
+ skip : Skip not exist table.
2559
+ """
2560
+
2561
+ # Drop.
2562
+ self.db.orm.drop(*models, skip=skip)
2563
+
2564
+
2565
+ def build(
2566
+ self,
2567
+ databases: list[dict] | None = None,
2568
+ tables: list[dict | Type[DatabaseORMModel] | DatabaseORMModel] | None = None,
2569
+ views: list[dict] | None = None,
2570
+ views_stats: list[dict] | None = None,
2571
+ ask: bool = True,
2572
+ skip: bool = False
2573
+ ) -> None:
2574
+ """
2575
+ Build databases or tables.
2576
+
2577
+ Parameters
2578
+ ----------
2579
+ databases : Database build parameters, equivalent to the parameters of method `self.create_database`.
2580
+ tables : Tables build parameters or model, equivalent to the parameters of method `self.create_table` or `self.create_orm_table`.
2581
+ views : Views build parameters, equivalent to the parameters of method `self.create_view`.
2582
+ views_stats : Views stats build parameters, equivalent to the parameters of method `self.create_view_stats`.
2583
+ ask : Whether ask confirm execute.
2584
+ skip : Whether skip existing table.
2585
+ """
2586
+
2587
+ # Set parameter.
2588
+ databases = databases or []
2589
+ tables = tables or []
2590
+ views = views or []
2591
+ views_stats = views_stats or []
2592
+ refresh_schema = False
2593
+
2594
+ # Database.
2595
+ for params in databases:
2596
+ database = params['name']
2597
+
2598
+ ## Exist.
2599
+ if (
2600
+ skip
2601
+ and self.db.schema.exist(database)
2602
+ ):
2603
+ continue
2604
+
2605
+ ## SQL.
2606
+ sql = self.get_sql_create_database(**params)
2607
+
2608
+ ## Confirm.
2609
+ if ask:
2610
+ self.input_confirm_build(sql)
2611
+
2612
+ ## Execute.
2613
+ self.db.execute(sql)
2614
+
2615
+ ## Report.
2616
+ text = f"Database '{database}' build completed."
2617
+ print(text)
2618
+
2619
+ # Table.
2620
+ for params in tables:
2621
+
2622
+ ## ORM.
2623
+ if (
2624
+ is_instance(params)
2625
+ and isinstance(params, DatabaseORMModel)
2626
+ or issubclass(params, DatabaseORMModel)
2627
+ ):
2628
+ database = self.db.database
2629
+ table = params._table().name
2630
+
2631
+ ## Exist.
2632
+ if (
2633
+ skip
2634
+ and self.db.schema.exist(self.db.database, table)
2635
+ ):
2636
+ continue
2637
+
2638
+ ## Confirm.
2639
+ if ask:
2640
+ text = self.get_orm_table_text(params)
2641
+ self.input_confirm_build(text)
2642
+
2643
+ ## Execute.
2644
+ self.create_orm_table(params)
2645
+
2646
+ ## Parameter.
2647
+ else:
2648
+ path: str | tuple[str, str] = params['path']
2649
+ if type(path) == str:
2650
+ database, table = self.db.database, path
2651
+ else:
2652
+ database, table = path
2653
+
2654
+ ### Exist.
2655
+ if (
2656
+ skip
2657
+ and self.db.schema.exist(database, table)
2658
+ ):
2659
+ continue
2660
+
2661
+ ### SQL.
2662
+ sql = self.get_sql_create_table(**params)
2663
+
2664
+ ### Confirm.
2665
+ if ask:
2666
+ self.input_confirm_build(sql)
2667
+
2668
+ ### Execute.
2669
+ self.db.execute(sql)
2670
+
2671
+ ## Report.
2672
+ text = f"Table '{table}' of database '{database}' build completed."
2673
+ print(text)
2674
+ refresh_schema = True
2675
+
2676
+ # Refresh schema.
2677
+ if refresh_schema:
2678
+ self.db.schema()
2679
+
1200
2680
  # View.
1201
2681
  for params in views:
1202
2682
  path = params['path']
@@ -1324,7 +2804,7 @@ class DatabaseBuildAsync(DatabaseBuildSuper['rdb.DatabaseAsync']):
1324
2804
  skip : Whether skip existing table.
1325
2805
  """
1326
2806
 
1327
- # Handle parameter.
2807
+ # Set parameter.
1328
2808
  databases = databases or []
1329
2809
  tables = tables or []
1330
2810
  tables_orm = tables_orm or []