@@ -273,6 +273,52 @@ plone.pgcatalog's SQL query builder. Here is how it gets populated:
273273The registry is a module-level singleton. Once populated, it is used by both the
274274write path (` _extract_idx() ` ) and the read path (` build_query() ` ).
275275
276+ ### Runtime registration
277+
278+ Addons can register new indexes after startup -- either by calling
279+ ` catalog.addIndex("my_field", "FieldIndex") ` directly or, more commonly, via
280+ GenericSetup profile import (`` catalog.xml `` ). When ` addIndex() ` is called:
281+
282+ 1 . The index object is created and stored in ` _catalog.indexes ` (a
283+ ` PersistentMapping ` ), persisting it across restarts.
284+ 2 . The index's ` meta_type ` is looked up in ` META_TYPE_MAP ` . If found, the
285+ in-memory ` IndexRegistry ` singleton is updated immediately via
286+ ` registry.register() ` .
287+
288+ Similarly, ` addColumn() ` calls ` registry.add_metadata() ` inline.
289+
290+ ** What works immediately** (same transaction, no restart needed):
291+
292+ - ** Queries.** The query builder dispatches on the registry, so queries using
293+ the new index name work right away for standard types (FieldIndex,
294+ KeywordIndex, DateIndex, BooleanIndex, UUIDIndex, GopipIndex).
295+ - ** New writes.** ` extract_idx() ` iterates the registry, so any subsequent
296+ ` catalog_object() ` or ` reindexObject() ` extracts and stores the new index
297+ value in the ` idx ` JSONB.
298+
299+ ** What requires a Zope restart:**
300+
301+ - ** GIN expression indexes for TEXT types.** ` _ensure_text_indexes() ` only runs
302+ during the startup subscriber. A new ZCTextIndex added at runtime will not
303+ have a GIN index until the next restart. Queries still work (PG falls back
304+ to a sequential scan), just without GIN acceleration.
305+ - ** IPGIndexTranslator utilities for DRI / DRIRI.** ` _register_dri_translators() `
306+ and ` _register_driri_translators() ` only run at startup. A
307+ DateRecurringIndex or DateRangeInRangeIndex added at runtime will fall through
308+ to the generic JSONB containment fallback, which does not handle
309+ range/recurrence semantics.
310+
311+ ** What requires a manual reindex:**
312+
313+ - ** Existing objects.** Objects already in the catalog do not have the new field
314+ in their ` idx ` JSONB. A ` clearFindAndRebuild() ` or ` refreshCatalog() ` is
315+ needed to backfill. This matches ZCatalog's behavior -- adding a new index
316+ never auto-populates it.
317+
318+ ** No DDL needed** for standard indexes. Since all index data lives in the
319+ single ` idx ` JSONB column, no ` ALTER TABLE ` is required -- a key benefit of
320+ the JSONB design.
321+
276322## Base class architecture
277323
278324` PlonePGCatalogTool ` inherits from ` UniqueObject + Folder ` -- not from ZCatalog.
0 commit comments