Skip to content

Commit 60e57b3

Browse files
committed
Fix mapping typing issue
1 parent 9159367 commit 60e57b3

File tree

5 files changed

+142
-24
lines changed

5 files changed

+142
-24
lines changed

django_mongodb_backend/base.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,38 @@ def _isnull_operator(a, b):
127127
"iregex": lambda a, b: regex_match(a, b, insensitive=True),
128128
}
129129

130+
mongo_data_types = {
131+
"AutoField": "number",
132+
"BigAutoField": "number",
133+
"BinaryField": "string",
134+
"BooleanField": "boolean",
135+
"CharField": "string",
136+
"DateField": "date",
137+
"DateTimeField": "date",
138+
"DecimalField": "number",
139+
"DurationField": "number",
140+
"FileField": "string",
141+
"FilePathField": "string",
142+
"FloatField": "double",
143+
"IntegerField": "number",
144+
"BigIntegerField": "number",
145+
"GenericIPAddressField": "string",
146+
"JSONField": "document",
147+
"OneToOneField": "number",
148+
"PositiveBigIntegerField": "number",
149+
"PositiveIntegerField": "number",
150+
"PositiveSmallIntegerField": "number",
151+
"SlugField": "string",
152+
"SmallAutoField": "number",
153+
"SmallIntegerField": "number",
154+
"TextField": "string",
155+
"TimeField": "date",
156+
"UUIDField": "uuid",
157+
"ObjectIdAutoField": ["objectId", "number"],
158+
"ObjectIdField": ["objectId"],
159+
"EmbeddedModelField": "embeddedDocuments",
160+
}
161+
130162
display_name = "MongoDB"
131163
vendor = "mongodb"
132164
Database = Database
@@ -175,12 +207,7 @@ def get_connection_params(self):
175207

176208
@async_unsafe
177209
def get_new_connection(self, conn_params):
178-
# import ipdb
179-
# ipdb.set_trace()
180-
return MongoClient(
181-
"mongodb://127.0.0.1:27017/?directConnection=true", driver=self._driver_info()
182-
)
183-
# return MongoClient(**conn_params, driver=self._driver_info())
210+
return MongoClient(**conn_params, directConnection=True, driver=self._driver_info())
184211

185212
def _driver_info(self):
186213
if not os.environ.get("RUNNING_DJANGOS_TEST_SUITE"):

django_mongodb_backend/indexes.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,16 @@ def where_node_idx(self, compiler, connection):
6060
return mql
6161

6262

63-
def create_mongodb_index(self, model, schema_editor, *, field=None, unique=False, column_prefix=""):
63+
def create_mongodb_index(
64+
self,
65+
model,
66+
schema_editor,
67+
*,
68+
connection=None, # noqa: ARG001
69+
field=None,
70+
unique=False,
71+
column_prefix="",
72+
):
6473
from collections import defaultdict
6574

