Commit ffe8d4ed authored by Matthieu Gautier's avatar Matthieu Gautier
Browse files

The `Search` class is now a private class.

And it is the same for each specific search classes.

So there is non need for the `search` and `ids` methods in the
`Search` class.
parent 2ce5840a
Pipeline #16248 failed with stage
in 7 minutes and 58 seconds
......@@ -13,19 +13,19 @@ def test_nothing_is_indexed_without_any_fixture():
@pytest.mark.usefixtures('cleansearch')
def test_draft_is_indexed(draft):
assert Content.objects.count() == 1
assert len(list(Content.SearchModel.search(public=True))) == 0
assert len(list(Content.objects.search(public=True))) == 0
@pytest.mark.usefixtures('cleansearch')
def test_deleted_is_indexed(deleted):
assert Content.objects.count() == 1
assert len(list(Content.SearchModel.search(public=True))) == 0
assert len(list(Content.objects.search(public=True))) == 0
@pytest.mark.usefixtures('cleansearch')
def test_published_is_indexed(published):
assert Content.objects.count() == 1
assert len(list(Content.SearchModel.search(public=True))) == 1
assert len(list(Content.objects.search(public=True))) == 1
assert Content.objects.search(text__match="Ikinyugunyugu").count() == 0
published.title = "Ikinyugunyugu"
published.save()
......
......@@ -9,7 +9,7 @@ pytestmark = pytest.mark.django_db
@pytest.mark.usefixtures('cleansearch')
def test_document_are_indexed(video):
assert Document.SearchModel.objects.count() == 1
assert len(list(Document.SearchModel.search(public=True))) == 1
assert len(list(Document.objects.search(public=True))) == 1
assert Document.objects.search(text__match="Ikinyugunyugu").count() == 0
video.title = "Ikinyugunyugu"
video.save()
......
......@@ -2,6 +2,7 @@ from django.db import models
from django.db.backends.signals import connection_created
from django.db.models.signals import post_save, pre_delete
from django.db.models.base import ModelBase
from django.db.models import Case, When
from django.dispatch import receiver
from .utils import rank
......@@ -52,7 +53,7 @@ class SearchQuerySet(models.QuerySet):
return self.extra(select=extra).order_by('-relevancy')
class Search(models.Model):
class _Search(models.Model):
"""Model that handle the search."""
rowid = models.IntegerField(primary_key=True)
object_id = models.IntegerField()
......@@ -68,16 +69,6 @@ class Search(models.Model):
class Meta:
abstract = True
@classmethod
def ids(cls, **kwargs):
qs = cls.objects.filter(**kwargs).order_by_relevancy()
return qs.values_list('object_id', flat=True)
@classmethod
def search(cls, **kwargs):
qs = cls.objects.filter(**kwargs).order_by_relevancy()
return (cls.model.objects.get(pk=r.object_id) for r in qs)
class MetaSearchMixin(MetaRegistry, ModelBase):
def __new__(cls, name, bases, attrs):
......@@ -100,7 +91,7 @@ class MetaSearchMixin(MetaRegistry, ModelBase):
Model = super().__new__(cls, name, bases, attrs)
SearchModel = type(
table_name,
(Search,),
(_Search,),
{
'__module__': module,
'Meta': search_meta,
......@@ -167,12 +158,16 @@ class SearchMixin(models.Model, metaclass=MetaSearchMixin):
class SearchableQuerySet(object):
def ids(self, **kwargs):
qs = self.model.SearchModel.objects.filter(**kwargs).order_by_relevancy()
return qs.values_list('object_id', flat=True)
def search(self, **kwargs):
ids = self.model.SearchModel.ids(**kwargs).distinct()
# Force the execution of the request here
# as we can request on several db in the same time.
ids = list(ids)
return self.filter(pk__in=ids)
ids = list(self.ids(**kwargs).distinct())
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(ids)])
return self.filter(pk__in=ids).order_by(preserved)
@receiver(post_save)
......
......@@ -23,7 +23,7 @@ def test_searchable_model_is_indexed():
assert Content.objects.count() == 0
content = ContentFactory(title="music")
assert Content.objects.count() == 1
assert content in Content.SearchModel.search(text__match="music")
assert content in Content.objects.search(text__match="music")
@pytest.mark.usefixtures('cleansearch')
......@@ -31,8 +31,8 @@ def test_search_Document_on_lang():
assert Document.objects.count() == 0
document = DocumentFactory(lang="FR")
assert Document.objects.count() == 1
assert document in Document.SearchModel.search(lang="FR")
assert document not in Document.SearchModel.search(lang="EN")
assert document in Document.objects.search(lang="FR")
assert document not in Document.objects.search(lang="EN")
@pytest.mark.usefixtures('cleansearch')
......@@ -40,8 +40,8 @@ def test_search_Document_on_kind():
assert Document.objects.count() == 0
document = DocumentFactory(kind="video")
assert Document.objects.count() == 1
assert document in Document.SearchModel.search(kind="video")
assert document not in Document.SearchModel.search(kind="pdf")
assert document in Document.objects.search(kind="video")
assert document not in Document.objects.search(kind="pdf")
@pytest.mark.usefixtures('cleansearch')
......@@ -51,11 +51,11 @@ def test_search_Document_on_tag():
document_no_tag = DocumentFactory()
assert Document.objects.count() == 2
assert document in Document.SearchModel.search(tags__match=["foo"])
assert document_no_tag not in Document.SearchModel.search(tags__match=["foo"])
assert document in Document.objects.search(tags__match=["foo"])
assert document_no_tag not in Document.objects.search(tags__match=["foo"])
assert document not in Document.SearchModel.search(tags__match=["bar"])
assert document_no_tag not in Document.SearchModel.search(tags__match=["bar"])
assert document not in Document.objects.search(tags__match=["bar"])
assert document_no_tag not in Document.objects.search(tags__match=["bar"])
@pytest.mark.usefixtures('cleansearch')
......@@ -65,8 +65,8 @@ def test_search_Document_on_no_tag():
document_no_tag = DocumentFactory()
assert Document.objects.count() == 2
assert document not in Document.SearchModel.search(tags__match=[])
assert document_no_tag in Document.SearchModel.search(tags__match=[])
assert document not in Document.objects.search(tags__match=[])
assert document_no_tag in Document.objects.search(tags__match=[])
@pytest.mark.usefixtures('cleansearch')
......@@ -78,24 +78,24 @@ def test_search_Document_multiple_tag():
doc = DocumentFactory()
for d in (doc_foo, doc_foo_bar, doc_bar_foo):
assert d in Document.SearchModel.search(tags__match=["foo"])
assert d in Document.objects.search(tags__match=["foo"])
for d in (doc, doc_bar):
assert d not in Document.SearchModel.search(tags__match=["foo"])
assert d not in Document.objects.search(tags__match=["foo"])
for d in (doc_bar, doc_foo_bar, doc_bar_foo):
assert d in Document.SearchModel.search(tags__match=["bar"])
assert d in Document.objects.search(tags__match=["bar"])
for d in (doc, doc_foo):
assert d not in Document.SearchModel.search(tags__match=["bar"])
assert d not in Document.objects.search(tags__match=["bar"])
for d in (doc_foo_bar, doc_bar_foo):
assert d in Document.SearchModel.search(tags__match=["bar", "foo"])
assert d in Document.objects.search(tags__match=["bar", "foo"])
for d in (doc, doc_foo, doc_bar):
assert d not in Document.SearchModel.search(tags__match=["bar", "foo"])
assert d not in Document.objects.search(tags__match=["bar", "foo"])
for d in (doc_foo_bar, doc_bar_foo):
assert d in Document.SearchModel.search(tags__match=["foo", "bar"])
assert d in Document.objects.search(tags__match=["foo", "bar"])
for d in (doc, doc_foo, doc_bar):
assert d not in Document.SearchModel.search(tags__match=["foo", "bar"])
assert d not in Document.objects.search(tags__match=["foo", "bar"])
@pytest.mark.usefixtures('cleansearch')
......@@ -103,11 +103,11 @@ def test_search_Document_on_tag_name_and_slug():
doc1 = DocumentFactory(tags=["aé"])
doc2 = DocumentFactory(tags=["ae"])
assert doc1 in Document.SearchModel.search(tags__match=["ae"])
assert doc2 in Document.SearchModel.search(tags__match=["ae"])
assert doc1 in Document.objects.search(tags__match=["ae"])
assert doc2 in Document.objects.search(tags__match=["ae"])
assert doc1 in Document.SearchModel.search(tags__match=["aé"])
assert doc2 not in Document.SearchModel.search(tags__match=["aé"])
assert doc1 in Document.objects.search(tags__match=["aé"])
assert doc2 not in Document.objects.search(tags__match=["aé"])
@pytest.mark.usefixtures('cleansearch')
......@@ -120,11 +120,11 @@ def test_search_Document_is_case_insensitive():
doc2 = DocumentFactory(tags=[sanitize_tag_name("AÉ")])
doc3 = DocumentFactory(tags=[sanitize_tag_name("Bar")])
assert sorted(Document.SearchModel.search(tags__match=["aé"]), key=attrgetter('id')) \
assert sorted(Document.objects.search(tags__match=["aé"]), key=attrgetter('id')) \
== [doc1, doc2]
assert sorted(Document.SearchModel.search(tags__match=["AÉ"]), key=attrgetter('id')) \
assert sorted(Document.objects.search(tags__match=["AÉ"]), key=attrgetter('id')) \
== [doc1, doc2]
assert doc3 in Document.SearchModel.search(tags__match=["baR"])
assert doc3 in Document.objects.search(tags__match=["baR"])
@pytest.mark.usefixtures('cleansearch')
......@@ -133,18 +133,18 @@ def test_more_relevant_should_come_first():
third = ContentFactory(title="About music")
first = ContentFactory(title="About music and music but also music")
assert Content.objects.count() == 3
assert first == list(Content.SearchModel.search(text__match="music"))[0]
assert second == list(Content.SearchModel.search(text__match="music"))[1]
assert third == list(Content.SearchModel.search(text__match="music"))[2]
assert first == list(Content.objects.search(text__match="music"))[0]
assert second == list(Content.objects.search(text__match="music"))[1]
assert third == list(Content.objects.search(text__match="music"))[2]
@pytest.mark.usefixtures('cleansearch')
def test_ids_only_returns_ids():
content = ContentFactory(title="music")
assert content.pk in Content.SearchModel.ids(text__match="music")
assert content.pk in Content.objects.ids(text__match="music")
@pytest.mark.usefixtures('cleansearch')
def test_we_can_search_on_non_fts_fields_only():
content = ContentFactory(title="music")
assert content in Content.SearchModel.search(public=False)
assert content in Content.objects.search(public=False)
......@@ -11,7 +11,7 @@ def search(request):
if not request.user.is_staff:
search_kwargs['public'] = True
for model in SearchMixin.registered_types.values():
results.extend(model.SearchModel.search(**search_kwargs))
results.extend(model.objects.search(**search_kwargs))
context = {
'results': results,
'q': query
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment