Skip to content

Commit 08654ec

Browse files
committed
Add search index support check in search indexes
1 parent fd6e8e8 commit 08654ec

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

django_mongodb_backend/indexes.py

+24-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import itertools
22
from collections import defaultdict
33

4-
from django.core.checks import Error
4+
from django.core.checks import Error, Warning
55
from django.db import NotSupportedError
66
from django.db.models import DecimalField, FloatField, Index
77
from django.db.models.lookups import BuiltinLookup
@@ -107,6 +107,23 @@ def where_node_idx(self, compiler, connection):
107107

108108
class SearchIndex(Index):
109109
suffix = "six"
110+
_error_id_prefix = "django_mongodb_backend.indexes.SearchIndex"
111+
112+
def check(self, model, connection):
113+
errors = []
114+
if not connection.features.supports_search_indexes:
115+
errors.append(
116+
Warning(
117+
"This version of MongoDB does not support search indexes.",
118+
hint=(
119+
"The index won't be created. Silence this warning if you "
120+
"don't care about it."
121+
),
122+
obj=self,
123+
id=f"{self._error_id_prefix}.W001",
124+
)
125+
)
126+
return errors
110127

111128
# Maps Django internal type to atlas search index type.
112129
# Reference: https://www.mongodb.com/docs/atlas/atlas-search/define-field-mappings/#data-types
@@ -144,14 +161,14 @@ def get_pymongo_index_model(
144161
class VectorSearchIndex(SearchIndex):
145162
suffix = "vsi"
146163
ALLOWED_SIMILARITY_FUNCTIONS = frozenset(("euclidean", "cosine", "dotProduct"))
164+
_error_id_prefix = "django_mongodb_backend.indexes.VectorSearchIndex"
147165

148166
def __init__(self, *expressions, similarities="cosine", **kwargs):
149167
super().__init__(*expressions, **kwargs)
150168
self.similarities = similarities
151169

152170
def check(self, model, connection):
153-
errors = []
154-
error_id_prefix = "django_mongodb_backend.indexes.VectorSearchIndex"
171+
errors = super().check(model, connection)
155172
similarities = (
156173
self.similarities if isinstance(self.similarities, list) else [self.similarities]
157174
)
@@ -162,7 +179,7 @@ def check(self, model, connection):
162179
f"{func} isn't a valid similarity function, options "
163180
f"are {', '.join(sorted(self.ALLOWED_SIMILARITY_FUNCTIONS))}",
164181
obj=self,
165-
id=f"{error_id_prefix}.E004",
182+
id=f"{self._error_id_prefix}.E004",
166183
)
167184
)
168185
for field_name, _ in self.fields_orders:
@@ -175,15 +192,15 @@ def check(self, model, connection):
175192
Error(
176193
"Atlas vector search requires size.",
177194
obj=self,
178-
id=f"{error_id_prefix}.E001",
195+
id=f"{self._error_id_prefix}.E001",
179196
)
180197
)
181198
if not isinstance(field_.base_field, FloatField | DecimalField):
182199
errors.append(
183200
Error(
184201
"Base type must be Float or Decimal.",
185202
obj=self,
186-
id=f"{error_id_prefix}.E002",
203+
id=f"{self._error_id_prefix}.E002",
187204
)
188205
)
189206
else:
@@ -197,7 +214,7 @@ def check(self, model, connection):
197214
Error(
198215
f"Unsupported filter of type {field_.get_internal_type()}.",
199216
obj=self,
200-
id="django_mongodb_backend.indexes.VectorSearchIndex.E003",
217+
id=f"{self._error_id_prefix}.E003",
201218
)
202219
)
203220
return errors

tests/system_checks/tests.py

+34-3
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
from django.core import checks
22
from django.db import models
3-
from django.test import SimpleTestCase
3+
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
44
from django.test.utils import (
55
isolate_apps,
66
override_system_checks,
77
)
88

99
from django_mongodb_backend.checks import check_vector_search_indexes
1010
from django_mongodb_backend.fields import ArrayField
11-
from django_mongodb_backend.indexes import VectorSearchIndex
11+
from django_mongodb_backend.indexes import SearchIndex, VectorSearchIndex
1212

1313

14+
@skipIfDBFeature("supports_search_indexes")
1415
@isolate_apps("system_checks", attr_name="apps")
1516
@override_system_checks([check_vector_search_indexes])
16-
class InvalidSearchIndexesTest(SimpleTestCase):
17+
class InvalidSearchIndexesTest(TestCase):
18+
def test_search_requires_search_index_support(self):
19+
class Article(models.Model):
20+
title = models.CharField(max_length=10)
21+
22+
class Meta:
23+
indexes = [
24+
SearchIndex(fields=["title"]),
25+
]
26+
27+
errors = checks.run_checks(app_configs=self.apps.get_app_configs(), databases={"default"})
28+
self.assertEqual(
29+
errors,
30+
[
31+
checks.Warning(
32+
"This version of MongoDB does not support search indexes.",
33+
hint=(
34+
"The index won't be created. Silence this warning if you "
35+
"don't care about it."
36+
),
37+
obj=Article._meta.indexes[0],
38+
id="django_mongodb_backend.indexes.SearchIndex.W001",
39+
)
40+
],
41+
)
42+
43+
44+
@skipUnlessDBFeature("supports_search_indexes")
45+
@isolate_apps("system_checks", attr_name="apps")
46+
@override_system_checks([check_vector_search_indexes])
47+
class InvalidVectorSearchIndexesTest(TestCase):
1748
def test_vectorsearch_requires_size(self):
1849
class Article(models.Model):
1950
title_embedded = ArrayField(models.FloatField())

0 commit comments

Comments
 (0)