6675
if self.contains_expressions:
@@ -101,6 +110,8 @@ def create_mongodb_index(self, model, schema_editor, *, field=None, unique=False
101110

102111

103112
class AtlasSearchIndex(Index):
113+
suffix = "atlas_search"
114+
104115
def __init__(self, *expressions, **kwargs):
105116
super().__init__(*expressions, **kwargs)
106117

@@ -110,9 +121,10 @@ def create_mongodb_index(
110121
fields = {}
111122
for field_name, _ in self.fields_orders:
112123
field_ = model._meta.get_field(field_name)
113-
fields[field_name] = {"type": field_.db_type(connection)}
124+
type_ = connection.mongo_data_types[field_.get_internal_type()]
125+
fields[field_name] = {"type": type_}
114126
return SearchIndexModel(
115-
definition={"mappings": {"dynamic": False}, "fields": fields}, name=self.name
127+
definition={"mappings": {"dynamic": False, "fields": fields}}, name=self.name
116128
)
117129

118130

django_mongodb_backend/introspection.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
from django.db.models import Index
33
from pymongo import ASCENDING, DESCENDING
44

5+
from django_mongodb_backend.indexes import AtlasSearchIndex
6+
57

68
class DatabaseIntrospection(BaseDatabaseIntrospection):
79
ORDER_DIR = {ASCENDING: "ASC", DESCENDING: "DESC"}
810

911
def table_names(self, cursor=None, include_views=False):
1012
return sorted([x["name"] for x in self.connection.database.list_collections()])
1113

12-
def get_constraints(self, cursor, table_name):
14+
def _get_index_info(self, table_name):
1315
indexes = self.connection.get_collection(table_name).index_information()
1416
constraints = {}
1517
for name, details in indexes.items():
@@ -30,3 +32,25 @@ def get_constraints(self, cursor, table_name):
3032
"options": {},
3133
}
3234
return constraints
35+
36+
def _get_atlas_index_info(self, table_name):
37+
constraints = {}
38+
indexes = self.connection.get_collection(table_name).list_search_indexes()
39+
for details in indexes:
40+
columns = list(details["latestDefinition"]["mappings"].get("fields", {}).keys())
41+
constraints[details["name"]] = {
42+
"check": False,
43+
"columns": columns,
44+
"definition": None,
45+
"foreign_key": None,
46+
"index": True,
47+
"orders": [],
48+
"primary_key": False,
49+
"type": AtlasSearchIndex.suffix,
50+
"unique": False,
51+
"options": details["latestDefinition"]["mappings"],
52+
}
53+
return constraints
54+
55+
def get_constraints(self, cursor, table_name):
56+
return {**self._get_index_info(table_name), **self._get_atlas_index_info(table_name)}

tests/indexes_/models.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
from django.db import models
22

3+
from django_mongodb_backend.fields import EmbeddedModelField
4+
from django_mongodb_backend.models import EmbeddedModel
5+
6+
7+
class Data(EmbeddedModel):
8+
integer = models.IntegerField()
9+
310

411
class Article(models.Model):
512
headline = models.CharField(max_length=100)
613
number = models.IntegerField()
714
body = models.TextField()
15+
data = models.JSONField()
16+
embedded = EmbeddedModelField(Data)
17+
auto_now = models.DateTimeField(auto_now=True)

tests/indexes_/test_atlas_indexes.py

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,76 @@
11
from django.db import connection
2-
from django.test import TransactionTestCase
3-
from django.test.utils import override_settings
2+
from django.test import TestCase
43

54
from django_mongodb_backend.indexes import AtlasSearchIndex
65

76
from .models import Article
87

98

10-
@override_settings(USE_TZ=True)
11-
class PartialIndexTests(TransactionTestCase):
9+
class PartialIndexTests(TestCase):
1210
# Schema editor is used to create the index to test that it works.
1311
# available_apps = ["indexes"]
1412
available_apps = None
1513

16-
def test_partial_index(self):
14+
def assertAddRemoveIndex(self, editor, model, index):
15+
editor.add_index(index=index, model=model)
16+
self.assertIn(
17+
index.name,
18+
connection.introspection.get_constraints(
19+
cursor=None,
20+
table_name=model._meta.db_table,
21+
),
22+
)
23+
editor.remove_index(index=index, model=model)
24+
25+
def test_simple_atlas_index(self):
1726
with connection.schema_editor() as editor:
1827
index = AtlasSearchIndex(
1928
name="recent_article_idx",
2029
fields=["number"],
2130
)
2231
editor.add_index(index=index, model=Article)
23-
# with connection.cursor() as cursor:
24-
# self.assertIn(
25-
# index.name,
26-
# connection.introspection.get_constraints(
27-
# cursor=cursor,
28-
# table_name=Article._meta.db_table,
29-
# ),
30-
# )
31-
editor.remove_index(index=index, model=Article)
32+
self.assertAddRemoveIndex(editor, Article, index)
33+
34+
def test_multiple_fields_atlas_index(self):
35+
with connection.schema_editor() as editor:
36+
index = AtlasSearchIndex(
37+
name="recent_article_idx",
38+
fields=["headline", "number", "body", "data", "embedded", "auto_now"],
39+
)
40+
# editor.remove_index(index=index, model=Article)
41+
editor.add_index(index=index, model=Article)
42+
index_info = connection.introspection.get_constraints(
43+
cursor=None,
44+
table_name=Article._meta.db_table,
45+
)
46+
expected_options = {
47+
"dynamic": False,
48+
"fields": {
49+
"auto_now": {"type": "date"},
50+
"body": {
51+
"indexOptions": "offsets",
52+
"norms": "include",
53+
"store": True,
54+
"type": "string",
55+
},
56+
"data": {"dynamic": False, "fields": {}, "type": "document"},
57+
"embedded": {"dynamic": False, "fields": {}, "type": "embeddedDocuments"},
58+
"headline": {
59+
"indexOptions": "offsets",
60+
"norms": "include",
61+
"store": True,
62+
"type": "string",
63+
},
64+
"number": {
65+
"indexDoubles": True,
66+
"indexIntegers": True,
67+
"representation": "double",
68+
"type": "number",
69+
},
70+
},
71+
}
72+
self.assertCountEqual(index_info[index.name]["columns"], index.fields)
73+
self.assertEqual(index_info[index.name]["options"], expected_options)
74+
75+
self.assertEqual(index_info, {})
76+
self.assertAddRemoveIndex(editor, Article, index)

0 commit comments

Comments
 (0)