Options (id/label) e option-sources

Options (id/label) e option-sources

Guia canonico para publicar selects metadata-driven no praxis-metadata-starter.

Contrato publico

Endpoints canonicos:

Forma publica de retorno:

Quando usar cada superficie

Regra pratica:

Definindo o label de options do proprio recurso

public class Funcionario {
  @Id
  private Long id;

  @OptionLabel
  private String nomeCompleto;
}

Se nao houver anotacao, o framework aplica heuristicas como getLabel, getNomeCompleto e getNome.

Registrando option-sources no service

option-sources vem do OptionSourceRegistry exposto pelo service.

private static final OptionSourceRegistry OPTION_SOURCES = OptionSourceRegistry.builder()
    .add(VwAnalyticsFolhaPagamento.class, new OptionSourceDescriptor(
        "payrollProfile",
        OptionSourceType.DISTINCT_DIMENSION,
        ApiPaths.HumanResources.VW_ANALYTICS_FOLHA_PAGAMENTO,
        "payrollProfile",
        "payrollProfile",
        "payrollProfile",
        "payrollProfile",
        List.of("competenciaBetween", "universo"),
        new OptionSourcePolicy(true, true, "contains", 0, 25, 100, true, false, "label")
    ))
    .build();

@Override
public OptionSourceRegistry getOptionSourceRegistry() {
    return OPTION_SOURCES;
}

O que vai para o schema em /schemas/filtered

Quando o ApiDocsController encontra um campo cujo nome coincide com a source registrada para o resourcePath, ele enriquece o schema com x-ui.optionSource.

Importante:

Como o Angular consome isso

O praxis-ui-angular ja tem consumo explicito para option-sources.

Fluxo real:

Suporte atual e limites

Cobertura confirmada hoje:

Execucao atualmente implementada no starter:

Tipos ainda nao implementados de ponta a ponta no executor JPA:

Boas praticas

Troubleshooting e Debugging

Problemas Comuns e Soluções

Como Testar Manualmente

Use ferramentas como Postman ou curl para testar endpoints:

Logs Úteis

Exemplos Avançados

Integrando com StatsFieldRegistry

Para DISTINCT_DIMENSION, o executor pode usar StatsFieldRegistry como backend:

// No service, registre no StatsFieldRegistry primeiro
statsFieldRegistry.register(VwAnalyticsFolhaPagamento.class, "universo");

// Depois, no OptionSourceRegistry
OptionSourceDescriptor descriptor = new OptionSourceDescriptor(
    "universo",
    OptionSourceType.DISTINCT_DIMENSION,
    // ... outros campos
);

Isso permite reaproveitar lógica de stats para options.

Customizando OptionDTO com Extra

Para adicionar metadados (ex.: count de ocorrências):

// No service, sobrescreva filterOptionSourceOptions
@Override
public Page<OptionDTO> filterOptionSourceOptions(String sourceKey, GenericFilterDTO filter, Pageable pageable) {
    // Lógica customizada
    return options.map(option -> option.withExtra(Map.of("count", 42)));
}

Migrando de Endpoint Legado

Campo antigo:

{
  "campo": {
    "endpoint": "/options/filter",
    "valueField": "id",
    "displayField": "label"
  }
}

Novo com OptionSource:

{
  "campo": {
    "x-ui.optionSource": {
      "key": "campo",
      "type": "RESOURCE_ENTITY",
      "resourcePath": "/api/campo"
    }
  }
}

Durante transição, publique ambos para compatibilidade.