Em um dos meus trabalhos anteriores, fiz algo semelhante:peguei uma consulta (não um sql, mas bastante semelhante) e traduzi para a consulta mongo com antlr.
Não tenho um código para compartilhar, mas posso compartilhar meus pensamentos:
-
Mongo não é compatível com SQL, então você não pode simplesmente usar uma gramática sql. E quanto aos JOINs e toda a álgebra relacional? E quanto às agregações que são bastante complicadas no mongo com sua estrutura de agregação? Na direção oposta, como você gera SQL que é traduzido para a cláusula "exists" no mongo. Existem muitas coisas assim, algumas são pequenas, algumas são enormes, mas no final das contas você deve estar falando sobre algum tipo de subconjunto de sql ,algum DSL que pode ser usado como uma linguagem de consulta e se parece com um sql porque as pessoas estão acostumadas com SQL.
-
Com isso em mente, você deve criar sua própria gramática e o Antlr gerará um lexer/parser para você. Você também terá como garantida uma verificação de sintaxe da consulta no Runtime. O Antlr não poderá analisar a consulta se não estiver em um formato correto, obviamente, alguma regra gramatical falhará. Esta é outra razão para não aceitar o SQL "como está".
-
Até aí tudo bem, você criou seu próprio ouvinte/visitante. No meu caso optei por criar uma representação de objeto da consulta com estado interno e tudo.
Select id,name
from employee
where age > 30
and department = 'IT'
limit 200
Foi traduzido para objetos do tipo:
class Query {
private SelectClause select;
private FromClause from;
private WhereClause where;
private Limit limit;
}
class SelectClause {
private List<String> fields;
}
...
class WhereClause {
Condition root;
}
interface Condition {
...
}
class AndCondition implements Condition { // the same for Not, Or
}
Para esta consulta específica é algo como:
Query q = new Query(new SelectClause(["id", "name"]), new FromClause("employee"), new WhereClause(new AndCondition(new SimpleLeafCondition("age", Operators.GT, 30), new SimpleLeafCondition("department", Operators.EQ, "IT" )), new Limit(30));
Então é possível fazer algumas otimizações na consulta (como a incorporação de cláusulas where se você precisar, ou, por exemplo, manipular a parte "For" se você estiver trabalhando em ambiente multi-inquilino e tiver coleções diferentes para diferentes inquilinos).
Afinal, você pode usar o "interpretador" de padrão de design e analisar recursivamente os objetos de consulta e "traduzi-los" para uma consulta mongo válida. adivinhar, mas ainda assim), dada a estrutura correta de objetos que representam a consulta, isso não deve ser tão complicado. Estou trazendo isso à tona, porque parece que é sua principal preocupação na questão.