Skip to content

Commit 3360efc

Browse files
committed
Add search index test
1 parent fdfc411 commit 3360efc

File tree

4 files changed

+334
-71
lines changed

4 files changed

+334
-71
lines changed

django_mongodb_backend/compiler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from django.utils.functional import cached_property
1818
from pymongo import ASCENDING, DESCENDING
1919

20-
from .functions import SearchExpression
20+
from .expressions.builtins import SearchExpression
2121
from .query import MongoQuery, wrap_database_errors
2222

2323

django_mongodb_backend/expressions/builtins.py

Lines changed: 83 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,7 @@ def value(self, compiler, connection): # noqa: ARG001
209209

210210

211211
class SearchExpression(Expression):
212-
def __init__(self):
213-
super().__init__(output_field=FloatField())
212+
output_field = FloatField()
214213

215214
def get_source_expressions(self):
216215
return []
@@ -235,34 +234,37 @@ def _get_query_index(self, fields, compiler):
235234

236235

237236
class SearchAutocomplete(SearchExpression):
238-
def __init__(self, path, query, score=None):
239-
self.path = F(path)
240-
self.query = Value(query)
237+
def __init__(self, path, query, fuzzy=None, score=None):
238+
self.path = path
239+
self.query = query
240+
self.fuzzy = fuzzy
241241
self.score = score
242242
super().__init__()
243243

244244
def as_mql(self, compiler, connection):
245245
params = {
246-
"path": self.path.as_mql(compiler, connection)[1:],
247-
"query": self.query.as_mql(compiler, connection),
246+
"path": self.path,
247+
"query": self.query,
248248
}
249249
if self.score is not None:
250250
params["score"] = self.score
251+
if self.fuzzy is not None:
252+
params["fuzzy"] = self.fuzzy
251253
index = self._get_query_index([self.path], compiler)
252254
return {"$search": {"autocomplete": params, "index": index}}
253255

254256

255257
class SearchEquals(SearchExpression):
256258
def __init__(self, path, value, score=None):
257-
self.path = F(path)
258-
self.value = Value(query)
259+
self.path = path
260+
self.value = value
259261
self.score = score
260262
super().__init__()
261263

262264
def as_mql(self, compiler, connection):
263265
params = {
264-
"path": self.path.as_mql(compiler, connection)[1:],
265-
"value": self.value.as_mql(compiler, connection),
266+
"path": self.path,
267+
"value": self.value,
266268
}
267269
if self.score is not None:
268270
params["score"] = self.score
@@ -272,13 +274,13 @@ def as_mql(self, compiler, connection):
272274

273275
class SearchExists(SearchExpression):
274276
def __init__(self, path, score=None):
275-
self.path = F(path)
277+
self.path = path
276278
self.score = score
277279
super().__init__()
278280

279281
def as_mql(self, compiler, connection):
280282
params = {
281-
"path": self.path.as_mql(compiler, connection)[1:],
283+
"path": self.path,
282284
}
283285
if self.score is not None:
284286
params["score"] = self.score
@@ -288,15 +290,15 @@ def as_mql(self, compiler, connection):
288290

289291
class SearchIn(SearchExpression):
290292
def __init__(self, path, value, score=None):
291-
self.path = F(path)
292-
self.value = Value(value)
293+
self.path = path
294+
self.value = value
293295
self.score = score
294296
super().__init__()
295297

296298
def as_mql(self, compiler, connection):
297299
params = {
298-
"path": self.path.as_mql(compiler, connection)[1:],
299-
"value": self.value.as_mql(compiler, connection),
300+
"path": self.path,
301+
"value": self.value,
300302
}
301303
if self.score is not None:
302304
params["score"] = self.score
@@ -305,18 +307,18 @@ def as_mql(self, compiler, connection):
305307

306308

307309
class SearchPhrase(SearchExpression):
308-
def __init__(self, path, value, slop=None, synonyms=None, score=None):
309-
self.path = F(path)
310-
self.value = Value(value)
310+
def __init__(self, path, query, slop=None, synonyms=None, score=None):
311+
self.path = path
312+
self.query = query
311313
self.score = score
312314
self.slop = slop
313315
self.synonyms = synonyms
314316
super().__init__()
315317

316318
def as_mql(self, compiler, connection):
317319
params = {
318-
"path": self.path.as_mql(compiler, connection)[1:],
319-
"value": self.value.as_mql(compiler, connection),
320+
"path": self.path,
321+
"query": self.query,
320322
}
321323
if self.score is not None:
322324
params["score"] = self.score
@@ -330,15 +332,15 @@ def as_mql(self, compiler, connection):
330332

