Dans l'un de mes emplois précédents, j'ai fait quelque chose de similaire :j'ai obtenu une requête (pas un sql, mais assez similaire) et je l'ai traduite en requête mongo avec antlr.
Je n'ai pas de code à partager, mais je peux partager mes réflexions :
-
Mongo n'est pas conforme à SQL, vous ne pouvez donc pas simplement prendre une grammaire SQL. Qu'en est-il des JOIN et de toute l'algèbre relationnelle ? Qu'en est-il des agrégations qui sont assez délicates dans mongo avec leur cadre d'agrégation ? Dans le sens opposé, comment générer du SQL qui est traduit en clause "existe" dans mongo. Il y a beaucoup de choses comme ça, certaines sont petites, d'autres sont énormes, mais en fin de compte, vous devez parler d'une sorte de sous-ensemble de sql, un DSL qui est autorisé à être utilisé comme langage de requête et ressemble "à" un sql parce que les gens sont habitués à SQL.
-
Dans cet esprit, vous devez créer votre propre grammaire et Antlr générera un lexer/analyseur pour vous. Vous obtiendrez également une vérification de la syntaxe de la requête dans le Runtime. Antlr ne pourra pas analyser la requête si elle n'est pas dans un format correct, évidemment, certaines règles de grammaire échoueront. C'est une autre raison de ne pas prendre SQL "tel quel".
-
Jusqu'ici tout va bien, vous avez créé votre propre auditeur/visiteur. Dans mon cas, j'ai opté pour la création d'une représentation objet de la requête avec l'état interne et tout. Donc la requête
Select id,name
from employee
where age > 30
and department = 'IT'
limit 200
A été traduit en objets de type :
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
}
Pour cette requête particulière, c'est quelque chose comme :
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));
Ensuite, il est possible de faire quelques optimisations dans la requête (comme l'intégration de clauses where si vous en avez besoin, ou, par exemple, la manipulation de la partie "For" si vous travaillez dans un environnement multi-locataires et que vous avez différentes collections pour différents locataires).
Après tout, vous pouvez utiliser le modèle de conception "interpréteur" et analyser récursivement les objets de requête et les "traduire" en requête mongo valide. Je me souviens que cette étape m'a pris environ 1 jour à accomplir (il y a 7 ans avec mongo 2 I devinez, mais quand même), étant donné la structure correcte des objets représentant la requête, cela ne devrait donc pas être si compliqué. J'en parle, car il semble que ce soit votre principale préoccupation dans la question.