feat(14-01): beachcomber DropIndex and EnsureIndex for reindex tooling

- optional IndexDropper reports whether a dropped index existed; DropIndex falls back to Flush
- optional IndexEnsurer creates an empty index from its schema; EnsureIndex is a no-op otherwise
- typesense implements both (404 is already absent; ensure reuses collection creation)
This commit is contained in:
Jakub Zych
2026-10-03 20:01:36 +02:00
parent 7241704e93
commit 58e6324da8
6 changed files with 214 additions and 1 deletions

View File

@@ -106,6 +106,43 @@ func SearchPage(ctx context.Context, e Engine, index string, q Query) (SearchRes
return SearchResult{IDs: ids, Found: len(ids)}, nil
}
// IndexDropper is implemented by an engine that can tell whether the index
// it dropped existed. It is optional; use DropIndex to call it.
type IndexDropper interface {
DropIndex(ctx context.Context, index string) (existed bool, err error)
}
// DropIndex drops index on e and reports whether it existed: through
// IndexDropper when e implements it, otherwise through Flush, in which case
// it reports existed true because Flush cannot tell.
func DropIndex(ctx context.Context, e Engine, index string) (bool, error) {
if d, ok := e.(IndexDropper); ok {
return d.DropIndex(ctx, index)
}
if err := e.Flush(ctx, index); err != nil {
return false, err
}
return true, nil
}
// IndexEnsurer is implemented by an engine that can create an empty index
// from its schema. It is optional; use EnsureIndex to call it.
type IndexEnsurer interface {
EnsureIndex(ctx context.Context, index string, schema map[string]any) error
}
// EnsureIndex creates index on e from schema when it does not exist yet,
// through IndexEnsurer when e implements it; for other engines it does
// nothing. A full reindex calls it first so an empty source table still
// leaves an (empty) index behind, because Upsert of zero documents creates
// nothing.
func EnsureIndex(ctx context.Context, e Engine, index string, schema map[string]any) error {
if en, ok := e.(IndexEnsurer); ok {
return en.EnsureIndex(ctx, index, schema)
}
return nil
}
// Gate is the application kill-switch consulted before every sync. It
// reads its setting through db, a clean session on the write's connection
// (inside a caller's plain transaction, a savepoint of it); any error must