Repository navigation
Make exists() a read-only check - #39
Merged
ryanmitchell merged 2 commits intoOct 8, 2026
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
Index::exists()calledgetOrCreateIndex(), so it created the collection it was asked to check and then reportedtrue. Core'sensureExists()andSearch::updateWithinIndexes()both rely onexists()to notice a missing index and callupdate(). Since it was never false, a collection that had gone missing (a Typesense restart with an empty data dir, say) was quietly recreated empty and treated as ready. Searches returned nothing, and nothing errored or logged.The fix
Follows the approach Duncan laid out in #36:
exists()is a read-only check, matching the Comb and Algolia drivers in core, and onlyupdate()andinsertDocuments()create the collection.exists()asks the client's memoisedCollection::exists()and nothing else. On v6 the rebuildensureExists()then triggers is queued per chunk by core'sinsertMultiple(), andupdate()creates the collection up front, so only the first save or search after a wipe starts a rebuild.delete()anddeleteIndex()no-op when the collection is missing instead of creating it first.searchUsingApi()returns empty results for a missing collection rather than creating it, same as a search against an index that's still being built.getTypesenseSchemaFields()andgetCount()also went throughgetOrCreateIndex().Querycalls the former on every search, so these are read-only too or the collection would be recreated through the back door.A private
collection()accessor returns the client's cachedCollectionfor the index name without any HTTP, and the read paths use it in place ofgetOrCreateIndex().Tests
tests/Unit/ExistsTest.phpmocksApiCallso each test asserts on the requests made, with no Typesense server needed. Six of the eight fail onmainbecausePOST /collectionsfires where it shouldn't. The mocked-client helper the existing tests duplicated has moved toTestCase.Closes #36