Skip to content

Widen AbstractIndexingAdvice type bound to admit BaseOpenmrsMetadata #16

Description

@dkayiwa

Problem

AbstractIndexingAdvice<T extends BaseOpenmrsData> (querystore-api org.openmrs.module.querystore.bridge.AbstractIndexingAdvice) constrains the generic type parameter to BaseOpenmrsData. This rules out indexing any entity that extends BaseOpenmrsMetadata or BaseChangeableOpenmrsMetadata — i.e., catalog and reference data.

In practice this shuts out a broad class of legitimate search targets:

  • BillableService (the billing module's service catalog — concrete pain point we hit; we had to drop catalog indexing entirely)
  • PaymentMode, CashPoint, BillableServicePrice
  • Drug, OrderType, LocationTag, and presumably similar catalog types in other modules

The serializer SPI (AbstractRecordSerializer<T>) has no such bound. Only the advice does, and only because it relies on BaseOpenmrsData.getVoided() to route voided entities through the delete path (the per-node voided policy).

What we tried

In the billing module's querystore slice we built a full BillableServiceRecordSerializer + BillableServiceIndexingAdvice + BillableServiceResourceTypeProvider, then deleted them when the type bound surfaced at compile time. Catalog search ("find every Lab-department service") remains unaddressed and there's no workaround within the existing SPI.

Suggested approach

Two reasonable shapes:

  1. Split the abstract. AbstractDataIndexingAdvice<T extends BaseOpenmrsData> for the current behavior, plus AbstractMetadataIndexingAdvice<T extends BaseOpenmrsMetadata> that routes retired entities through the delete path instead of voided. Slight code duplication, clean type system.

  2. Widen to OpenmrsObject. Drop the bound, replace entity.getVoided() with a strategy hook (protected boolean isInactive(T entity)) that data subclasses implement as getVoided() and metadata subclasses implement as getRetired(). Less duplication, slightly more contract for subclasses.

Either way, the document writes / SPI surface / consumer queries don't change — only the advice's type constraint.

Failure mode prevented

Without this, every module with catalog search needs (billing, stockmanagement, FHIR, formentry…) hand-rolls its own index outside the querystore, fragmenting the search surface that querystore exists to centralize.

Surfaced during a billing module slice that adds Bill / BillRefund / BillDiscount / Timesheet to the querystore. See openmrs/openmrs-module-billing#176 (the ADR) for the full context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions