Fix create/drop indexes in every migration (#377)
* Add `__eq__` method for `Index`instances * tests: add Index test case * refactor: compare index instances before set hash and eq func to class * fix: sort fields when generating index hash * docs: update changlog * fix style issue * refactor: use CustomIndex instead of postgres special HashIndex * Check tortoise version before patch Index * Add comment * Add comment for why > work --------- Co-authored-by: dbf <somnium@riseup.net>
This commit is contained in:
parent
f93faa8afb
commit
7d22518c74
@ -16,6 +16,7 @@
|
|||||||
- Fix configuration file reading error when containing Chinese characters. (#286)
|
- Fix configuration file reading error when containing Chinese characters. (#286)
|
||||||
- sqlite: failed to create/drop index. (#302)
|
- sqlite: failed to create/drop index. (#302)
|
||||||
- PostgreSQL: Cannot drop constraint after deleting or rename FK on a model. (#378)
|
- PostgreSQL: Cannot drop constraint after deleting or rename FK on a model. (#378)
|
||||||
|
- Fix create/drop indexes in every migration. (#377)
|
||||||
- Sort m2m fields before comparing them with diff. (#271)
|
- Sort m2m fields before comparing them with diff. (#271)
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import hashlib
|
from __future__ import annotations
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -6,6 +7,7 @@ from pathlib import Path
|
|||||||
from typing import Dict, Iterable, List, Optional, Set, Tuple, Type, Union, cast
|
from typing import Dict, Iterable, List, Optional, Set, Tuple, Type, Union, cast
|
||||||
|
|
||||||
import asyncclick as click
|
import asyncclick as click
|
||||||
|
import tortoise
|
||||||
from dictdiffer import diff
|
from dictdiffer import diff
|
||||||
from tortoise import BaseDBAsyncClient, Model, Tortoise
|
from tortoise import BaseDBAsyncClient, Model, Tortoise
|
||||||
from tortoise.exceptions import OperationalError
|
from tortoise.exceptions import OperationalError
|
||||||
@ -202,21 +204,25 @@ class Migrate:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _handle_indexes(cls, model: Type[Model], indexes: List[Union[Tuple[str], Index]]) -> list:
|
def _handle_indexes(cls, model: Type[Model], indexes: List[Union[Tuple[str], Index]]) -> list:
|
||||||
ret: list = []
|
if tortoise.__version__ > "0.22.2":
|
||||||
|
# The min version of tortoise is '0.11.0', so we can compare it by a `>`,
|
||||||
|
# tortoise>0.22.2 have __eq__/__hash__ with Index class since 313ee76.
|
||||||
|
return indexes
|
||||||
|
if index_classes := set(index.__class__ for index in indexes if isinstance(index, Index)):
|
||||||
|
# Leave magic patch here to compare with older version of tortoise-orm
|
||||||
|
# TODO: limit tortoise>0.22.2 in pyproject.toml and remove this function when v0.9.0 released
|
||||||
|
for index_cls in index_classes:
|
||||||
|
if index_cls(fields=("id",)) != index_cls(fields=("id",)):
|
||||||
|
|
||||||
def index_hash(self) -> str:
|
def _hash(self) -> int:
|
||||||
h = hashlib.new("MD5", usedforsecurity=False) # type:ignore[call-arg]
|
return hash((tuple(sorted(self.fields)), self.name, self.expressions))
|
||||||
h.update(
|
|
||||||
self.index_name(cls.ddl.schema_generator, model).encode()
|
|
||||||
+ self.__class__.__name__.encode()
|
|
||||||
)
|
|
||||||
return h.hexdigest()
|
|
||||||
|
|
||||||
for index in indexes:
|
def _eq(self, other) -> bool:
|
||||||
if isinstance(index, Index):
|
return type(self) is type(other) and self.__dict__ == other.__dict__
|
||||||
index.__hash__ = index_hash # type:ignore[method-assign,assignment]
|
|
||||||
ret.append(index)
|
setattr(index_cls, "__hash__", _hash)
|
||||||
return ret
|
setattr(index_cls, "__eq__", _eq)
|
||||||
|
return indexes
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_indexes(cls, model, model_describe: dict) -> Set[Union[Index, Tuple[str, ...]]]:
|
def _get_indexes(cls, model, model_describe: dict) -> Set[Union[Index, Tuple[str, ...]]]:
|
||||||
|
7
tests/indexes.py
Normal file
7
tests/indexes.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from tortoise.indexes import Index
|
||||||
|
|
||||||
|
|
||||||
|
class CustomIndex(Index):
|
||||||
|
def __init__(self, *args, **kw) -> None:
|
||||||
|
super().__init__(*args, **kw)
|
||||||
|
self._foo = ""
|
@ -3,6 +3,9 @@ import uuid
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
|
||||||
from tortoise import Model, fields
|
from tortoise import Model, fields
|
||||||
|
from tortoise.indexes import Index
|
||||||
|
|
||||||
|
from tests.indexes import CustomIndex
|
||||||
|
|
||||||
|
|
||||||
class ProductType(IntEnum):
|
class ProductType(IntEnum):
|
||||||
@ -33,6 +36,10 @@ class User(Model):
|
|||||||
|
|
||||||
products: fields.ManyToManyRelation["Product"]
|
products: fields.ManyToManyRelation["Product"]
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
# reverse indexes elements
|
||||||
|
indexes = [CustomIndex(fields=("is_superuser",)), Index(fields=("username", "is_active"))]
|
||||||
|
|
||||||
|
|
||||||
class Email(Model):
|
class Email(Model):
|
||||||
email_id = fields.IntField(primary_key=True)
|
email_id = fields.IntField(primary_key=True)
|
||||||
|
@ -2,6 +2,9 @@ import datetime
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
|
|
||||||
from tortoise import Model, fields
|
from tortoise import Model, fields
|
||||||
|
from tortoise.indexes import Index
|
||||||
|
|
||||||
|
from tests.indexes import CustomIndex
|
||||||
|
|
||||||
|
|
||||||
class ProductType(IntEnum):
|
class ProductType(IntEnum):
|
||||||
@ -31,6 +34,9 @@ class User(Model):
|
|||||||
intro = fields.TextField(default="")
|
intro = fields.TextField(default="")
|
||||||
longitude = fields.DecimalField(max_digits=12, decimal_places=9)
|
longitude = fields.DecimalField(max_digits=12, decimal_places=9)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
indexes = [Index(fields=("username", "is_active")), CustomIndex(fields=("is_superuser",))]
|
||||||
|
|
||||||
|
|
||||||
class Email(Model):
|
class Email(Model):
|
||||||
email = fields.CharField(max_length=200)
|
email = fields.CharField(max_length=200)
|
||||||
|
@ -3,6 +3,7 @@ from pathlib import Path
|
|||||||
import pytest
|
import pytest
|
||||||
import tortoise
|
import tortoise
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from tortoise.indexes import Index
|
||||||
|
|
||||||
from aerich.ddl.mysql import MysqlDDL
|
from aerich.ddl.mysql import MysqlDDL
|
||||||
from aerich.ddl.postgres import PostgresDDL
|
from aerich.ddl.postgres import PostgresDDL
|
||||||
@ -10,6 +11,7 @@ from aerich.ddl.sqlite import SqliteDDL
|
|||||||
from aerich.exceptions import NotSupportError
|
from aerich.exceptions import NotSupportError
|
||||||
from aerich.migrate import MIGRATE_TEMPLATE, Migrate
|
from aerich.migrate import MIGRATE_TEMPLATE, Migrate
|
||||||
from aerich.utils import get_models_describe
|
from aerich.utils import get_models_describe
|
||||||
|
from tests.indexes import CustomIndex
|
||||||
|
|
||||||
# tortoise-orm>=0.21 changes IntField constraints
|
# tortoise-orm>=0.21 changes IntField constraints
|
||||||
# from {"ge": 1, "le": 2147483647} to {"ge": -2147483648, "le": 2147483647}
|
# from {"ge": 1, "le": 2147483647} to {"ge": -2147483648, "le": 2147483647}
|
||||||
@ -608,7 +610,7 @@ old_models_describe = {
|
|||||||
"description": None,
|
"description": None,
|
||||||
"docstring": None,
|
"docstring": None,
|
||||||
"unique_together": [],
|
"unique_together": [],
|
||||||
"indexes": [],
|
"indexes": [Index(fields=("username", "is_active")), CustomIndex(fields=("is_superuser",))],
|
||||||
"pk_field": {
|
"pk_field": {
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"field_type": "IntField",
|
"field_type": "IntField",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user