From a6f3feca0979a33571463da0a958078d7f65d939 Mon Sep 17 00:00:00 2001
From: Andy Waite <13400+andyw8@users.noreply.github.com>
Date: Sat, 16 Nov 2024 21:40:04 -0600
Subject: [PATCH] Prevent `index_all` being called multiple times

---
 lib/ruby_indexer/lib/ruby_indexer/index.rb | 9 +++++++++
 lib/ruby_indexer/test/index_test.rb        | 7 +++++++
 2 files changed, 16 insertions(+)

diff --git a/lib/ruby_indexer/lib/ruby_indexer/index.rb b/lib/ruby_indexer/lib/ruby_indexer/index.rb
index 7effc5b77f..180d03798b 100644
--- a/lib/ruby_indexer/lib/ruby_indexer/index.rb
+++ b/lib/ruby_indexer/lib/ruby_indexer/index.rb
@@ -7,6 +7,7 @@ class Index
 
     class UnresolvableAliasError < StandardError; end
     class NonExistingNamespaceError < StandardError; end
+    class IndexNotEmptyError < StandardError; end
 
     # The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query
     ENTRY_SIMILARITY_THRESHOLD = 0.7
@@ -360,6 +361,14 @@ def resolve(name, nesting, seen_names = [])
       ).void
     end
     def index_all(indexable_paths: @configuration.indexables, &block)
+      # When troubleshooting an indexing issue, e.g. through irb, it's not obvious that `index_all` will augment the
+      # existing index values, meaning it may contain 'stale' entries. This check ensures that the user is aware of this
+      # behavior and can take appropriate action.
+      # binding.break
+      if @entries.any?
+        raise IndexNotEmptyError, "The index is not empty. Create a new instance before re-indexing"
+      end
+
       RBSIndexer.new(self).index_ruby_core
       # Calculate how many paths are worth 1% of progress
       progress_step = (indexable_paths.length / 100.0).ceil
diff --git a/lib/ruby_indexer/test/index_test.rb b/lib/ruby_indexer/test/index_test.rb
index c83d3b0e64..2723edc0a8 100644
--- a/lib/ruby_indexer/test/index_test.rb
+++ b/lib/ruby_indexer/test/index_test.rb
@@ -2023,5 +2023,12 @@ def test_build_non_redundant_name
         ),
       )
     end
+
+    def test_prevents_multiple_calls_to_index_all
+      # For this test class, `index_all` is already called once in `setup`.
+      assert_raises(Index::IndexNotEmptyError) do
+        @index.index_all
+      end
+    end
   end
 end