Skip to content

Commit

Permalink
Fix create/drop indexes in every migration (#377)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
waketzheng and fullonic authored Dec 21, 2024
1 parent f93faa8 commit 7d22518
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- Fix configuration file reading error when containing Chinese characters. (#286)
- sqlite: failed to create/drop index. (#302)
- 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)

#### Changed
Expand Down
38 changes: 22 additions & 16 deletions aerich/migrate.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import hashlib
from __future__ import annotations

import importlib
import os
from datetime import datetime
from pathlib import Path
from typing import Dict, Iterable, List, Optional, Set, Tuple, Type, Union, cast

import asyncclick as click
import tortoise
from dictdiffer import diff
from tortoise import BaseDBAsyncClient, Model, Tortoise
from tortoise.exceptions import OperationalError
Expand Down Expand Up @@ -202,21 +204,25 @@ def _add_operator(cls, operator: str, upgrade=True, fk_m2m_index=False) -> None:

@classmethod
def _handle_indexes(cls, model: Type[Model], indexes: List[Union[Tuple[str], Index]]) -> list:
ret: list = []

def index_hash(self) -> str:
h = hashlib.new("MD5", usedforsecurity=False) # type:ignore[call-arg]
h.update(
self.index_name(cls.ddl.schema_generator, model).encode()
+ self.__class__.__name__.encode()
)
return h.hexdigest()

for index in indexes:
if isinstance(index, Index):
index.__hash__ = index_hash # type:ignore[method-assign,assignment]
ret.append(index)
return ret
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 _hash(self) -> int:
return hash((tuple(sorted(self.fields)), self.name, self.expressions))

def _eq(self, other) -> bool:
return type(self) is type(other) and self.__dict__ == other.__dict__

setattr(index_cls, "__hash__", _hash)
setattr(index_cls, "__eq__", _eq)
return indexes

@classmethod
def _get_indexes(cls, model, model_describe: dict) -> Set[Union[Index, Tuple[str, ...]]]:
Expand Down
7 changes: 7 additions & 0 deletions tests/indexes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from tortoise.indexes import Index


class CustomIndex(Index):
def __init__(self, *args, **kw) -> None:
super().__init__(*args, **kw)
self._foo = ""
7 changes: 7 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from enum import IntEnum

from tortoise import Model, fields
from tortoise.indexes import Index

from tests.indexes import CustomIndex


class ProductType(IntEnum):
Expand Down Expand Up @@ -33,6 +36,10 @@ class User(Model):

products: fields.ManyToManyRelation["Product"]

class Meta:
# reverse indexes elements
indexes = [CustomIndex(fields=("is_superuser",)), Index(fields=("username", "is_active"))]


class Email(Model):
email_id = fields.IntField(primary_key=True)
Expand Down
6 changes: 6 additions & 0 deletions tests/old_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from enum import IntEnum

from tortoise import Model, fields
from tortoise.indexes import Index

from tests.indexes import CustomIndex


class ProductType(IntEnum):
Expand Down Expand Up @@ -31,6 +34,9 @@ class User(Model):
intro = fields.TextField(default="")
longitude = fields.DecimalField(max_digits=12, decimal_places=9)

class Meta:
indexes = [Index(fields=("username", "is_active")), CustomIndex(fields=("is_superuser",))]


class Email(Model):
email = fields.CharField(max_length=200)
Expand Down
4 changes: 3 additions & 1 deletion tests/test_migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import pytest
import tortoise
from pytest_mock import MockerFixture
from tortoise.indexes import Index

from aerich.ddl.mysql import MysqlDDL
from aerich.ddl.postgres import PostgresDDL
from aerich.ddl.sqlite import SqliteDDL
from aerich.exceptions import NotSupportError
from aerich.migrate import MIGRATE_TEMPLATE, Migrate
from aerich.utils import get_models_describe
from tests.indexes import CustomIndex

# tortoise-orm>=0.21 changes IntField constraints
# from {"ge": 1, "le": 2147483647} to {"ge": -2147483648, "le": 2147483647}
Expand Down Expand Up @@ -608,7 +610,7 @@
"description": None,
"docstring": None,
"unique_together": [],
"indexes": [],
"indexes": [Index(fields=("username", "is_active")), CustomIndex(fields=("is_superuser",))],
"pk_field": {
"name": "id",
"field_type": "IntField",
Expand Down

0 comments on commit 7d22518

Please sign in to comment.