now alice is basic worked

This commit is contained in:
long2ice
2020-05-15 10:45:40 +08:00
parent a79f5c1dc6
commit a99a06e563
14 changed files with 427 additions and 163 deletions

View File

@@ -1 +1 @@
__version__ = "0.1.0"
__version__ = "0.1.1"

View File

@@ -5,7 +5,7 @@ import sys
from enum import Enum
import asyncclick as click
from asyncclick import BadOptionUsage, BadParameter, Context, UsageError
from asyncclick import BadOptionUsage, Context, UsageError
from tortoise import Tortoise, generate_schema_for_client
from alice.migrate import Migrate
@@ -23,7 +23,7 @@ class Color(str, Enum):
"--config",
default="settings",
show_default=True,
help="Tortoise-ORM config module, will read config variable from it.",
help="Tortoise-ORM config module, will auto read dict config variable from it.",
)
@click.option(
"--tortoise-orm",
@@ -44,10 +44,14 @@ async def cli(ctx: Context, config, tortoise_orm, location, app):
raise BadOptionUsage(ctx=ctx, message=f'No module named "{config}"', option_name="--config")
config = getattr(config_module, tortoise_orm, None)
if not config:
raise BadOptionUsage(f'Can\'t get "{tortoise_orm}" from module "{config_module}"', ctx=ctx)
raise BadOptionUsage(
option_name="--config",
message=f'Can\'t get "{tortoise_orm}" from module "{config_module}"',
ctx=ctx,
)
if app not in config.get("apps").keys():
raise BadOptionUsage(f'No app found in "{config}"', ctx=ctx)
raise BadOptionUsage(option_name="--config", message=f'No app found in "{config}"', ctx=ctx)
ctx.obj["config"] = config
ctx.obj["location"] = location
@@ -142,7 +146,7 @@ def history(ctx):
@cli.command(
help="Init migrate location and generate schema, you must exec first before other cmd."
help="Init migrate location and generate schema, you must exec first."
)
@click.option(
"--safe",

View File

@@ -2,10 +2,10 @@ from typing import List, Type
from tortoise import BaseDBAsyncClient, ForeignKeyFieldInstance, Model
from tortoise.backends.base.schema_generator import BaseSchemaGenerator
from tortoise.fields import Field, JSONField, TextField, UUIDField
from tortoise.fields import Field
class DDL:
class BaseDDL:
schema_generator_cls: Type[BaseSchemaGenerator] = BaseSchemaGenerator
DIALECT = "sql"
_DROP_TABLE_TEMPLATE = "DROP TABLE {table_name} IF EXISTS"
@@ -23,108 +23,25 @@ class DDL:
self.schema_generator = self.schema_generator_cls(client)
def create_table(self, model: "Type[Model]"):
return self.schema_generator._get_table_sql(model, True)["table_creation_string"]
raise NotImplementedError
def drop_table(self, model: "Type[Model]"):
return self._DROP_TABLE_TEMPLATE.format(table_name=model._meta.db_table)
raise NotImplementedError
def add_column(self, model: "Type[Model]", field_object: Field):
db_table = model._meta.db_table
default = field_object.default
db_column = field_object.model_field_name
auto_now_add = getattr(field_object, "auto_now_add", False)
auto_now = getattr(field_object, "auto_now", False)
if default is not None or auto_now or auto_now_add:
if callable(default) or isinstance(field_object, (UUIDField, TextField, JSONField)):
default = ""
else:
default = field_object.to_db_value(default, model)
try:
default = self.schema_generator._column_default_generator(
db_table,
db_column,
self.schema_generator._escape_default_value(default),
auto_now_add,
auto_now,
)
except NotImplementedError:
default = ""
else:
default = ""
return self._ADD_COLUMN_TEMPLATE.format(
table_name=db_table,
column=self.schema_generator._create_string(
db_column=field_object.model_field_name,
field_type=field_object.get_for_dialect(self.DIALECT, "SQL_TYPE"),
nullable="NOT NULL" if not field_object.null else "",
unique="UNIQUE" if field_object.unique else "",
comment=self.schema_generator._column_comment_generator(
table=db_table,
column=field_object.model_field_name,
comment=field_object.description,
)
if field_object.description
else "",
is_primary_key=field_object.pk,
default=default,
),
)
raise NotImplementedError
def drop_column(self, model: "Type[Model]", column_name: str):
return self._DROP_COLUMN_TEMPLATE.format(
table_name=model._meta.db_table, column_name=column_name
)
raise NotImplementedError
def add_index(self, model: "Type[Model]", field_names: List[str], unique=False):
return self._ADD_INDEX_TEMPLATE.format(
unique="UNIQUE" if unique else "",
index_name=self.schema_generator._generate_index_name(
"idx" if not unique else "uid", model, field_names
),
table_name=model._meta.db_table,
column_names=", ".join([self.schema_generator.quote(f) for f in field_names]),
)
raise NotImplementedError
def drop_index(self, model: "Type[Model]", field_names: List[str], unique=False):
return self._DROP_INDEX_TEMPLATE.format(
index_name=self.schema_generator._generate_index_name(
"idx" if not unique else "uid", model, field_names
),
table_name=model._meta.db_table,
)
raise NotImplementedError
def add_fk(self, model: "Type[Model]", field: ForeignKeyFieldInstance):
db_table = model._meta.db_table
to_field_name = field.to_field_instance.source_field
if not to_field_name:
to_field_name = field.to_field_instance.model_field_name
fk_name = self.schema_generator._generate_fk_name(
from_table=db_table,
from_field=field.source_field or field.model_field_name + "_id",
to_table=field.related_model._meta.db_table,
to_field=to_field_name,
)
return self._ADD_FK_TEMPLATE.format(
table_name=db_table,
fk_name=fk_name,
db_column=field.source_field or field.model_field_name + "_id",
table=field.related_model._meta.db_table,
field=to_field_name,
on_delete=field.on_delete,
)
raise NotImplementedError
def drop_fk(self, model: "Type[Model]", field: ForeignKeyFieldInstance):
to_field_name = field.to_field_instance.source_field
if not to_field_name:
to_field_name = field.to_field_instance.model_field_name
db_table = model._meta.db_table
return self._DROP_FK_TEMPLATE.format(
table_name=db_table,
fk_name=self.schema_generator._generate_fk_name(
from_table=db_table,
from_field=field.source_field or field.model_field_name + "_id",
to_table=field.related_model._meta.db_table,
to_field=to_field_name,
),
)
raise NotImplementedError

View File

@@ -1,8 +1,120 @@
from typing import List, Type
from tortoise import ForeignKeyFieldInstance, Model
from tortoise.backends.mysql.schema_generator import MySQLSchemaGenerator
from tortoise.fields import Field, JSONField, TextField, UUIDField
from alice.ddl import DDL
from alice.ddl import BaseDDL
class MysqlDDL(DDL):
class MysqlDDL(BaseDDL):
schema_generator_cls = MySQLSchemaGenerator
DIALECT = MySQLSchemaGenerator.DIALECT
def create_table(self, model: "Type[Model]"):
return self.schema_generator._get_table_sql(model, True)["table_creation_string"]
def drop_table(self, model: "Type[Model]"):
return self._DROP_TABLE_TEMPLATE.format(table_name=model._meta.db_table)
def add_column(self, model: "Type[Model]", field_object: Field):
db_table = model._meta.db_table
default = field_object.default
db_column = field_object.model_field_name
auto_now_add = getattr(field_object, "auto_now_add", False)
auto_now = getattr(field_object, "auto_now", False)
if default is not None or auto_now_add:
if callable(default) or isinstance(field_object, (UUIDField, TextField, JSONField)):
default = ""
else:
default = field_object.to_db_value(default, model)
try:
default = self.schema_generator._column_default_generator(
db_table,
db_column,
self.schema_generator._escape_default_value(default),
auto_now_add,
auto_now,
)
except NotImplementedError:
default = ""
else:
default = ""
return self._ADD_COLUMN_TEMPLATE.format(
table_name=db_table,
column=self.schema_generator._create_string(
db_column=field_object.model_field_name,
field_type=field_object.get_for_dialect(self.DIALECT, "SQL_TYPE"),
nullable="NOT NULL" if not field_object.null else "",
unique="UNIQUE" if field_object.unique else "",
comment=self.schema_generator._column_comment_generator(
table=db_table,
column=field_object.model_field_name,
comment=field_object.description,
)
if field_object.description
else "",
is_primary_key=field_object.pk,
default=default,
),
)
def drop_column(self, model: "Type[Model]", column_name: str):
return self._DROP_COLUMN_TEMPLATE.format(
table_name=model._meta.db_table, column_name=column_name
)
def add_index(self, model: "Type[Model]", field_names: List[str], unique=False):
return self._ADD_INDEX_TEMPLATE.format(
unique="UNIQUE" if unique else "",
index_name=self.schema_generator._generate_index_name(
"idx" if not unique else "uid", model, field_names
),
table_name=model._meta.db_table,
column_names=", ".join([self.schema_generator.quote(f) for f in field_names]),
)
def drop_index(self, model: "Type[Model]", field_names: List[str], unique=False):
return self._DROP_INDEX_TEMPLATE.format(
index_name=self.schema_generator._generate_index_name(
"idx" if not unique else "uid", model, field_names
),
table_name=model._meta.db_table,
)
def add_fk(self, model: "Type[Model]", field: ForeignKeyFieldInstance):
db_table = model._meta.db_table
to_field_name = field.to_field_instance.source_field
if not to_field_name:
to_field_name = field.to_field_instance.model_field_name
db_column = field.source_field or field.model_field_name + "_id"
fk_name = self.schema_generator._generate_fk_name(
from_table=db_table,
from_field=db_column,
to_table=field.related_model._meta.db_table,
to_field=to_field_name,
)
return self._ADD_FK_TEMPLATE.format(
table_name=db_table,
fk_name=fk_name,
db_column=db_column,
table=field.related_model._meta.db_table,
field=to_field_name,
on_delete=field.on_delete,
)
def drop_fk(self, model: "Type[Model]", field: ForeignKeyFieldInstance):
to_field_name = field.to_field_instance.source_field
if not to_field_name:
to_field_name = field.to_field_instance.model_field_name
db_table = model._meta.db_table
return self._DROP_FK_TEMPLATE.format(
table_name=db_table,
fk_name=self.schema_generator._generate_fk_name(
from_table=db_table,
from_field=field.source_field or field.model_field_name + "_id",
to_table=field.related_model._meta.db_table,
to_field=to_field_name,
),
)

View File

@@ -9,7 +9,7 @@ from tortoise import BackwardFKRelation, ForeignKeyFieldInstance, Model, Tortois
from tortoise.backends.mysql.schema_generator import MySQLSchemaGenerator
from tortoise.fields import Field
from alice.ddl import DDL
from alice.ddl import BaseDDL
from alice.ddl.mysql import MysqlDDL
from alice.exceptions import ConfigurationError
from alice.utils import get_app_connection
@@ -21,7 +21,7 @@ class Migrate:
_upgrade_fk_operators: List[str] = []
_downgrade_fk_operators: List[str] = []
ddl: DDL
ddl: BaseDDL
migrate_config: dict
old_models = "old_models"
diff_app = "diff_models"
@@ -85,6 +85,11 @@ class Migrate:
@classmethod
def migrate(cls, name):
"""
diff old models and new models to generate diff content
:param name:
:return:
"""
if not cls.migrate_config:
raise ConfigurationError("You must call init_with_old_models() first!")
apps = Tortoise.apps
@@ -103,6 +108,13 @@ class Migrate:
@classmethod
def _add_operator(cls, operator: str, upgrade=True, fk=False):
"""
add operator,differentiate fk because fk is order limit
:param operator:
:param upgrade:
:param fk:
:return:
"""
if upgrade:
if fk:
cls._upgrade_fk_operators.append(operator)
@@ -134,6 +146,13 @@ class Migrate:
@classmethod
def _get_migrate_config(cls, config: dict, app: str, location: str):
"""
generate tmp config with old models
:param config:
:param app:
:param location:
:return:
"""
temp_config = deepcopy(config)
path = os.path.join(location, app, cls.old_models)
path = path.replace("/", ".").lstrip(".")
@@ -142,6 +161,13 @@ class Migrate:
@classmethod
def write_old_models(cls, config: dict, app: str, location: str):
"""
write new models to old models
:param config:
:param app:
:param location:
:return:
"""
old_model_files = []
models = config.get("apps").get(app).get("models")
for model in models:
@@ -235,6 +261,11 @@ class Migrate:
@classmethod
def _exclude_field(cls, field: Field):
"""
exclude BackwardFKRelation
:param field:
:return:
"""
return isinstance(field, BackwardFKRelation)
@classmethod
@@ -251,11 +282,23 @@ class Migrate:
return cls.ddl.drop_column(model, field.model_field_name)
@classmethod
def _add_fk(cls, model: Type[Model], field: Field):
def _add_fk(cls, model: Type[Model], field: ForeignKeyFieldInstance):
"""
add fk
:param model:
:param field:
:return:
"""
return cls.ddl.add_fk(model, field)
@classmethod
def _remove_fk(cls, model: Type[Model], field: Field):
def _remove_fk(cls, model: Type[Model], field: ForeignKeyFieldInstance):
"""
drop fk
:param model:
:param field:
:return:
"""
return cls.ddl.drop_fk(model, field)
@classmethod