Olá pessoal! Estou com outra dúvida de implementação que gostaria da opinião de vocês.
Estou implementando um novo framework de persistência de dados orientado a DML Relacional (por enquanto, batizado de RelationalDao), ou seja: algo bem parecido à linguagem DML (select, update, delete, insert). (Nota: não quero discutir sobre utilidade deste ou sobre diferenças com outros frameworks de mercado).
Para ilustrar um exemplo de uso do RelationalDao para select:
Dada a tabela: Clients(id integer, name varchar2(100))
Eu tenho um objeto DbTable para representar essa tabela, chamado ClientsTable.
E um bean para representar os registros dessa tabela, chamado Clients.
Assim, posso efetuar um select simples com o seguinte comando:
import static extensions.util.db.relationaldao.standard92.StatementFactory.select;
...
SelectStatement stm = select(table.id, table.name).from(table);
Rows rows = stm.run(this.conn);
for (Row row : rows.rows()) {
Clients clients = row.get(table);
System.out.println("Nome: "+clients.getName());
}Toda a estrutura dos comandos DML estão prontas e funcionando, porém não há restrição nenhuma da ordem ou leque de opções para se montar um select. Assim, eu poderia montar algo assim em tempo de programação:
select(table.id, table.name).orderBy(table.id).from(table)E isso não faz nenhum sentido, mas funcionaria.
O problema maior seria em joins, que eu poderia colocar os ONs separados dos joins e sem ordem específica, causando confusão.
Outro problema que vejo é aparecer muitas opções para o programador qdo pressionado ctrl+espaço.
Eu gostaria de algo mais limpo para se trabalhar, com apenas as opções válidas em cada etapa da criação do select.
Com os itens acima em mente, sabemos que um select pode ter várias opções, algumas obrigatórias, outras não. Por ex:
[list]é obrigatório utilizar from[/list]
[list]é opcional utilizar where, orderBy, having, innerJoin, etc.[/list]
[list]é obrigatório utilizar on sempre após algum join, etc.[/list]
Como mostrado abaixo:
SELECT [DISTINCT] select_list
FROM table_list
[WHERE conditions]
[[INNER|LEFT|RIGHT]JOIN table ON conditions]
[GROUP BY group_by_list]
[HAVING search_conditions]
[ORDER BY order_list [ASC | DESC] ]
Então, pensando em diferentes abordagens, a que eu achei que ficaria melhor é utilizar a restrição de opções por interfaces específicas. Desta forma, o objeto SelectStatement seria “explodido” em vários objetos menores, um para cada função do select e cada método retornaria uma interface para um conjunto de opções válidas subsequentes. Ex:
class StatementFactory{
public static SelectOptions select(...){...}
...
}interface SelectOptions {
FromOptions from(...)
}interface StatementOptions{
SelectStatement getStatement();
}interface OrderByOptions extends StatementOptions{
}interface HavingOptions extends OrderByOptions {
OrderByOptions orderBy(...)
}interface GroupByOptions extends HavingOptions {
HavingOptions having(...)
}interface JoinOptions {
WhereOptions on(...)
}interface WhereOptions extends HavingOptions {
JoinOptions innerJoin(...)
JoinOptions leftJoin(...)
...
}interface FromOptions extends WhereOptions {
WhereOptions where(...)
...
}
Gostaria da opinião de vocês quanto a solução, se vcs conhecem alguma forma melhor de fazer isso ou se há alguma outra idéia p/ me ajudar no problema.
Grato, e feliz ano novo a todos!