diff --git a/Makefile b/Makefile index b107c31..c189921 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -checkfiles = aerich/ tests/ +checkfiles = aerich/ tests/ conftest.py black_opts = -l 100 -t py38 py_warn = PYTHONDEVMODE=1 MYSQL_HOST ?= "127.0.0.1" diff --git a/README.rst b/README.rst index cb5f536..9093327 100644 --- a/README.rst +++ b/README.rst @@ -104,6 +104,10 @@ Init db Success create app migrate location ./migrations/models Success generate schema for app "models" +.. note:: + + If your Tortoise-ORM app is not default ``models``, you must specify ``--app`` like ``aerich --app other_models init-db``. + Update models and make migrate ------------------------------ diff --git a/aerich/cli.py b/aerich/cli.py index 30e4d23..ae2bf86 100644 --- a/aerich/cli.py +++ b/aerich/cli.py @@ -12,6 +12,7 @@ from aerich.migrate import Migrate from aerich.utils import get_app_connection, get_app_connection_name, get_tortoise_config + from . import __version__ from .models import Aerich @@ -158,7 +159,7 @@ def history(ctx): ) @click.pass_context async def init( - ctx: Context, tortoise_orm, location, + ctx: Context, tortoise_orm, location, ): config_file = ctx.obj["config_file"] name = ctx.obj["name"] diff --git a/aerich/migrate.py b/aerich/migrate.py index d859e02..862e8a2 100644 --- a/aerich/migrate.py +++ b/aerich/migrate.py @@ -111,10 +111,9 @@ async def migrate(cls, name) -> str: apps = Tortoise.apps diff_models = apps.get(cls.diff_app) app_models = apps.get(cls.app) - app_models.pop(cls._aerich, None) - cls._diff_models(diff_models, app_models) - cls._diff_models(app_models, diff_models, False) + cls.diff_models(diff_models, app_models) + cls.diff_models(app_models, diff_models, False) cls._merge_operators() @@ -198,7 +197,7 @@ def write_old_models(cls, config: dict, app: str, location: str): cls.cp_models(app, old_model_files, os.path.join(location, app, cls.get_old_model_file())) @classmethod - def _diff_models( + def diff_models( cls, old_models: Dict[str, Type[Model]], new_models: Dict[str, Type[Model]], upgrade=True ): """ @@ -208,6 +207,9 @@ def _diff_models( :param upgrade: :return: """ + old_models.pop(cls._aerich, None) + new_models.pop(cls._aerich, None) + for new_model_str, new_model in new_models.items(): if new_model_str not in old_models.keys(): cls._add_operator(cls.add_model(new_model), upgrade) diff --git a/conftest.py b/conftest.py index 668b162..4c2fa5e 100644 --- a/conftest.py +++ b/conftest.py @@ -1,11 +1,61 @@ +import asyncio import os import pytest -from tortoise.contrib.test import finalizer, initializer +from tortoise import Tortoise, expand_db_url, generate_schema_for_client +from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator +from tortoise.backends.mysql.schema_generator import MySQLSchemaGenerator +from tortoise.backends.sqlite.schema_generator import SqliteSchemaGenerator +from aerich.ddl.mysql import MysqlDDL +from aerich.ddl.postgres import PostgresDDL +from aerich.ddl.sqlite import SqliteDDL +from aerich.migrate import Migrate -@pytest.fixture(scope="module", autouse=True) -def initialize_tests(request): - db_url = os.getenv("TEST_DB", "sqlite://:memory:") - initializer(["tests.models"], db_url=db_url) - request.addfinalizer(finalizer) +db_url = os.getenv("TEST_DB", "sqlite://:memory:") +tortoise_orm = { + "connections": {"default": expand_db_url(db_url, True)}, + "apps": { + "models": { + "models": ["tests.models", "aerich.models"], + "default_connection": "default", + }, + }, +} + + +@pytest.fixture(scope="function", autouse=True) +def reset_migrate(): + Migrate.upgrade_operators = [] + Migrate.downgrade_operators = [] + Migrate._upgrade_fk_m2m_index_operators = [] + Migrate._downgrade_fk_m2m_index_operators = [] + Migrate._upgrade_m2m = [] + Migrate._downgrade_m2m = [] + + +@pytest.fixture(scope="session") +def loop(): + loop = asyncio.get_event_loop() + return loop + + +@pytest.fixture(scope="session", autouse=True) +def initialize_tests(loop, request): + tortoise_orm['connections']['diff_models'] = "sqlite://:memory:" + tortoise_orm['apps']['diff_models'] = {"models": ["tests.diff_models"], "default_connection": "diff_models"} + + loop.run_until_complete(Tortoise.init(config=tortoise_orm, _create_db=True)) + loop.run_until_complete( + generate_schema_for_client(Tortoise.get_connection("default"), safe=True) + ) + + client = Tortoise.get_connection("default") + if client.schema_generator is MySQLSchemaGenerator: + Migrate.ddl = MysqlDDL(client) + elif client.schema_generator is SqliteSchemaGenerator: + Migrate.ddl = SqliteDDL(client) + elif client.schema_generator is AsyncpgSchemaGenerator: + Migrate.ddl = PostgresDDL(client) + + request.addfinalizer(lambda: loop.run_until_complete(Tortoise._drop_databases())) diff --git a/poetry.lock b/poetry.lock index 06b86f1..6e024d8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -90,14 +90,6 @@ dev = ["Cython (0.29.14)", "pytest (>=3.6.0)", "Sphinx (>=1.7.3,<1.8.0)", "sphin docs = ["Sphinx (>=1.7.3,<1.8.0)", "sphinxcontrib-asyncio (>=0.2.0,<0.3.0)", "sphinx-rtd-theme (>=0.2.4,<0.3.0)"] test = ["pycodestyle (>=2.5.0,<2.6.0)", "flake8 (>=3.7.9,<3.8.0)", "uvloop (>=0.14.0,<0.15.0)"] -[[package]] -category = "dev" -description = "Enhance the standard unittest package with features for testing asyncio libraries" -name = "asynctest" -optional = false -python-versions = ">=3.5" -version = "0.13.0" - [[package]] category = "dev" description = "Atomic file writes." @@ -217,7 +209,7 @@ description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "3.8.1" +version = "3.8.2" [package.dependencies] mccabe = ">=0.6.0,<0.7.0" @@ -412,6 +404,20 @@ wcwidth = "*" checkqa-mypy = ["mypy (v0.761)"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +category = "dev" +description = "Pytest support for asyncio." +name = "pytest-asyncio" +optional = false +python-versions = ">= 3.5" +version = "0.12.0" + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +testing = ["async_generator (>=1.3)", "coverage", "hypothesis (>=5.7.1)"] + [[package]] category = "dev" description = "run tests in isolated forked subprocesses" @@ -454,7 +460,7 @@ description = "Python 2 and 3 compatibility utilities" name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.14.0" +version = "1.15.0" [[package]] category = "main" @@ -489,7 +495,7 @@ description = "Easy async ORM for python, built with relations in mind" name = "tortoise-orm" optional = false python-versions = "*" -version = "0.16.11" +version = "0.16.12" [package.dependencies] aiosqlite = ">=0.11.0" @@ -498,10 +504,6 @@ iso8601 = ">=0.1.12" pypika = ">=0.36.5" typing-extensions = ">=3.7" -[package.source] -reference = "1f67b7a0ca1384365d6ff89d9e245e733166d1a6" -type = "git" -url = "https://github.com/long2ice/tortoise-orm.git" [[package]] category = "dev" description = "a fork of Python 2 and 3 ast modules with type comment support" @@ -527,7 +529,7 @@ python-versions = "*" version = "0.1.9" [metadata] -content-hash = "58a032bbb47859e87d2bce036af24149060cc531ff9220a14f6cd48db6252f39" +content-hash = "35274e9622d359af475f573760ba687b31756b1b1de70bc4d75dab5ddbc5a93d" python-versions = "^3.8" [metadata.files] @@ -581,10 +583,6 @@ asyncpg = [ {file = "asyncpg-0.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:2af6a5a705accd36e13292ea43d08c20b15e52d684beb522cb3a7d3c9c8f3f48"}, {file = "asyncpg-0.20.1.tar.gz", hash = "sha256:394bf19bdddbba07a38cd6fb526ebf66e120444d6b3097332b78efd5b26495b0"}, ] -asynctest = [ - {file = "asynctest-0.13.0-py3-none-any.whl", hash = "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676"}, - {file = "asynctest-0.13.0.tar.gz", hash = "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac"}, -] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -664,8 +662,8 @@ execnet = [ {file = "execnet-1.7.1.tar.gz", hash = "sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50"}, ] flake8 = [ - {file = "flake8-3.8.1-py2.py3-none-any.whl", hash = "sha256:6c1193b0c3f853ef763969238f6c81e9e63ace9d024518edc020d5f1d6d93195"}, - {file = "flake8-3.8.1.tar.gz", hash = "sha256:ea6623797bf9a52f4c9577d780da0bb17d65f870213f7b5bcc9fca82540c31d5"}, + {file = "flake8-3.8.2-py2.py3-none-any.whl", hash = "sha256:ccaa799ef9893cebe69fdfefed76865aeaefbb94cb8545617b2298786a4de9a5"}, + {file = "flake8-3.8.2.tar.gz", hash = "sha256:c69ac1668e434d37a2d2880b3ca9aafd54b3a10a3ac1ab101d22f29e29cf8634"}, ] iso8601 = [ {file = "iso8601-0.1.12-py2.py3-none-any.whl", hash = "sha256:210e0134677cc0d02f6028087fee1df1e1d76d372ee1db0bf30bf66c5c1c89a3"}, @@ -766,6 +764,9 @@ pytest = [ {file = "pytest-5.4.2-py3-none-any.whl", hash = "sha256:95c710d0a72d91c13fae35dce195633c929c3792f54125919847fdcdf7caa0d3"}, {file = "pytest-5.4.2.tar.gz", hash = "sha256:eb2b5e935f6a019317e455b6da83dd8650ac9ffd2ee73a7b657a30873d67a698"}, ] +pytest-asyncio = [ + {file = "pytest-asyncio-0.12.0.tar.gz", hash = "sha256:475bd2f3dc0bc11d2463656b3cbaafdbec5a47b47508ea0b329ee693040eebd2"}, +] pytest-forked = [ {file = "pytest-forked-1.1.3.tar.gz", hash = "sha256:1805699ed9c9e60cb7a8179b8d4fa2b8898098e82d229b0825d8095f0f261100"}, {file = "pytest_forked-1.1.3-py2.py3-none-any.whl", hash = "sha256:1ae25dba8ee2e56fb47311c9638f9e58552691da87e82d25b0ce0e4bf52b7d87"}, @@ -798,8 +799,8 @@ regex = [ {file = "regex-2020.5.14.tar.gz", hash = "sha256:ce450ffbfec93821ab1fea94779a8440e10cf63819be6e176eb1973a6017aff5"}, ] six = [ - {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, - {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] sniffio = [ {file = "sniffio-1.1.0-py3-none-any.whl", hash = "sha256:20ed6d5b46f8ae136d00b9dcb807615d83ed82ceea6b2058cecb696765246da5"}, @@ -813,7 +814,9 @@ toml = [ {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, ] -tortoise-orm = [] +tortoise-orm = [ + {file = "tortoise-orm-0.16.12.tar.gz", hash = "sha256:170e4bbfe1c98223ad1fba33d7fded7923e4bb49c9d74c78bd173a0ebc861658"}, +] typed-ast = [ {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, diff --git a/pyproject.toml b/pyproject.toml index 5ed2468..b6e2fd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,13 +6,12 @@ authors = ["long2ice "] [tool.poetry.dependencies] python = "^3.8" -tortoise-orm = {git = "https://github.com/tortoise-orm/tortoise-orm.git", branch = "develop"} +tortoise-orm = "*" asyncclick = "*" pydantic = "*" [tool.poetry.dev-dependencies] taskipy = "*" -asynctest = "*" flake8 = "*" isort = "*" black = "^19.10b0" @@ -21,6 +20,7 @@ aiomysql = "*" asyncpg = "*" pytest-xdist = "*" mypy = "*" +pytest-asyncio = "*" [tool.taskipy.tasks] export = "poetry export -f requirements.txt --without-hashes > requirements.txt" diff --git a/requirements-dev.txt b/requirements-dev.txt index 4633e09..a2baa92 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,7 +6,6 @@ appdirs==1.4.4 async-generator==1.10 asyncclick==7.0.9 asyncpg==0.20.1 -asynctest==0.13.0 atomicwrites==1.4.0; sys_platform == "win32" attrs==19.3.0 black==19.10b0 @@ -16,7 +15,7 @@ click==7.1.2 colorama==0.4.3; sys_platform == "win32" cryptography==2.9.2 execnet==1.7.1 -flake8==3.8.1 +flake8==3.8.2 iso8601==0.1.12; sys_platform == "win32" or implementation_name != "cpython" isort==4.3.21 mccabe==0.6.1 @@ -35,14 +34,15 @@ pymysql==0.9.2 pyparsing==2.4.7 pypika==0.37.6 pytest==5.4.2 +pytest-asyncio==0.12.0 pytest-forked==1.1.3 pytest-xdist==1.32.0 regex==2020.5.14 -six==1.14.0 +six==1.15.0 sniffio==1.1.0 taskipy==1.2.1 toml==0.10.1 --e git+https://github.com/long2ice/tortoise-orm.git@1f67b7a0ca1384365d6ff89d9e245e733166d1a6#egg=tortoise-orm +tortoise-orm==0.16.12 typed-ast==1.4.1 typing-extensions==3.7.4.2 wcwidth==0.1.9 diff --git a/requirements.txt b/requirements.txt index 623ebe3..863509f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,5 @@ iso8601==0.1.12; sys_platform == "win32" or implementation_name != "cpython" pydantic==1.5.1 pypika==0.37.6 sniffio==1.1.0 +tortoise-orm==0.16.12 typing-extensions==3.7.4.2 diff --git a/tests/__init__.py b/tests/__init__.py index 4abc103..e69de29 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +0,0 @@ -TORTOISE_ORM = { - "connections": {"default": "mysql://root:123456@127.0.0.1:3306/test"}, - "apps": { - "models": {"models": ["tests.models", "aerich.models"], "default_connection": "default"} - }, -} diff --git a/tests/diff_models.py b/tests/diff_models.py new file mode 100644 index 0000000..7f5af93 --- /dev/null +++ b/tests/diff_models.py @@ -0,0 +1,56 @@ +import datetime +from enum import IntEnum + +from tortoise import Model, fields + + +class ProductType(IntEnum): + article = 1 + page = 2 + + +class PermissionAction(IntEnum): + create = 1 + delete = 2 + update = 3 + read = 4 + + +class Status(IntEnum): + on = 1 + off = 0 + + +class User(Model): + username = fields.CharField(max_length=20,) + password = fields.CharField(max_length=200) + last_login = fields.DatetimeField(description="Last Login", default=datetime.datetime.now) + is_active = fields.BooleanField(default=True, description="Is Active") + is_superuser = fields.BooleanField(default=False, description="Is SuperUser") + avatar = fields.CharField(max_length=200, default="") + intro = fields.TextField(default="") + + +class Category(Model): + slug = fields.CharField(max_length=200) + user = fields.ForeignKeyField("diff_models.User", description="User") + created_at = fields.DatetimeField(auto_now_add=True) + + +class Product(Model): + categories = fields.ManyToManyField("diff_models.Category") + name = fields.CharField(max_length=50) + view_num = fields.IntField(description="View Num") + sort = fields.IntField() + is_reviewed = fields.BooleanField(description="Is Reviewed") + type = fields.IntEnumField(ProductType, description="Product Type") + image = fields.CharField(max_length=200) + body = fields.TextField() + created_at = fields.DatetimeField(auto_now_add=True) + + +class Config(Model): + label = fields.CharField(max_length=200) + key = fields.CharField(max_length=20) + value = fields.JSONField() + status: Status = fields.IntEnumField(Status, default=Status.on) diff --git a/tests/test_ddl.py b/tests/test_ddl.py index 0ed2897..5ab4040 100644 --- a/tests/test_ddl.py +++ b/tests/test_ddl.py @@ -1,114 +1,101 @@ -from tortoise import Tortoise -from tortoise.backends.asyncpg.schema_generator import AsyncpgSchemaGenerator -from tortoise.backends.mysql.schema_generator import MySQLSchemaGenerator -from tortoise.backends.sqlite.schema_generator import SqliteSchemaGenerator -from tortoise.contrib import test - from aerich.ddl.mysql import MysqlDDL from aerich.ddl.postgres import PostgresDDL from aerich.ddl.sqlite import SqliteDDL +from aerich.migrate import Migrate from tests.models import Category -class TestDDL(test.TruncationTestCase): - maxDiff = None - - def setUp(self) -> None: - client = Tortoise.get_connection("models") - if client.schema_generator is MySQLSchemaGenerator: - self.ddl = MysqlDDL(client) - elif client.schema_generator is SqliteSchemaGenerator: - self.ddl = SqliteDDL(client) - elif client.schema_generator is AsyncpgSchemaGenerator: - self.ddl = PostgresDDL(client) - - def test_create_table(self): - ret = self.ddl.create_table(Category) - if isinstance(self.ddl, MysqlDDL): - self.assertEqual( - ret, - """CREATE TABLE IF NOT EXISTS `category` ( +def test_create_table(): + ret = Migrate.ddl.create_table(Category) + if isinstance(Migrate.ddl, MysqlDDL): + assert ( + ret + == """CREATE TABLE IF NOT EXISTS `category` ( `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT, `slug` VARCHAR(200) NOT NULL, `name` VARCHAR(200) NOT NULL, `created_at` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), `user_id` INT NOT NULL COMMENT 'User', CONSTRAINT `fk_category_user_e2e3874c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE -) CHARACTER SET utf8mb4;""", - ) - elif isinstance(self.ddl, SqliteDDL): - self.assertEqual( - ret, - """CREATE TABLE IF NOT EXISTS "category" ( +) CHARACTER SET utf8mb4;""" + ) + + elif isinstance(Migrate.ddl, SqliteDDL): + assert ( + ret + == """CREATE TABLE IF NOT EXISTS "category" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "slug" VARCHAR(200) NOT NULL, "name" VARCHAR(200) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "user_id" INT NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE /* User */ -);""", - ) - elif isinstance(self.ddl, PostgresDDL): - self.assertEqual( - ret, - """CREATE TABLE IF NOT EXISTS "category" ( +);""" + ) + + elif isinstance(Migrate.ddl, PostgresDDL): + assert ( + ret + == """CREATE TABLE IF NOT EXISTS "category" ( "id" SERIAL NOT NULL PRIMARY KEY, "slug" VARCHAR(200) NOT NULL, "name" VARCHAR(200) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "user_id" INT NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE ); -COMMENT ON COLUMN "category"."user_id" IS 'User';""", - ) - - def test_drop_table(self): - ret = self.ddl.drop_table(Category) - self.assertEqual(ret, "DROP TABLE IF EXISTS category") - - def test_add_column(self): - ret = self.ddl.add_column(Category, Category._meta.fields_map.get("name")) - if isinstance(self.ddl, MysqlDDL): - self.assertEqual(ret, "ALTER TABLE category ADD `name` VARCHAR(200) NOT NULL") - elif isinstance(self.ddl, PostgresDDL): - self.assertEqual(ret, 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL') - elif isinstance(self.ddl, SqliteDDL): - self.assertEqual(ret, 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL') - - def test_drop_column(self): - ret = self.ddl.drop_column(Category, "name") - self.assertEqual(ret, "ALTER TABLE category DROP COLUMN name") - self.assertEqual(ret, "ALTER TABLE category DROP COLUMN name") - - def test_add_index(self): - index = self.ddl.add_index(Category, ["name"]) - index_u = self.ddl.add_index(Category, ["name"], True) - if isinstance(self.ddl, MysqlDDL): - self.assertEqual( - index, "ALTER TABLE category ADD INDEX idx_category_name_8b0cb9 (`name`)" - ) - self.assertEqual( - index_u, "ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 (`name`)" - ) - elif isinstance(self.ddl, SqliteDDL): - self.assertEqual( - index_u, 'ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 ("name")' - ) - self.assertEqual( - index_u, 'ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 ("name")' - ) - - def test_drop_index(self): - ret = self.ddl.drop_index(Category, ["name"]) - self.assertEqual(ret, "ALTER TABLE category DROP INDEX idx_category_name_8b0cb9") - ret = self.ddl.drop_index(Category, ["name"], True) - self.assertEqual(ret, "ALTER TABLE category DROP INDEX uid_category_name_8b0cb9") - - def test_add_fk(self): - ret = self.ddl.add_fk(Category, Category._meta.fields_map.get("user")) - self.assertEqual( - ret, - "ALTER TABLE category ADD CONSTRAINT `fk_category_user_e2e3874c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE", +COMMENT ON COLUMN "category"."user_id" IS 'User';""" ) - def test_drop_fk(self): - ret = self.ddl.drop_fk(Category, Category._meta.fields_map.get("user")) - self.assertEqual(ret, "ALTER TABLE category DROP FOREIGN KEY fk_category_user_e2e3874c") + +def test_drop_table(): + ret = Migrate.ddl.drop_table(Category) + assert ret == "DROP TABLE IF EXISTS category" + + +def test_add_column(): + ret = Migrate.ddl.add_column(Category, Category._meta.fields_map.get("name")) + if isinstance(Migrate.ddl, MysqlDDL): + assert ret == "ALTER TABLE category ADD `name` VARCHAR(200) NOT NULL" + elif isinstance(Migrate.ddl, PostgresDDL): + assert ret == 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL' + elif isinstance(Migrate.ddl, SqliteDDL): + assert ret == 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL' + + +def test_drop_column(): + ret = Migrate.ddl.drop_column(Category, "name") + assert ret == "ALTER TABLE category DROP COLUMN name" + assert ret == "ALTER TABLE category DROP COLUMN name" + + +def test_add_index(): + index = Migrate.ddl.add_index(Category, ["name"]) + index_u = Migrate.ddl.add_index(Category, ["name"], True) + if isinstance(Migrate.ddl, MysqlDDL): + assert index == "ALTER TABLE category ADD INDEX idx_category_name_8b0cb9 (`name`)" + + assert index_u == "ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 (`name`)" + + elif isinstance(Migrate.ddl, SqliteDDL): + assert index_u == 'ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 ("name")' + + assert index_u == 'ALTER TABLE category ADD UNIQUE INDEX uid_category_name_8b0cb9 ("name")' + + +def test_drop_index(): + ret = Migrate.ddl.drop_index(Category, ["name"]) + assert ret == "ALTER TABLE category DROP INDEX idx_category_name_8b0cb9" + ret = Migrate.ddl.drop_index(Category, ["name"], True) + assert ret == "ALTER TABLE category DROP INDEX uid_category_name_8b0cb9" + + +def test_add_fk(): + ret = Migrate.ddl.add_fk(Category, Category._meta.fields_map.get("user")) + assert ( + ret + == "ALTER TABLE category ADD CONSTRAINT `fk_category_user_e2e3874c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE" + ) + + +def test_drop_fk(): + ret = Migrate.ddl.drop_fk(Category, Category._meta.fields_map.get("user")) + assert ret == "ALTER TABLE category DROP FOREIGN KEY fk_category_user_e2e3874c" diff --git a/tests/test_migrate.py b/tests/test_migrate.py new file mode 100644 index 0000000..55baaea --- /dev/null +++ b/tests/test_migrate.py @@ -0,0 +1,41 @@ +from tortoise import Tortoise + +from aerich.ddl.mysql import MysqlDDL +from aerich.ddl.postgres import PostgresDDL +from aerich.ddl.sqlite import SqliteDDL +from aerich.migrate import Migrate + + +def test_migrate(): + apps = Tortoise.apps + models = apps.get("models") + diff_models = apps.get("diff_models") + Migrate.diff_models(diff_models, models) + Migrate.diff_models(models, diff_models, False) + if isinstance(Migrate.ddl, MysqlDDL): + assert Migrate.upgrade_operators == [ + "ALTER TABLE category ADD `name` VARCHAR(200) NOT NULL", + "ALTER TABLE user ADD UNIQUE INDEX uid_user_usernam_9987ab (`username`)", + ] + assert Migrate.downgrade_operators == [ + "ALTER TABLE category DROP COLUMN name", + "ALTER TABLE user DROP INDEX uid_user_usernam_9987ab", + ] + elif isinstance(Migrate.ddl, SqliteDDL): + assert Migrate.upgrade_operators == [ + 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL', + 'ALTER TABLE user ADD UNIQUE INDEX uid_user_usernam_9987ab ("username")', + ] + assert Migrate.downgrade_operators == [ + "ALTER TABLE category DROP COLUMN name", + "ALTER TABLE user DROP INDEX uid_user_usernam_9987ab", + ] + elif isinstance(Migrate.ddl, PostgresDDL): + assert Migrate.upgrade_operators == [ + 'ALTER TABLE category ADD "name" VARCHAR(200) NOT NULL', + 'ALTER TABLE user ADD UNIQUE INDEX uid_user_usernam_9987ab ("username")', + ] + assert Migrate.downgrade_operators == [ + "ALTER TABLE category DROP COLUMN name", + "ALTER TABLE user DROP INDEX uid_user_usernam_9987ab", + ]