@@ -85,17 +85,19 @@ def test_multiple_fields(self):
85
85
def test_field_not_exists (self ):
86
86
index = AtlasSearchIndex (
87
87
name = "recent_article_idx" ,
88
- fields = ["headline" , "number1 " ],
88
+ fields = ["headline" , "non_existing_name " ],
89
89
)
90
90
with connection .schema_editor () as editor :
91
- msg = "Article has no field named 'number1 '"
91
+ msg = "Article has no field named 'non_existing_name '"
92
92
with self .assertRaisesMessage (
93
93
FieldDoesNotExist , msg
94
94
), connection .schema_editor () as editor :
95
95
editor .add_index (index = index , model = Article )
96
96
97
97
98
- class AtlasIndexTestsWithData (AtlasIndexTests ):
98
+ class AtlasIndexTestsWithData (TestCase ):
99
+ available_apps = None
100
+
99
101
@classmethod
100
102
def setUpTestData (cls ):
101
103
articles = [
@@ -115,6 +117,74 @@ def setUpTestData(cls):
115
117
]
116
118
cls .objs = Article .objects .bulk_create (articles )
117
119
120
+ def assertAddRemoveIndex (self , editor , model , index ):
121
+ editor .add_index (index = index , model = model )
122
+ self .assertIn (
123
+ index .name ,
124
+ connection .introspection .get_constraints (
125
+ cursor = None ,
126
+ table_name = model ._meta .db_table ,
127
+ ),
128
+ )
129
+ editor .remove_index (index = index , model = model )
130
+ self .assertNotIn (
131
+ index .name ,
132
+ connection .introspection .get_constraints (
133
+ cursor = None ,
134
+ table_name = model ._meta .db_table ,
135
+ ),
136
+ )
137
+
138
+ def test_simple (self ):
139
+ with connection .schema_editor () as editor :
140
+ index = AtlasSearchIndex (
141
+ name = "recent_article_idx" ,
142
+ fields = ["number" ],
143
+ )
144
+ editor .add_index (index = index , model = Article )
145
+ self .assertAddRemoveIndex (editor , Article , index )
146
+
147
+ def test_multiple_fields (self ):
148
+ with connection .schema_editor () as editor :
149
+ index = AtlasSearchIndex (
150
+ name = "recent_article_idx" ,
151
+ fields = ["headline" , "number" , "body" , "data" , "embedded" , "auto_now" ],
152
+ )
153
+ editor .add_index (index = index , model = Article )
154
+ index_info = connection .introspection .get_constraints (
155
+ cursor = None ,
156
+ table_name = Article ._meta .db_table ,
157
+ )
158
+ expected_options = {
159
+ "dynamic" : False ,
160
+ "fields" : {
161
+ "auto_now" : {"type" : "date" },
162
+ "body" : {
163
+ "indexOptions" : "offsets" ,
164
+ "norms" : "include" ,
165
+ "store" : True ,
166
+ "type" : "string" ,
167
+ },
168
+ "data" : {"dynamic" : False , "fields" : {}, "type" : "document" },
169
+ "embedded" : {"dynamic" : False , "fields" : {}, "type" : "embeddedDocuments" },
170
+ "headline" : {
171
+ "indexOptions" : "offsets" ,
172
+ "norms" : "include" ,
173
+ "store" : True ,
174
+ "type" : "string" ,
175
+ },
176
+ "number" : {
177
+ "indexDoubles" : True ,
178
+ "indexIntegers" : True ,
179
+ "representation" : "double" ,
180
+ "type" : "number" ,
181
+ },
182
+ },
183
+ }
184
+ self .assertCountEqual (index_info [index .name ]["columns" ], index .fields )
185
+ self .assertEqual (index_info [index .name ]["options" ], expected_options )
186
+ self .assertAddRemoveIndex (editor , Article , index )
187
+
118
188
119
189
class AtlasSearchIndexTests (TestCase ):
120
190
# Schema editor is used to create the index to test that it works.
@@ -187,17 +257,19 @@ def test_multiple_fields(self):
187
257
def test_field_not_exists (self ):
188
258
index = AtlasVectorSearchIndex (
189
259
name = "recent_article_idx" ,
190
- fields = ["headline" , "number1 " , "title_embedded" ],
260
+ fields = ["headline" , "non_existing_name " , "title_embedded" ],
191
261
)
192
262
with connection .schema_editor () as editor :
193
- msg = "Article has no field named 'number1 '"
263
+ msg = "Article has no field named 'non_existing_name '"
194
264
with self .assertRaisesMessage (
195
265
FieldDoesNotExist , msg
196
266
), connection .schema_editor () as editor :
197
267
editor .add_index (index = index , model = Article )
198
268
199
269
200
- class AtlasSearchIndexTestsWithData (AtlasSearchIndexTests ):
270
+ class AtlasSearchIndexTestsWithData (TestCase ):
271
+ available_apps = None # could be removed?
272
+
201
273
@classmethod
202
274
def setUpTestData (cls ):
203
275
articles = [
@@ -216,3 +288,88 @@ def setUpTestData(cls):
216
288
for i in range (5 )
217
289
]
218
290
cls .objs = Article .objects .bulk_create (articles )
291
+
292
+ def assertAddRemoveIndex (self , editor , model , index ):
293
+ editor .add_index (index = index , model = model )
294
+ self .assertIn (
295
+ index .name ,
296
+ connection .introspection .get_constraints (
297
+ cursor = None ,
298
+ table_name = model ._meta .db_table ,
299
+ ),
300
+ )
301
+ editor .remove_index (index = index , model = model )
302
+ self .assertNotIn (
303
+ index .name ,
304
+ connection .introspection .get_constraints (
305
+ cursor = None ,
306
+ table_name = model ._meta .db_table ,
307
+ ),
308
+ )
309
+
310
+ def test_simple_atlas_vector_search (self ):
311
+ with connection .schema_editor () as editor :
312
+ index = AtlasVectorSearchIndex (
313
+ name = "recent_article_idx" ,
314
+ fields = ["number" ],
315
+ )
316
+ editor .add_index (index = index , model = Article )
317
+ self .assertAddRemoveIndex (editor , Article , index )
318
+
319
+ def test_multiple_fields (self ):
320
+ with connection .schema_editor () as editor :
321
+ index = AtlasVectorSearchIndex (
322
+ name = "recent_article_idx" ,
323
+ fields = ["headline" , "number" , "body" , "description_embedded" ],
324
+ )
325
+ editor .add_index (index = index , model = Article )
326
+ index_info = connection .introspection .get_constraints (
327
+ cursor = None ,
328
+ table_name = Article ._meta .db_table ,
329
+ )
330
+ expected_options = {
331
+ "latestDefinition" : {
332
+ "fields" : [
333
+ {"path" : "headline" , "type" : "filter" },
334
+ {"path" : "number" , "type" : "filter" },
335
+ {"path" : "body" , "type" : "filter" },
336
+ {
337
+ "numDimensions" : 10 ,
338
+ "path" : "description_embedded" ,
339
+ "similarity" : "cosine" ,
340
+ "type" : "vector" ,
341
+ },
342
+ ]
343
+ },
344
+ "latestVersion" : 0 ,
345
+ "name" : "recent_article_idx" ,
346
+ "queryable" : False ,
347
+ "type" : "vectorSearch" ,
348
+ }
349
+ self .assertCountEqual (index_info [index .name ]["columns" ], index .fields )
350
+ index_info [index .name ]["options" ].pop ("id" )
351
+ index_info [index .name ]["options" ].pop ("status" )
352
+ self .assertEqual (index_info [index .name ]["options" ], expected_options )
353
+ self .assertAddRemoveIndex (editor , Article , index )
354
+
355
+ def test_corrupted_data (self ):
356
+ # Mongodb does not raises anything when some vector does not fulfill the required size
357
+ with connection .schema_editor () as editor :
358
+ Article .objects .create (
359
+ headline = "Title" ,
360
+ number = 10 ,
361
+ body = f"body { 10 } " ,
362
+ data = "{json: 3}" ,
363
+ embedded = Data (integer = 3 ),
364
+ auto_now = datetime .datetime .now (),
365
+ title_embedded = [0.1 ] * 15 ,
366
+ description_embedded = [2.5 ] * 16 , # it does not have the required size of ten.
367
+ number_list = [2 ] * 22 ,
368
+ name_list = [f"name_{ 2 } " ] * 7 ,
369
+ )
370
+ index = AtlasVectorSearchIndex (
371
+ name = "recent_article_idx" ,
372
+ fields = ["headline" , "number" , "body" , "description_embedded" ],
373
+ )
374
+ editor .add_index (index = index , model = Article )
375
+ self .assertAddRemoveIndex (editor , Article , index )
0 commit comments