Ich arbeite an einer Abfrageabstraktion über die WebSQL / Phonegap-Datenbank-API, und ich bin sowohl davon überzeugt als auch bezweifelt, eine fließende API zu definieren, die die Verwendung der Grammatik in natürlicher englischer Sprache imitiert.
Dies lässt sich am einfachsten anhand von Beispielen erklären. Das Folgende sind alle gültigen Abfragen in meiner Grammatik und Kommentare erklären die beabsichtigte Semantik:
//find user where name equals "foo" or email starts with "foo@"
find("user").where("name").equals("foo").and("email").startsWith("foo@")
//find user where name equals "foo" or "bar"
find("user").where("name").equals("foo").or("bar");
//find user where name equals "foo" or ends with "bar"
find("user").where("name").equals("foo").or().endsWith("bar");
//find user where name equals or ends with "foo"
find("user").where("name").equals().or().endsWith("foo");
//find user where name equals "foo" and email is not like "%contoso.com"
find("user").where("name").equals("foo").and("email").is().not().like("%contoso.com");
//where name is not null
find("user").where("name").is().not().null();
//find post where author is "foo" and id is in (1,2,3)
find("post").where("author").is("foo").and("id").is().in(1, 2, 3);
//find post where id is between 1 and 100
find("post").where("id").is().between(1).and(100);
Edit basierend auf dem Feedback von Quentin Pradet : Außerdem müsste die API anscheinend sowohl Plural- als auch Singular-Verbformen unterstützen.
//a equals b
find("post").where("foo").equals(1);
//a and b (both) equal c
find("post").where("foo").and("bar").equal(2);
Um der Frage willen nehmen wir an, dass ich hier nicht alle möglichen Konstrukte ausgeschöpft habe. Nehmen wir auch an, dass ich die meisten korrekten englischen Sätze abdecken kann - schließlich ist die Grammatik selbst auf die von SQL definierten Verben und Konjunktionen beschränkt.
Bearbeiten hinsichtlich der Gruppierung : Ein "Satz" ist eine Gruppe, und die Rangfolge ist wie in SQL definiert: von links nach rechts. Mehrere Gruppierungen können mit mehreren where
Anweisungen ausgedrückt werden :
//the conjunctive "and()" between where statements is optional
find("post")
.where("foo").and("bar").equal(2).and()
.where("baz").isLessThan(5);
Wie Sie sehen, hängt die Definition jeder Methode vom grammatikalischen Kontext ab, in dem sie sich befindet. Zum Beispiel das Argument für "Konjunktionsmethoden" or()
und and()
kann entweder weggelassen werden oder auf einen Feldnamen oder einen erwarteten Wert verweisen .
Für mich fühlt sich das sehr intuitiv an, aber ich möchte, dass Sie Ihr Feedback hören: Ist dies eine gute, nützliche API, oder sollte ich zu einer geradlinigeren Implementierung zurückkehren?
Um es festzuhalten: Diese Bibliothek bietet auch eine konventionellere, nicht fließende API, die auf Konfigurationsobjekten basiert.
quelle
... where foo = 1 or (bar = 2 and qux = 3)
:?where("name").equals("foo").or("bar")
als(name=="foo")or bar
. Dann ist es nicht klar, wann ein String ein Literal repräsentiert und wann er einen Spaltennamen präsentiert, ...Antworten:
Ich denke es ist sehr falsch. Ich lerne natürliche Sprache und sie ist voller Mehrdeutigkeiten, die nur mit Kontext und viel menschlichem Wissen gelöst werden können. Die Tatsache, dass Programmiersprachen nicht mehrdeutig sind, ist eine sehr gute Sache! Ich glaube nicht, dass Sie die Bedeutung von Methoden je nach Kontext ändern möchten:
find("user").where("name").and("email").equals("foo");
find("user").where("name").not().is().null();
?Nein, die meisten korrekten englischen Sätze können nicht abgedeckt werden. Andere haben es bereits versucht, und es wird sehr schnell sehr kompliziert. Es heißt natürliches Sprachverständnis, aber das versucht niemand wirklich: Wir versuchen zuerst, kleinere Probleme zu lösen. Für Ihre Bibliothek haben Sie grundsätzlich zwei Möglichkeiten:
quelle
is()
oderequal()
nurequals()
. Ihr Problem mit dem Melden von Fehlern wird danach nicht mehr angezeigt.null()
würde auch ein Literal zum Vergleichen werden, anstatt eine Syntaxfunktion.find("user").where("name").is().not().null();
wirdfind("user").where("name").not().equals(null);
Ich stimme den Beiträgen anderer eher zu, dass dies kein großartiges Design ist. Ich glaube jedoch, dass ich verschiedene Gründe habe.
Sie präsentieren, was ich als konkrete Syntax für SQL-Abfragen betrachte. Ich bin der festen Überzeugung, dass eine konkrete Syntax einer Sprache niemals helfen kann, sondern nur schadet, wenn sie schlecht ist.
Die abstrakte Syntax ist jedoch eine andere Geschichte. Abstrakte Syntax definiert die Struktur Ihrer Sprache und wie Phrasen kombiniert werden können, um größere Phrasen zu bilden. Ich bin der Meinung, dass der Erfolg einer Sprache stark von der Qualität ihrer abstrakten Syntaxdefinition abhängt.
Mein Problem mit der fließenden API ist nicht, dass sie mehrdeutig oder unklar oder nicht aussagekräftig ist. Sie verbirgt die eigentliche Sprache und ihre Struktur und macht die Dinge dadurch viel komplizierter, als sie sein müssen. durch Einführung von Mehrdeutigkeiten, nicht offensichtlichen Syntaxfehlern usw.).
Da Sie erwähnt haben, dass Sie auch eine "konventionellere API" bereitstellen, scheint Ihnen das alles bereits bekannt zu sein. Dazu sage ich "Gut!" Das heißt aber nicht, dass Sie nicht auch Ihre flüssige API parallel entwickeln können! Eine einzelne abstrakte Syntaxdefinition kann mehrere konkrete Syntaxen unterstützen. Während Sie bedenken sollten, dass die abstrakte Syntax die Realität ist, kann eine konkrete Syntax auch sehr hilfreich sein.
quelle
Neben den sehr guten Punkten von Quentin Pradet bezweifle ich die angeblichen Vorteile dieser Sprache.
Vermutlich besteht der Sinn einer der natürlichen Sprache nahe stehenden Grammatik darin, sie zugänglich zu machen. Aber SQL kommt der natürlichen Sprache schon sehr nahe. Ist einer von ihnen dem Englischen wirklich näher als der andere?
Ich sehe den Nutzen Ihrer Grammatik vom Standpunkt der Intuitivität oder Lesbarkeit nicht wirklich. Tatsächlich sieht die SQL-Version aufgrund ihres Leerzeichens lesbarer aus (und ist einfacher zu tippen).
quelle
Es gibt eine Reihe von
schlechtweniger als idealen Design - Entscheidungen , die bei der Prüfung dieser API gemacht zu haben scheinen worden.Die erste ist die Frage des Nutzens - welchem Zweck dient sie? Dies scheint eine Datenstruktur zu schaffen, die in einen SQL-Dialekt kompiliert wird. Übrigens scheint die Grammatik eine begrenzte Menge von SQL zu sein. Die Frage: "Welchen Vorteil hat dies gegenüber der Verwendung von SQL?" wird zum Schlüssel. Wenn es umständlicher ist, über die flüssige Schnittstelle zu schreiben, als nur einen String mit der entsprechenden Interpolation zu schreiben, wird über diese API nicht geschrieben.
Englisch ist mehrdeutig. Der Versuch, eine fließende Benutzeroberfläche auf Englisch zu modellieren, ist eine schlechte Wahl (Sie sollten lieber Latein verwenden ). Wenn es mehrere möglicherweise gültige Parsings derselben Aufrufkette gibt, führt dies zu Verwirrung und Überraschung . Beides ist nicht gut in einer API.
SQL enthält mehr Teile, als diese API bereitstellt. Verknüpfungen (in einer ihrer unzähligen Formen) fehlen im Beispielsatz besonders. Unterabfragen (
foo in (select id from bar)
), Gewerkschaften und Gruppieren nach sind einige der Dinge, die häufig verwendet werden. Komplexe Gruppierungen von Logik scheinen auf keine intuitive Weise vorhanden zu sein.Wenn Sie mit dieser API geschrieben haben und dann festgestellt haben, dass die API die gewünschte Abfrage nicht ausdrücken kann, geht viel Zeit verloren. Es ist keine gute Wahl, gemischte Stile für die Ausführung von Abfragen in einer Anwendung zu verwenden (einfache Abfragen in dieser API, komplex in Raw-SQL) - und letztendlich wird diejenige verwendet, die aussagekräftiger ist.
Während das Programmieren weit verbreitet ist, ist Englisch nicht fließend. Sogar mit einer Beschränkung der Sprache auf "SQL-like" gibt es Nuancen, wie ein Muttersprachler etwas lesen würde und jemanden, der Englisch als zweite oder dritte Sprache hat.
Es gibt unnötige Redundanz in der API für Englisch. Insbesondere
equal()
vsequals()
das gleiche zu tun. Ich bin mir zwar nicht sicher, aber ich glaube, dass diesis()
ein No-Op ist, der hinzugefügt wurde, um ein passendes Englisch näher zu bringen. Ich freue mich über jeden, der sich im Chat über die Redundanz der Ruby-Methoden beschwert - machen Sie nicht den gleichen Fehler.Setzen Sie sich und schreiben Sie ein umfassendes Beispielset der Abfragen auf, die Sie verwenden möchten. Stellen Sie fest, mit wem Sie all diese Beispiele auf eine nicht mehrdeutige Art und Weise behandeln, die weniger umständlich als die Abfragen selbst ist. Wenn nicht, überlegen Sie, ob es sich lohnt, die API zu schreiben. SQL ist dort, wo es heute ist (es ist nicht perfekt, aber ich habe nichts Besseres gefunden), und das über Jahrzehnte hinweg.
RFC 1925 - Die zwölf Wahrheiten der Vernetzung
quelle