diff --git a/aerich/cli.py b/aerich/cli.py index d1fff3e..6880acb 100644 --- a/aerich/cli.py +++ b/aerich/cli.py @@ -4,6 +4,7 @@ import sys from configparser import ConfigParser from functools import wraps from pathlib import Path +from typing import List import click from click import Context, UsageError @@ -12,6 +13,7 @@ from tortoise.exceptions import OperationalError from tortoise.transactions import in_transaction from tortoise.utils import get_schema_sql +from aerich.inspectdb import InspectDb from aerich.migrate import Migrate from aerich.utils import ( get_app_connection, @@ -288,6 +290,25 @@ async def init_db(ctx: Context, safe): click.secho(f'Success generate schema for app "{app}"', fg=Color.green) +@cli.command(help="Introspects the database tables to standard output as TortoiseORM model.") +@click.option( + "-t", + "--table", + help="Which tables to inspect.", + multiple=True, + required=False, +) +@click.pass_context +@coro +async def inspectdb(ctx: Context, table: List[str]): + config = ctx.obj["config"] + app = ctx.obj["app"] + connection = get_app_connection(config, app) + + inspect = InspectDb(connection, table) + await inspect.inspect() + + def main(): sys.path.insert(0, ".") cli() diff --git a/aerich/inspectdb.py b/aerich/inspectdb.py index e69de29..b301a67 100644 --- a/aerich/inspectdb.py +++ b/aerich/inspectdb.py @@ -0,0 +1,32 @@ +from typing import List, Optional + +from ddlparse import DdlParse +from tortoise import BaseDBAsyncClient +from tortoise.backends.mysql.client import MySQLSchemaGenerator + + +class InspectDb: + def __init__(self, conn: BaseDBAsyncClient, tables: Optional[List[str]] = None): + self.conn = conn + self.tables = tables + self.DIALECT = conn.schema_generator.DIALECT + + async def show_create_tables(self): + if self.DIALECT == MySQLSchemaGenerator.DIALECT: + if not self.tables: + sql_tables = f"SELECT table_name FROM information_schema.tables WHERE table_schema = '{self.conn.database}';" + ret = await self.conn.execute_query(sql_tables) + self.tables = map(lambda x: x[0], ret) + for table in self.tables: + sql_show_create_table = f"SHOW CREATE TABLE {table}" + ret = await self.conn.execute_query(sql_show_create_table) + yield ret[1][0]["Create Table"] + else: + raise NotImplementedError("Currently only support MySQL") + + async def inspect(self): + ddl_list = self.show_create_tables() + async for ddl in ddl_list: + parser = DdlParse(ddl, DdlParse.DATABASE.mysql) + table = parser.parse() + print(table) diff --git a/conftest.py b/conftest.py index 403ced8..5057664 100644 --- a/conftest.py +++ b/conftest.py @@ -36,7 +36,7 @@ def reset_migrate(): Migrate._downgrade_m2m = [] -@pytest.yield_fixture(scope="session") +@pytest.fixture(scope="session") def event_loop(): policy = asyncio.get_event_loop_policy() res = policy.new_event_loop() diff --git a/poetry.lock b/poetry.lock index 6d1635b..4ecb364 100644 --- a/poetry.lock +++ b/poetry.lock @@ -127,6 +127,17 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "ddlparse" +version = "1.9.0" +description = "DDL parase and Convert to BigQuery JSON schema" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pyparsing = "*" + [[package]] name = "execnet" version = "1.7.1" @@ -331,7 +342,7 @@ rsa = ["cryptography"] name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "dev" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" @@ -536,7 +547,7 @@ dbdrivers = ["aiomysql", "asyncpg"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "ff0825922451c3ebd311666956adc8987677dc66fe5321565213cd3568ebd9ae" +content-hash = "9adf7beba99d615c71a9148391386c9016cbafc7c11c5fc3ad81c8ec61026236" [metadata.files] aiomysql = [ @@ -605,6 +616,10 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +ddlparse = [ + {file = "ddlparse-1.9.0-py3-none-any.whl", hash = "sha256:a7962615a9325be7d0f182cbe34011e6283996473fb98c784c6f675b9783bc18"}, + {file = "ddlparse-1.9.0.tar.gz", hash = "sha256:cdffcf2f692f304a23c8e903b00afd7e83a920b79a2ff4e2f25c875b369d4f58"}, +] execnet = [ {file = "execnet-1.7.1-py2.py3-none-any.whl", hash = "sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"}, {file = "execnet-1.7.1.tar.gz", hash = "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50"}, diff --git a/pyproject.toml b/pyproject.toml index e3b4196..95ea4a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ click = "*" pydantic = "*" aiomysql = {version = "*", optional = true} asyncpg = {version = "*", optional = true} +ddlparse = "*" [tool.poetry.dev-dependencies] flake8 = "*"