Tenho trabalhado em um aplicativo de servlet Java que precisa construir instruções SQL muito dinâmicas para fins de relatório ad hoc. A função básica do aplicativo é alimentar vários parâmetros de solicitação HTTP nomeados em uma consulta pré-codificada e gerar uma tabela de saída bem formatada. Usei Spring MVC e a estrutura de injeção de dependência para armazenar todas as minhas consultas SQL em arquivos XML e carregá-los no aplicativo de relatório, junto com as informações de formatação da tabela. Eventualmente, os requisitos de relatório tornaram-se mais complicados do que os recursos das estruturas de mapeamento de parâmetros existentes e tive que escrever o meu próprio. Foi um exercício interessante de desenvolvimento e produziu uma estrutura para mapeamento de parâmetros muito mais robusta do que qualquer outra coisa que pude encontrar.
Os novos mapeamentos de parâmetros eram assim:
select app.name as "App",
${optional(" app.owner as "Owner", "):showOwner}
sv.name as "Server", sum(act.trans_ct) as "Trans"
from activity_records act, servers sv, applications app
where act.server_id = sv.id
and act.app_id = app.id
and sv.id = ${integer(0,50):serverId}
and app.id in ${integerList(50):appId}
group by app.name, ${optional(" app.owner, "):showOwner} sv.name
order by app.name, sv.name
A beleza da estrutura resultante era que ela podia processar parâmetros de solicitação HTTP diretamente na consulta com verificação de tipo e verificação de limite adequadas. Nenhum mapeamento extra necessário para validação de entrada. Na consulta de exemplo acima, o parâmetro denominado serverId
seria verificado para garantir que pudesse ser convertido em um número inteiro e estivesse no intervalo de 0-50. O parâmetro appId seria processado como uma matriz de inteiros, com um limite de comprimento de 50. Se o campo showOwnerestiver presente e definido como "verdadeiro", os bits de SQL nas aspas serão adicionados à consulta gerada para os mapeamentos de campo opcionais. field Vários outros mapeamentos de tipo de parâmetro estão disponíveis, incluindo segmentos opcionais de SQL com outros mapeamentos de parâmetro. Ele permite um mapeamento de consulta tão complexo quanto o desenvolvedor pode criar. Ele ainda possui controles na configuração do relatório para determinar se uma determinada consulta terá os mapeamentos finais por meio de um PreparedStatement ou simplesmente será executada como uma consulta pré-construída.
Para os valores de solicitação Http de amostra:
showOwner: true
serverId: 20
appId: 1,2,3,5,7,11,13
Isso produziria o seguinte SQL:
select app.name as "App",
app.owner as "Owner",
sv.name as "Server", sum(act.trans_ct) as "Trans"
from activity_records act, servers sv, applications app
where act.server_id = sv.id
and act.app_id = app.id
and sv.id = 20
and app.id in (1,2,3,5,7,11,13)
group by app.name, app.owner, sv.name
order by app.name, sv.name
Eu realmente acho que Spring ou Hibernate ou um desses frameworks deveriam oferecer um mecanismo de mapeamento mais robusto que verifica tipos, permite tipos de dados complexos como arrays e outros recursos. Eu escrevi meu motor apenas para meus propósitos, ele não foi totalmente lido para lançamento geral. Ele só funciona com consultas Oracle no momento e todo o código pertence a uma grande corporação. Algum dia, posso pegar minhas ideias e construir uma nova estrutura de código aberto, mas espero que um dos grandes jogadores existentes aceite o desafio.