diff --git a/.gitignore b/.gitignore index a3ce90a..c722626 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea/ +.vscode/ *.egg-info/ *.pyc *.coverage diff --git a/postgres_searchindex/management/commands/_utils.py b/postgres_searchindex/management/commands/_utils.py new file mode 100644 index 0000000..9fe0974 --- /dev/null +++ b/postgres_searchindex/management/commands/_utils.py @@ -0,0 +1,40 @@ +import sys + +from django.contrib.contenttypes.models import ContentType + +from postgres_searchindex import conf +from postgres_searchindex.models import IndexEntry +from postgres_searchindex.source_pool import source_pool + + +def delete_indexes(): + IndexEntry.objects.all().delete() + + +def update_indexes(): + for index_key, index in conf.POSTGRES_SEARCHINDEX.items(): + sys.stdout.write("====================================") + sys.stdout.write( + f"Updating index \"{index_key}\" with kwargs {index.get('kwargs', {})}" + ) + for source_cls in source_pool.get_sources().values(): + source = source_cls(**index.get("kwargs", {})) + sys.stdout.write( + f"{source.model.__name__}. " + f"Indexing {source.get_queryset().count()} entries" + ) + # index + current_ids = [] + for obj in source.get_queryset(): + source.update(index_key, obj) + current_ids.append(obj.id) + # remove no more existing + content_type = ContentType.objects.get_for_model(source.model) + to_delete = IndexEntry.objects.filter( + index_key=index_key, + content_type=content_type, + ).exclude( + object_id__in=current_ids, + ) + delete_result = to_delete.delete() + sys.stdout.write(f"> Done. Removed from index: {delete_result[0]}") \ No newline at end of file diff --git a/postgres_searchindex/management/commands/postgres_searchindex_rebuild.py b/postgres_searchindex/management/commands/postgres_searchindex_rebuild.py index 66077f5..67f8d01 100644 --- a/postgres_searchindex/management/commands/postgres_searchindex_rebuild.py +++ b/postgres_searchindex/management/commands/postgres_searchindex_rebuild.py @@ -1,8 +1,31 @@ +# commands/reindex_indexes.py from django.core.management import BaseCommand - +from ._utils import delete_indexes, update_indexes class Command(BaseCommand): - help = "Try send something to Sentry!" + help = "Reindexing postgres " + + def add_arguments(self, parser): + parser.add_argument( + '--force', + action='store_true', + help='Force reindex without confirmation' + ) def handle(self, *args, **options): - pass + if not options['force']: + self.stdout.write(self.style.WARNING( + "This will delete all indexes and reindex them." + " Are you sure you want to proceed?" + )) + + confirmation = input("Type 'yes' to continue: ") + + if confirmation.lower() != 'yes': + self.stdout.write(self.style.ERROR("Reindexing aborted.")) + return + + self.stdout.write(self.style.SUCCESS("Starting the reindexing process...")) + delete_indexes() + update_indexes() + self.stdout.write(self.style.SUCCESS("Reindexing completed successfully!")) diff --git a/postgres_searchindex/management/commands/postgres_searchindex_update.py b/postgres_searchindex/management/commands/postgres_searchindex_update.py index 6651560..3b50a60 100644 --- a/postgres_searchindex/management/commands/postgres_searchindex_update.py +++ b/postgres_searchindex/management/commands/postgres_searchindex_update.py @@ -1,38 +1,10 @@ -from django.contrib.contenttypes.models import ContentType from django.core.management import BaseCommand -from postgres_searchindex import conf -from postgres_searchindex.models import IndexEntry -from postgres_searchindex.source_pool import source_pool +from ._utils import update_indexes class Command(BaseCommand): help = "Update/build index" def handle(self, *args, **options): - for index_key, index in conf.POSTGRES_SEARCHINDEX.items(): - self.stdout.write("====================================") - self.stdout.write( - f"Updating index \"{index_key}\" with kwargs {index.get('kwargs', {})}" - ) - for source_cls in source_pool.get_sources().values(): - source = source_cls(**index.get("kwargs", {})) - self.stdout.write( - f"{source.model.__name__}. " - f"Indexing {source.get_queryset().count()} entries" - ) - # index - current_ids = [] - for obj in source.get_queryset(): - source.update(index_key, obj) - current_ids.append(obj.id) - # remove no more existing - content_type = ContentType.objects.get_for_model(source.model) - to_delete = IndexEntry.objects.filter( - index_key=index_key, - content_type=content_type, - ).exclude( - object_id__in=current_ids, - ) - delete_result = to_delete.delete() - self.stdout.write(f"> Done. Removed from index: {delete_result[0]}") + update_indexes() diff --git a/postgres_searchindex/tests/test_indexing.py b/postgres_searchindex/tests/test_indexing.py index 64b9caa..4dc95de 100644 --- a/postgres_searchindex/tests/test_indexing.py +++ b/postgres_searchindex/tests/test_indexing.py @@ -16,13 +16,19 @@ def setUp(self): def tearDown(self): pass - def test_indexing(self): + def test_rebuild_index(self): + call_command("postgres_searchindex_rebuild", "--force") + qs = IndexEntry.objects.all() + self.assertEqual(qs.count(), 2) + self.assertEqual(qs.filter(title__contains="One").count(), 1) + + def test_update_index(self): call_command("postgres_searchindex_update") qs = IndexEntry.objects.all() self.assertEqual(qs.count(), 2) self.assertEqual(qs.filter(title__contains="One").count(), 1) - def test_indexing_unpublish(self): + def test_update_index_unpublish(self): """ unpublishing something requires index update """ @@ -35,7 +41,7 @@ def test_indexing_unpublish(self): self.assertEqual(qs.count(), 1) self.assertEqual(qs.filter(title__contains="One").count(), 0) - def test_indexing_deletion(self): + def test_update_index_deletion(self): """ generic relations do cascade deletion """