331333
class SearchQueryString(SearchExpression):
332334
def __init__(self, path, query, score=None):
333-
self.path = F(path)
334-
self.query = Value(query)
335+
self.path = path
336+
self.query = query
335337
self.score = score
336338
super().__init__()
337339

338340
def as_mql(self, compiler, connection):
339341
params = {
340-
"defaultPath": self.path.as_mql(compiler, connection)[1:],
341-
"query": self.query.as_mql(compiler, connection),
342+
"defaultPath": self.path,
343+
"query": self.query,
342344
}
343345
if self.score is not None:
344346
params["score"] = self.score
@@ -348,132 +350,138 @@ def as_mql(self, compiler, connection):
348350

349351
class SearchRange(SearchExpression):
350352
def __init__(self, path, lt=None, lte=None, gt=None, gte=None, score=None):
351-
self.path = F(path)
352-
self.lt = Value(lt)
353-
self.lte = Value(lte)
354-
self.gt = Value(gt)
355-
self.gte = Value(gte)
353+
self.path = path
354+
self.lt = lt
355+
self.lte = lte
356+
self.gt = gt
357+
self.gte = gte
356358
self.score = score
357359
super().__init__()
358360

359361
def as_mql(self, compiler, connection):
360362
params = {
361-
"path": self.path.as_mql(compiler, connection)[1:],
363+
"path": self.path,
362364
}
363365
if self.score is not None:
364366
params["score"] = self.score
365367
if self.lt is not None:
366-
params["lt"] = self.lt.as_mql(compiler, connection)
368+
params["lt"] = self.lt
367369
if self.lte is not None:
368-
params["lte"] = self.lte.as_mql(compiler, connection)
370+
params["lte"] = self.lte
369371
if self.gt is not None:
370-
params["gt"] = self.gt.as_mql(compiler, connection)
372+
params["gt"] = self.gt
371373
if self.gte is not None:
372-
params["gte"] = self.gte.as_mql(compiler, connection)
374+
params["gte"] = self.gte
373375
index = self._get_query_index([self.path], compiler)
374376
return {"$search": {"range": params, "index": index}}
375377

376378

377379
class SearchRegex(SearchExpression):
378380
def __init__(self, path, query, allow_analyzed_field=None, score=None):
379-
self.path = F(path)
380-
self.allow_analyzed_field = Value(allow_analyzed_field)
381+
self.path = path
382+
self.query = query
383+
self.allow_analyzed_field = allow_analyzed_field
381384
self.score = score
382385
super().__init__()
383386

384387
def as_mql(self, compiler, connection):
385388
params = {
386-
"path": self.path.as_mql(compiler, connection)[1:],
389+
"path": self.path,
390+
"query": self.query,
387391
}
388392
if self.score:
389393
params["score"] = self.score
390394
if self.allow_analyzed_field is not None:
391-
params["allowAnalyzedField"] = self.allow_analyzed_field.as_mql(compiler, connection)
395+
params["allowAnalyzedField"] = self.allow_analyzed_field
392396
index = self._get_query_index([self.path], compiler)
393397
return {"$search": {"regex": params, "index": index}}
394398

395399

396400
class SearchText(SearchExpression):
397401
def __init__(self, path, query, fuzzy=None, match_criteria=None, synonyms=None, score=None):
398-
self.path = F(path)
399-
self.fuzzy = Value(fuzzy)
400-
self.match_criteria = Value(match_criteria)
401-
self.synonyms = Value(synonyms)
402+
self.path = path
403+
self.query = query
404+
self.fuzzy = fuzzy
405+
self.match_criteria = match_criteria
406+
self.synonyms = synonyms
402407
self.score = score
403408
super().__init__()
404409

405410
def as_mql(self, compiler, connection):
406411
params = {
407-
"path": self.path.as_mql(compiler, connection)[1:],
412+
"path": self.path,
413+
"query": self.query,
408414
}
409415
if self.score:
410416
params["score"] = self.score
411417
if self.fuzzy is not None:
412-
params["fuzzy"] = self.fuzzy.as_mql(compiler, connection)
418+
params["fuzzy"] = self.fuzzy
413419
if self.match_criteria is not None:
414-
params["matchCriteria"] = self.match_criteria.as_mql(compiler, connection)
420+
params["matchCriteria"] = self.match_criteria
415421
if self.synonyms is not None:
416-
params["synonyms"] = self.synonyms.as_mql(compiler, connection)
422+
params["synonyms"] = self.synonyms
417423
index = self._get_query_index([self.path], compiler)
418424
return {"$search": {"text": params, "index": index}}
419425

420426

421427
class SearchWildcard(SearchExpression):
422428
def __init__(self, path, query, allow_analyzed_field=None, score=None):
423-
self.path = F(path)
424-
self.allow_analyzed_field = Value(allow_analyzed_field)
429+
self.path = path
430+
self.query = query
431+
self.allow_analyzed_field = allow_analyzed_field
425432
self.score = score
426433
super().__init__()
427434

428435
def as_mql(self, compiler, connection):
429436
params = {
430-
"path": self.path.as_mql(compiler, connection)[1:],
437+
"path": self.path,
438+
"query": self.query,
431439
}
432440
if self.score:
433441
params["score"] = self.score
434442
if self.allow_analyzed_field is not None:
435-
params["allowAnalyzedField"] = self.allow_analyzed_field.as_mql(compiler, connection)
443+
params["allowAnalyzedField"] = self.allow_analyzed_field
436444
index = self._get_query_index([self.path], compiler)
437445
return {"$search": {"wildcard": params, "index": index}}
438446

439447

440448
class SearchGeoShape(SearchExpression):
441449
def __init__(self, path, relation, geometry, score=None):
442-
self.path = F(path)
450+
self.path = path
443451
self.relation = relation
444452
self.geometry = geometry
445453
self.score = score
446454
super().__init__()
447455

448456
def as_mql(self, compiler, connection):
449457
params = {
450-
"path": self.path.as_mql(compiler, connection)[1:],
458+
"path": self.path,
451459
"relation": self.relation,
452460
"geometry": self.geometry,
453461
}
454462
if self.score:
455463
params["score"] = self.score
456464
index = self._get_query_index([self.path], compiler)
457-
return {"$search": {"wildcard": params, "index": index}}
465+
return {"$search": {"geoShape": params, "index": index}}
458466

459467

460468
class SearchGeoWithin(SearchExpression):
461-
def __init__(self, path, kind, geo_object, geometry, score=None):
462-
self.path = F(path)
469+
def __init__(self, path, kind, geo_object, score=None):
470+
self.path = path
463471
self.kind = kind
464472
self.geo_object = geo_object
465473
self.score = score
466474
super().__init__()
467475

468476
def as_mql(self, compiler, connection):
469477
params = {
470-
"path": self.path.as_mql(compiler, connection)[1:],
478+
"path": self.path,
471479
self.kind: self.geo_object,
472480
}
473481
if self.score:
474482
params["score"] = self.score
475483
index = self._get_query_index([self.path], compiler)
476-
return {"$search": {"wildcard": params, "index": index}}
484+
return {"$search": {"geoWithin": params, "index": index}}
477485

478486

479487
class SearchMoreLikeThis(SearchExpression):
@@ -492,7 +500,22 @@ def as_mql(self, compiler, connection):
492500
for doc in self.documents:
493501
needed_fields += list(doc.keys())
494502
index = self._get_query_index(needed_fields, compiler)
495-
return {"$search": {"wildcard": params, "index": index}}
503+
return {"$search": {"moreLikeThis": params, "index": index}}
504+
505+
506+
class SearchScoreOption:
507+
"""Class to mutate scoring on a search operation"""
508+
509+
def __init__(self, definitions=None):
510+
self.definitions = definitions
511+
512+
513+
class CombinedSearchExpression(SearchExpression):
514+
def __init__(self, lhs, connector, rhs, output_field=None):
515+
super().__init__(output_field=output_field)
516+
self.connector = connector
517+
self.lhs = lhs
518+
self.rhs = rhs
496519

497520

498521
def register_expressions():

tests/queries_/models.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from django.db import models
22

33
from django_mongodb_backend.fields import ObjectIdAutoField, ObjectIdField
4-
from django_mongodb_backend.indexes import SearchIndex
54

65

76
class Author(models.Model):
@@ -60,6 +59,4 @@ class Article(models.Model):
6059
headline = models.CharField(max_length=100)
6160
number = models.IntegerField()
6261
body = models.TextField()
63-
64-
class Meta:
65-
indexes = [SearchIndex(fields=["headline"])]
62+
location = models.JSONField(null=True)

0 commit comments

Comments
 (0)