In einem meiner vorherigen Jobs habe ich etwas Ähnliches gemacht:Ich habe eine Abfrage bekommen (keine SQL, aber ziemlich ähnlich) und sie mit Antlr in eine Mongo-Abfrage übersetzt.
Ich habe keinen Code zum Teilen, aber ich kann meine Gedanken teilen:
-
Mongo ist nicht SQL-kompatibel, Sie können also nicht einfach eine SQL-Grammatik nehmen. Was ist mit JOINs und all der relationalen Algebra? Was ist mit Aggregationen, die in Mongo mit ihrem Aggregations-Framework ziemlich knifflig sind? Wie generieren Sie in umgekehrter Richtung SQL, das in Mongo in die Klausel "exists" übersetzt wird? Es gibt viele Dinge wie diese, einige sind klein, andere sind riesig, aber unterm Strich müssen Sie über eine Art Teilmenge von SQL sprechen, einige DSL, die als Abfragesprache verwendet werden dürfen und "wie" eine SQL aussehen, weil Menschen sind an SQL gewöhnt.
-
In diesem Sinne sollten Sie Ihre eigene Grammatik erstellen und Antlr wird einen Lexer/Parser für Sie generieren. Selbstverständlich erhalten Sie auch eine Syntaxprüfung der Abfrage zur Runtime. Antlr kann die Abfrage nicht analysieren, wenn sie offensichtlich nicht im richtigen Format vorliegt, da einige Grammatikregeln fehlschlagen. Dies ist ein weiterer Grund, SQL nicht "wie es ist" zu nehmen.
-
So weit so gut, Sie haben Ihren eigenen Zuhörer/Besucher erstellt. In meinem Fall habe ich mich dafür entschieden, eine Objektdarstellung der Abfrage mit internem Status und allem zu erstellen. Also die Abfrage
Select id,name
from employee
where age > 30
and department = 'IT'
limit 200
Wurde in Objekte des Typs übersetzt:
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
}
Für diese spezielle Abfrage ist es etwa so:
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));
Dann ist es möglich, einige Optimierungen in der Abfrage vorzunehmen (wie das Einbetten von Where-Klauseln, falls erforderlich, oder beispielsweise das Manipulieren des „For“-Teils, wenn Sie in einer Multi-Tenant-Umgebung arbeiten und unterschiedliche Sammlungen für verschiedene Tenants haben).
Schließlich können Sie mit dem Entwurfsmuster "Interpreter" gehen und die Abfrageobjekte rekursiv analysieren und in eine gültige Mongo-Abfrage "übersetzen". Ich erinnere mich, dass ich für diesen Schritt etwa einen Tag benötigt habe (es war vor 7 Jahren mit Mongo 2 I raten, aber trotzdem), angesichts der korrekten Struktur der Objekte, die die Abfrage darstellen, sollte dies also nicht so kompliziert sein. Ich spreche das an, weil es so aussieht, als wäre es Ihr Hauptanliegen in der Frage.