Skip to content

Commit

Permalink
Fix Model.describe when Index is used
Browse files Browse the repository at this point in the history
  • Loading branch information
henadzit committed Jan 13, 2025
1 parent cfe0a88 commit 6ce5711
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 6 deletions.
13 changes: 11 additions & 2 deletions tests/fields/test_db_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from tortoise.contrib import test
from tortoise.exceptions import ConfigurationError
from tortoise.indexes import Index
from tests.testmodels import ModelWithIndexes


class CustomIndex(Index):
Expand All @@ -14,7 +15,7 @@ def __init__(self, *args, **kw):
self._foo = ""


class TestIndexHashEqualRepr(test.TestCase):
class TestIndexHashEqualRepr(test.SimpleTestCase):
def test_index_eq(self):
assert Index(fields=("id",)) == Index(fields=("id",))
assert CustomIndex(fields=("id",)) == CustomIndex(fields=("id",))
Expand Down Expand Up @@ -46,7 +47,7 @@ def test_index_repr(self):
assert repr(Index(fields=("id",), name="MyIndex")) == "Index(fields=['id'], name='MyIndex')"
assert repr(Index(Field("id"))) == f'Index({str(Field("id"))})'
assert repr(Index(Field("a"), name="Id")) == f"Index({str(Field('a'))}, name='Id')"
with self.assertRaises(ValueError):
with self.assertRaises(ConfigurationError):
Index(Field("id"), fields=("name",))


Expand Down Expand Up @@ -94,3 +95,11 @@ class TestIndexAliasUUID(TestIndexAlias):
class TestIndexAliasChar(TestIndexAlias):
Field = fields.CharField
init_kwargs = {"max_length": 10}


class TestModelWithIndexes(test.TestCase):
def test_meta(self):
self.assertEqual(ModelWithIndexes._meta.indexes, [Index(fields=("f1", "f2"))])
self.assertTrue(ModelWithIndexes._meta.fields_map["id"].index)
self.assertTrue(ModelWithIndexes._meta.fields_map["indexed"].index)
self.assertTrue(ModelWithIndexes._meta.fields_map["unique_indexed"].unique)
17 changes: 17 additions & 0 deletions tests/testmodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from tortoise import fields
from tortoise.exceptions import ValidationError
from tortoise.fields import NO_ACTION
from tortoise.indexes import Index
from tortoise.manager import Manager
from tortoise.models import Model
from tortoise.queryset import QuerySet
Expand Down Expand Up @@ -1050,3 +1051,19 @@ class BenchmarkManyFields(Model):
col_text4 = fields.TextField(null=True)
col_decimal4 = fields.DecimalField(12, 8, null=True)
col_json4 = fields.JSONField[dict](null=True)


class ModelWithIndexes(Model):
id = fields.IntField(primary_key=True)
indexed = fields.CharField(max_length=255, index=True)
unique_indexed = fields.CharField(max_length=255, unique=True)
f1 = fields.CharField(max_length=255)
f2 = fields.CharField(max_length=255)
u1 = fields.IntField()
u2 = fields.IntField()

class Meta:
indexes = [
Index(fields=["f1", "f2"]),
]
unique_together = [("u1", "u2")]
17 changes: 17 additions & 0 deletions tests/utils/test_describe_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from tests.testmodels import (
Event,
JSONFields,
ModelWithIndexes,
Reporter,
SourceFields,
StraightFields,
Expand Down Expand Up @@ -1561,3 +1562,19 @@ def test_describe_model_json_native(self):
"m2m_fields": [],
},
)

def test_describe_indexes_serializable(self):
val = ModelWithIndexes.describe()

self.assertEqual(
val["indexes"],
[{"fields": ["f1", "f2"], "expressions": [], "name": None, "type": "", "extra": ""}],
)

def test_describe_indexes_not_serializable(self):
val = ModelWithIndexes.describe(serializable=False)

self.assertEqual(
val["indexes"],
ModelWithIndexes._meta.indexes,
)
17 changes: 15 additions & 2 deletions tortoise/indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from pypika_tortoise.terms import Term, ValueWrapper

from tortoise.exceptions import ConfigurationError


class Index:
INDEX_TYPE = ""
Expand All @@ -24,15 +26,26 @@ def __init__(
"""
self.fields = list(fields or [])
if not expressions and not fields:
raise ValueError("At least one field or expression is required to define an " "index.")
raise ConfigurationError(
"At least one field or expression is required to define an " "index."
)
if expressions and fields:
raise ValueError(
raise ConfigurationError(
"Index.fields and expressions are mutually exclusive.",
)
self.name = name
self.expressions = expressions
self.extra = ""

def describe(self) -> dict:
return {
"fields": self.fields,
"expressions": [str(expression) for expression in self.expressions],
"name": self.name,
"type": self.INDEX_TYPE,
"extra": self.extra,
}

def __repr__(self) -> str:
argument = ""
if self.expressions:
Expand Down
13 changes: 11 additions & 2 deletions tortoise/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def __init__(self, meta: "Model.Meta") -> None:
self.schema: Optional[str] = getattr(meta, "schema", None)
self.app: Optional[str] = getattr(meta, "app", None)
self.unique_together: Tuple[Tuple[str, ...], ...] = get_together(meta, "unique_together")
self.indexes: Tuple[Tuple[str, ...], ...] = get_together(meta, "indexes")
self.indexes: Tuple[Union[Tuple[str, ...], Index], ...] = get_together(meta, "indexes")
self._default_ordering: Tuple[Tuple[str, Order], ...] = prepare_default_ordering(meta)
self._ordering_validated: bool = False
self.fields: Set[str] = set()
Expand Down Expand Up @@ -1466,6 +1466,15 @@ def _check_together(cls, together: str) -> None:
" to ManyToMany field."
)

@classmethod
def _describe_index(
cls, index: Union[Index, Tuple[str, ...]], serializable: bool
) -> Union[Index, Tuple[str, ...], dict]:
if isinstance(index, Index):
return index.describe() if serializable else index

return index

@classmethod
def describe(cls, serializable: bool = True) -> dict:
"""
Expand Down Expand Up @@ -1511,7 +1520,7 @@ def describe(cls, serializable: bool = True) -> dict:
"description": cls._meta.table_description or None,
"docstring": inspect.cleandoc(cls.__doc__ or "") or None,
"unique_together": cls._meta.unique_together or [],
"indexes": cls._meta.indexes or [],
"indexes": [cls._describe_index(index, serializable) for index in cls._meta.indexes],
"pk_field": cls._meta.fields_map[cls._meta.pk_attr].describe(serializable),
"data_fields": [
field.describe(serializable)
Expand Down

0 comments on commit 6ce5711

Please sign in to comment.