Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9889d9492b | ||
|
823368aea8 | ||
|
6b1ad46cf1 | ||
|
ce8c0b1f06 | ||
|
43922d3734 | ||
|
48c5318737 |
@@ -2,6 +2,11 @@
|
||||
|
||||
## 0.2
|
||||
|
||||
### 0.2.5
|
||||
|
||||
- Fix windows support. (#46)
|
||||
- Support `db_constraint` in fk, m2m should manual define table with fk. (#52)
|
||||
|
||||
### 0.2.4
|
||||
|
||||
- Raise error with SQLite unsupported features.
|
||||
|
2
Makefile
2
Makefile
@@ -40,7 +40,7 @@ test_sqlite:
|
||||
$(py_warn) TEST_DB=sqlite://:memory: py.test
|
||||
|
||||
test_mysql:
|
||||
$(py_warn) TEST_DB="mysql://root:$(MYSQL_PASS)@$(MYSQL_HOST):$(MYSQL_PORT)/test_\{\}" pytest -v -s
|
||||
$(py_warn) TEST_DB="mysql://root:$(MYSQL_PASS)@$(MYSQL_HOST):$(MYSQL_PORT)/test_\{\}" pytest -vv -s
|
||||
|
||||
test_postgres:
|
||||
$(py_warn) TEST_DB="postgres://postgres:$(POSTGRES_PASS)@$(POSTGRES_HOST):$(POSTGRES_PORT)/test_\{\}" pytest
|
||||
|
@@ -113,6 +113,8 @@ Format of migrate filename is
|
||||
|
||||
And if `aerich` guess you are renaming a column, it will ask `Rename {old_column} to {new_column} [True]`, you can choice `True` to rename column without column drop, or choice `False` to drop column then create.
|
||||
|
||||
If you use `MySQL`, only MySQL8.0+ support `rename..to` syntax.
|
||||
|
||||
### Upgrade to latest version
|
||||
|
||||
```shell
|
||||
|
@@ -1 +1 @@
|
||||
__version__ = "0.2.4"
|
||||
__version__ = "0.2.5"
|
||||
|
@@ -1,10 +1,12 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from configparser import ConfigParser
|
||||
from functools import wraps
|
||||
|
||||
import asyncclick as click
|
||||
from asyncclick import Context, UsageError
|
||||
import click
|
||||
from click import Context, UsageError
|
||||
from tortoise import Tortoise, generate_schema_for_client
|
||||
from tortoise.exceptions import OperationalError
|
||||
from tortoise.transactions import in_transaction
|
||||
@@ -20,6 +22,15 @@ from .models import Aerich
|
||||
parser = ConfigParser()
|
||||
|
||||
|
||||
def coro(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
loop = asyncio.get_event_loop()
|
||||
return loop.run_until_complete(f(*args, **kwargs))
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
||||
@click.version_option(__version__, "-V", "--version")
|
||||
@click.option(
|
||||
@@ -34,6 +45,7 @@ parser = ConfigParser()
|
||||
help="Name of section in .ini file to use for aerich config.",
|
||||
)
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def cli(ctx: Context, config, app, name):
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj["config_file"] = config
|
||||
@@ -63,6 +75,7 @@ async def cli(ctx: Context, config, app, name):
|
||||
@cli.command(help="Generate migrate changes file.")
|
||||
@click.option("--name", default="update", show_default=True, help="Migrate name.")
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def migrate(ctx: Context, name):
|
||||
config = ctx.obj["config"]
|
||||
location = ctx.obj["location"]
|
||||
@@ -76,6 +89,7 @@ async def migrate(ctx: Context, name):
|
||||
|
||||
@cli.command(help="Upgrade to latest version.")
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def upgrade(ctx: Context):
|
||||
config = ctx.obj["config"]
|
||||
app = ctx.obj["app"]
|
||||
@@ -102,6 +116,7 @@ async def upgrade(ctx: Context):
|
||||
|
||||
@cli.command(help="Downgrade to previous version.")
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def downgrade(ctx: Context):
|
||||
app = ctx.obj["app"]
|
||||
config = ctx.obj["config"]
|
||||
@@ -124,6 +139,7 @@ async def downgrade(ctx: Context):
|
||||
|
||||
@cli.command(help="Show current available heads in migrate location.")
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def heads(ctx: Context):
|
||||
app = ctx.obj["app"]
|
||||
versions = Migrate.get_all_version_files()
|
||||
@@ -138,6 +154,7 @@ async def heads(ctx: Context):
|
||||
|
||||
@cli.command(help="List all migrate items.")
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def history(ctx: Context):
|
||||
versions = Migrate.get_all_version_files()
|
||||
for version in versions:
|
||||
@@ -157,6 +174,7 @@ async def history(ctx: Context):
|
||||
"--location", default="./migrations", show_default=True, help="Migrate store location."
|
||||
)
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def init(
|
||||
ctx: Context, tortoise_orm, location,
|
||||
):
|
||||
@@ -188,6 +206,7 @@ async def init(
|
||||
show_default=True,
|
||||
)
|
||||
@click.pass_context
|
||||
@coro
|
||||
async def init_db(ctx: Context, safe):
|
||||
config = ctx.obj["config"]
|
||||
location = ctx.obj["location"]
|
||||
@@ -220,4 +239,4 @@ async def init_db(ctx: Context, safe):
|
||||
|
||||
def main():
|
||||
sys.path.insert(0, ".")
|
||||
cli(_anyio_backend="asyncio")
|
||||
cli()
|
||||
|
@@ -2,7 +2,7 @@ from typing import List, Type
|
||||
|
||||
from tortoise import BaseDBAsyncClient, ForeignKeyFieldInstance, ManyToManyFieldInstance, Model
|
||||
from tortoise.backends.base.schema_generator import BaseSchemaGenerator
|
||||
from tortoise.fields import Field, JSONField, TextField, UUIDField
|
||||
from tortoise.fields import CASCADE, Field, JSONField, TextField, UUIDField
|
||||
|
||||
|
||||
class BaseDDL:
|
||||
@@ -20,7 +20,7 @@ class BaseDDL:
|
||||
_DROP_INDEX_TEMPLATE = 'ALTER TABLE "{table_name}" DROP INDEX "{index_name}"'
|
||||
_ADD_FK_TEMPLATE = 'ALTER TABLE "{table_name}" ADD CONSTRAINT "{fk_name}" FOREIGN KEY ("{db_column}") REFERENCES "{table}" ("{field}") ON DELETE {on_delete}'
|
||||
_DROP_FK_TEMPLATE = 'ALTER TABLE "{table_name}" DROP FOREIGN KEY "{fk_name}"'
|
||||
_M2M_TABLE_TEMPLATE = 'CREATE TABLE "{table_name}" ("{backward_key}" {backward_type} NOT NULL REFERENCES "{backward_table}" ("{backward_field}") ON DELETE CASCADE,"{forward_key}" {forward_type} NOT NULL REFERENCES "{forward_table}" ("{forward_field}") ON DELETE CASCADE){extra}{comment};'
|
||||
_M2M_TABLE_TEMPLATE = 'CREATE TABLE "{table_name}" ("{backward_key}" {backward_type} NOT NULL REFERENCES "{backward_table}" ("{backward_field}") ON DELETE CASCADE,"{forward_key}" {forward_type} NOT NULL REFERENCES "{forward_table}" ("{forward_field}") ON DELETE {on_delete}){extra}{comment};'
|
||||
_MODIFY_COLUMN_TEMPLATE = 'ALTER TABLE "{table_name}" MODIFY COLUMN {column}'
|
||||
|
||||
def __init__(self, client: "BaseDBAsyncClient"):
|
||||
@@ -44,6 +44,7 @@ class BaseDDL:
|
||||
backward_type=model._meta.pk.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
||||
forward_key=field.forward_key,
|
||||
forward_type=field.related_model._meta.pk.get_for_dialect(self.DIALECT, "SQL_TYPE"),
|
||||
on_delete=CASCADE,
|
||||
extra=self.schema_generator._table_generate_extra(table=field.through),
|
||||
comment=self.schema_generator._table_comment_generator(
|
||||
table=field.through, comment=field.description
|
||||
|
@@ -132,7 +132,7 @@ class Migrate:
|
||||
return await cls._generate_diff_sql(name)
|
||||
|
||||
@classmethod
|
||||
def _add_operator(cls, operator: str, upgrade=True, fk=False):
|
||||
def _add_operator(cls, operator: str, upgrade=True, fk_m2m=False):
|
||||
"""
|
||||
add operator,differentiate fk because fk is order limit
|
||||
:param operator:
|
||||
@@ -141,12 +141,12 @@ class Migrate:
|
||||
:return:
|
||||
"""
|
||||
if upgrade:
|
||||
if fk:
|
||||
if fk_m2m:
|
||||
cls._upgrade_fk_m2m_index_operators.append(operator)
|
||||
else:
|
||||
cls.upgrade_operators.append(operator)
|
||||
else:
|
||||
if fk:
|
||||
if fk_m2m:
|
||||
cls._downgrade_fk_m2m_index_operators.append(operator)
|
||||
else:
|
||||
cls.downgrade_operators.append(operator)
|
||||
@@ -268,17 +268,17 @@ class Migrate:
|
||||
continue
|
||||
if new_key not in old_keys:
|
||||
new_field_dict = new_field.describe(serializable=True)
|
||||
new_field_dict.pop("name")
|
||||
new_field_dict.pop("db_column")
|
||||
new_field_dict.pop("name", None)
|
||||
new_field_dict.pop("db_column", None)
|
||||
for diff_key in old_keys - new_keys:
|
||||
old_field = old_fields_map.get(diff_key)
|
||||
old_field_dict = old_field.describe(serializable=True)
|
||||
old_field_dict.pop("name")
|
||||
old_field_dict.pop("db_column")
|
||||
old_field_dict.pop("name", None)
|
||||
old_field_dict.pop("db_column", None)
|
||||
if old_field_dict == new_field_dict:
|
||||
if upgrade:
|
||||
is_rename = click.prompt(
|
||||
f"Rename {diff_key} to {new_key}",
|
||||
f"Rename {diff_key} to {new_key}?",
|
||||
default=True,
|
||||
type=bool,
|
||||
show_choices=True,
|
||||
@@ -294,9 +294,7 @@ class Migrate:
|
||||
break
|
||||
else:
|
||||
cls._add_operator(
|
||||
cls._add_field(new_model, new_field),
|
||||
upgrade,
|
||||
isinstance(new_field, (ForeignKeyFieldInstance, ManyToManyFieldInstance)),
|
||||
cls._add_field(new_model, new_field), upgrade, cls._is_fk_m2m(new_field),
|
||||
)
|
||||
else:
|
||||
old_field = old_fields_map.get(new_key)
|
||||
@@ -344,6 +342,15 @@ class Migrate:
|
||||
upgrade,
|
||||
cls._is_fk_m2m(new_field),
|
||||
)
|
||||
if isinstance(new_field, ForeignKeyFieldInstance):
|
||||
if old_field.db_constraint and not new_field.db_constraint:
|
||||
cls._add_operator(
|
||||
cls._drop_fk(new_model, new_field), upgrade, True,
|
||||
)
|
||||
if new_field.db_constraint and not old_field.db_constraint:
|
||||
cls._add_operator(
|
||||
cls._add_fk(new_model, new_field), upgrade, True,
|
||||
)
|
||||
|
||||
for old_key in old_keys:
|
||||
field = old_fields_map.get(old_key)
|
||||
@@ -437,6 +444,10 @@ class Migrate:
|
||||
def _modify_field(cls, model: Type[Model], field: Field):
|
||||
return cls.ddl.modify_column(model, field)
|
||||
|
||||
@classmethod
|
||||
def _drop_fk(cls, model: Type[Model], field: ForeignKeyFieldInstance):
|
||||
return cls.ddl.drop_fk(model, field)
|
||||
|
||||
@classmethod
|
||||
def _remove_field(cls, model: Type[Model], field: Field):
|
||||
if isinstance(field, ForeignKeyFieldInstance):
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import importlib
|
||||
|
||||
from asyncclick import BadOptionUsage, Context
|
||||
from click import BadOptionUsage, Context
|
||||
from tortoise import BaseDBAsyncClient, Tortoise
|
||||
|
||||
|
||||
|
76
poetry.lock
generated
76
poetry.lock
generated
@@ -23,28 +23,6 @@ version = "0.15.0"
|
||||
[package.dependencies]
|
||||
typing_extensions = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||
name = "anyio"
|
||||
optional = false
|
||||
python-versions = ">=3.6.2"
|
||||
version = "2.0.0"
|
||||
|
||||
[package.dependencies]
|
||||
idna = ">=2.8"
|
||||
sniffio = ">=1.1"
|
||||
|
||||
[package.dependencies.typing-extensions]
|
||||
python = "<3.8"
|
||||
version = "*"
|
||||
|
||||
[package.extras]
|
||||
curio = ["curio (>=1.4)"]
|
||||
doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
|
||||
test = ["coverage (>=4.5)", "hypothesis (>=4.0)", "pytest (>=4.3)", "trustme", "uvloop"]
|
||||
trio = ["trio (>=0.16)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "apipkg: namespace control and lazy-import mechanism"
|
||||
@@ -61,21 +39,6 @@ optional = false
|
||||
python-versions = "*"
|
||||
version = "1.4.4"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A simple anyio-compatible fork of Click, for powerful command line utilities."
|
||||
name = "asyncclick"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "7.1.2.1"
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=2"
|
||||
|
||||
[package.extras]
|
||||
dev = ["coverage", "pytest-runner", "pytest-trio", "pytest (>=3)", "sphinx", "tox"]
|
||||
docs = ["sphinx"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "An asyncio PostgreSQL driver"
|
||||
@@ -159,7 +122,7 @@ version = "1.14.3"
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
category = "main"
|
||||
description = "Composable command line interface toolkit"
|
||||
name = "click"
|
||||
optional = false
|
||||
@@ -247,14 +210,6 @@ version = "3.1.8"
|
||||
[package.dependencies]
|
||||
gitdb = ">=4.0.1,<5"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
name = "idna"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.10"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Read metadata from Python packages"
|
||||
@@ -430,7 +385,7 @@ description = "A SQL query builder API for Python"
|
||||
name = "pypika"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.39.1"
|
||||
version = "0.40.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
@@ -548,14 +503,6 @@ optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "3.0.4"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Sniff out which async library your code is running under"
|
||||
name = "sniffio"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "1.1.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Manage dynamic plugins for Python applications"
|
||||
@@ -629,7 +576,7 @@ testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pyt
|
||||
dbdrivers = ["aiomysql", "asyncpg"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "06f00778f783c4ad5b174a9c9ee80f4f0e38db9da9ff1012f09c7d306eaa0975"
|
||||
content-hash = "43fe9c0036f4d55d38f82c263887d8a7d9a35a597e02036b70a631955ff73149"
|
||||
lock-version = "1.0"
|
||||
python-versions = "^3.7"
|
||||
|
||||
@@ -642,10 +589,6 @@ aiosqlite = [
|
||||
{file = "aiosqlite-0.15.0-py3-none-any.whl", hash = "sha256:19b984b6702aed9f1c85c023f37296954547fc4030dae8e9d027b2a930bed78b"},
|
||||
{file = "aiosqlite-0.15.0.tar.gz", hash = "sha256:a2884793f4dc8f2798d90e1dfecb2b56a6d479cf039f7ec52356a7fd5f3bdc57"},
|
||||
]
|
||||
anyio = [
|
||||
{file = "anyio-2.0.0-py3-none-any.whl", hash = "sha256:0b8375c8fc665236cb4d143ea13e849eb9e074d727b1b5c27d88aba44ca8c547"},
|
||||
{file = "anyio-2.0.0.tar.gz", hash = "sha256:ceca4669ffa3f02bf20ef3d6c2a0c323b16cdc71d1ce0b0bc03c6f1f36054826"},
|
||||
]
|
||||
apipkg = [
|
||||
{file = "apipkg-1.5-py2.py3-none-any.whl", hash = "sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"},
|
||||
{file = "apipkg-1.5.tar.gz", hash = "sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6"},
|
||||
@@ -654,9 +597,6 @@ appdirs = [
|
||||
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
|
||||
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
|
||||
]
|
||||
asyncclick = [
|
||||
{file = "asyncclick-7.1.2.1.tar.gz", hash = "sha256:fe9fd8c44a6ae396e54471bd5f209838d46124e019ae701dd71a9c898928483b"},
|
||||
]
|
||||
asyncpg = [
|
||||
{file = "asyncpg-0.21.0-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:09badce47a4645cfe523cc8a182bd047d5d62af0caaea77935e6a3c9e77dc364"},
|
||||
{file = "asyncpg-0.21.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b7807bfedd24dd15cfb2c17c60977ce01410615ecc285268b5144a944ec97ff"},
|
||||
@@ -786,10 +726,6 @@ gitpython = [
|
||||
{file = "GitPython-3.1.8-py3-none-any.whl", hash = "sha256:1858f4fd089abe92ae465f01d5aaaf55e937eca565fb2c1fce35a51b5f85c910"},
|
||||
{file = "GitPython-3.1.8.tar.gz", hash = "sha256:080bf8e2cf1a2b907634761c2eaefbe83b69930c94c66ad11b65a8252959f912"},
|
||||
]
|
||||
idna = [
|
||||
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
|
||||
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"},
|
||||
{file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"},
|
||||
@@ -875,7 +811,7 @@ pyparsing = [
|
||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
||||
]
|
||||
pypika = [
|
||||
{file = "PyPika-0.39.1.tar.gz", hash = "sha256:f6c715348cb6fa0042fe5b69f40cbb19c36ee3ff68414ece8660465c56523012"},
|
||||
{file = "PyPika-0.40.0.tar.gz", hash = "sha256:659d307f7e531b66813619cbce08ecb97eeb302feabbd816ae8844b99496298b"},
|
||||
]
|
||||
pytest = [
|
||||
{file = "pytest-6.0.2-py3-none-any.whl", hash = "sha256:0e37f61339c4578776e090c3b8f6b16ce4db333889d65d0efb305243ec544b40"},
|
||||
@@ -940,10 +876,6 @@ smmap = [
|
||||
{file = "smmap-3.0.4-py2.py3-none-any.whl", hash = "sha256:54c44c197c819d5ef1991799a7e30b662d1e520f2ac75c9efbeb54a742214cf4"},
|
||||
{file = "smmap-3.0.4.tar.gz", hash = "sha256:9c98bbd1f9786d22f14b3d4126894d56befb835ec90cef151af566c7e19b5d24"},
|
||||
]
|
||||
sniffio = [
|
||||
{file = "sniffio-1.1.0-py3-none-any.whl", hash = "sha256:20ed6d5b46f8ae136d00b9dcb807615d83ed82ceea6b2058cecb696765246da5"},
|
||||
{file = "sniffio-1.1.0.tar.gz", hash = "sha256:8e3810100f69fe0edd463d02ad407112542a11ffdc29f67db2bf3771afb87a21"},
|
||||
]
|
||||
stevedore = [
|
||||
{file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"},
|
||||
{file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"},
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "aerich"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
description = "A database migrations tool for Tortoise ORM."
|
||||
authors = ["long2ice <long2ice@gmail.com>"]
|
||||
license = "Apache-2.0"
|
||||
@@ -17,7 +17,7 @@ include = ["CHANGELOG.md", "LICENSE", "README.md"]
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
tortoise-orm = "*"
|
||||
asyncclick = "*"
|
||||
click = "*"
|
||||
pydantic = "*"
|
||||
aiomysql = {version = "*", optional = true}
|
||||
asyncpg = {version = "*", optional = true}
|
||||
|
@@ -31,6 +31,12 @@ class User(Model):
|
||||
intro = fields.TextField(default="")
|
||||
|
||||
|
||||
class Email(Model):
|
||||
email = fields.CharField(max_length=200)
|
||||
is_primary = fields.BooleanField(default=False)
|
||||
user = fields.ForeignKeyField("diff_models.User", db_constraint=True)
|
||||
|
||||
|
||||
class Category(Model):
|
||||
slug = fields.CharField(max_length=200)
|
||||
user = fields.ForeignKeyField("diff_models.User", description="User")
|
||||
|
@@ -31,6 +31,12 @@ class User(Model):
|
||||
intro = fields.TextField(default="")
|
||||
|
||||
|
||||
class Email(Model):
|
||||
email = fields.CharField(max_length=200)
|
||||
is_primary = fields.BooleanField(default=False)
|
||||
user = fields.ForeignKeyField("models.User", db_constraint=False)
|
||||
|
||||
|
||||
class Category(Model):
|
||||
slug = fields.CharField(max_length=200)
|
||||
name = fields.CharField(max_length=200)
|
||||
|
@@ -20,8 +20,10 @@ def test_migrate(mocker: MockerFixture):
|
||||
Migrate.diff_models(models, diff_models, False)
|
||||
else:
|
||||
Migrate.diff_models(models, diff_models, False)
|
||||
Migrate._merge_operators()
|
||||
if isinstance(Migrate.ddl, MysqlDDL):
|
||||
assert Migrate.upgrade_operators == [
|
||||
"ALTER TABLE `email` DROP FOREIGN KEY `fk_email_user_5b58673d`",
|
||||
"ALTER TABLE `category` ADD `name` VARCHAR(200) NOT NULL",
|
||||
"ALTER TABLE `user` ADD UNIQUE INDEX `uid_user_usernam_9987ab` (`username`)",
|
||||
"ALTER TABLE `user` RENAME COLUMN `last_login_at` TO `last_login`",
|
||||
@@ -30,9 +32,12 @@ def test_migrate(mocker: MockerFixture):
|
||||
"ALTER TABLE `category` DROP COLUMN `name`",
|
||||
"ALTER TABLE `user` DROP INDEX `uid_user_usernam_9987ab`",
|
||||
"ALTER TABLE `user` RENAME COLUMN `last_login` TO `last_login_at`",
|
||||
"ALTER TABLE `email` ADD CONSTRAINT `fk_email_user_5b58673d` FOREIGN KEY "
|
||||
"(`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE",
|
||||
]
|
||||
elif isinstance(Migrate.ddl, PostgresDDL):
|
||||
assert Migrate.upgrade_operators == [
|
||||
'ALTER TABLE "email" DROP CONSTRAINT "fk_email_user_5b58673d"',
|
||||
'ALTER TABLE "category" ADD "name" VARCHAR(200) NOT NULL',
|
||||
'ALTER TABLE "user" ADD CONSTRAINT "uid_user_usernam_9987ab" UNIQUE ("username")',
|
||||
'ALTER TABLE "user" RENAME COLUMN "last_login_at" TO "last_login"',
|
||||
@@ -41,9 +46,11 @@ def test_migrate(mocker: MockerFixture):
|
||||
'ALTER TABLE "category" DROP COLUMN "name"',
|
||||
'ALTER TABLE "user" DROP CONSTRAINT "uid_user_usernam_9987ab"',
|
||||
'ALTER TABLE "user" RENAME COLUMN "last_login" TO "last_login_at"',
|
||||
'ALTER TABLE "email" ADD CONSTRAINT "fk_email_user_5b58673d" FOREIGN KEY ("user_id") REFERENCES "user" ("id") ON DELETE CASCADE',
|
||||
]
|
||||
elif isinstance(Migrate.ddl, SqliteDDL):
|
||||
assert Migrate.upgrade_operators == [
|
||||
'ALTER TABLE "email" DROP FOREIGN KEY "fk_email_user_5b58673d"',
|
||||
'ALTER TABLE "category" ADD "name" VARCHAR(200) NOT NULL',
|
||||
'ALTER TABLE "user" ADD UNIQUE INDEX "uid_user_usernam_9987ab" ("username")',
|
||||
'ALTER TABLE "user" RENAME COLUMN "last_login_at" TO "last_login"',
|
||||
|
Reference in New Issue
Block a user