Je suis en train de bricoler une abstraction de requête sur l'API WebSQL / Phonegap Database, et je me trouve à la fois attiré et douteux de définir une API fluide qui imite l'utilisation de la grammaire naturelle de la langue anglaise.
Il pourrait être plus facile d'expliquer cela à l'aide d'exemples. Les requêtes suivantes sont toutes valides dans ma grammaire et les commentaires expliquent la sémantique voulue:
//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 basé sur les commentaires de Quentin Pradet : En outre, il semble que l'API devrait prendre en charge les formes verbales plurielles et singulières, donc:
//a equals b
find("post").where("foo").equals(1);
//a and b (both) equal c
find("post").where("foo").and("bar").equal(2);
Par souci de question, supposons que je n'ai pas épuisé toutes les constructions possibles ici. Supposons également que je puisse couvrir la plupart des phrases anglaises correctes - après tout, la grammaire elle-même est limitée aux verbes et aux conjonctions définis par SQL.
Modifier concernant le regroupement : une "phrase" est un groupe et la priorité est telle que définie dans SQL: de gauche à droite. Plusieurs regroupements peuvent être exprimés avec plusieurs where
déclarations:
//the conjunctive "and()" between where statements is optional
find("post")
.where("foo").and("bar").equal(2).and()
.where("baz").isLessThan(5);
Comme vous pouvez le voir, la définition de chaque méthode dépend du contexte grammatical il est. Par exemple l'argument « méthodes de conjonction » or()
et and()
peut soit être laissé de côté, ou se référer à un nom de champ ou valeur attendue.
Pour moi, cela semble très intuitif, mais j'aimerais que vous entendiez vos commentaires: est-ce une bonne API utile, ou devrais-je revenir sur une mise en œuvre plus directe?
Pour mémoire: cette bibliothèque fournira également une API plus conventionnelle et non fluide basée sur des objets de configuration.
la source
... where foo = 1 or (bar = 2 and qux = 3)
:?where("name").equals("foo").or("bar")
comme(name=="foo")or bar
. Ensuite, on ne sait pas quand une chaîne représente un littéral, et quand elle présente un nom de colonne, ...Réponses:
Je pense que c'est très faux. J'étudie le langage naturel et il est plein d'ambiguïté qui ne peut être résolu qu'avec le contexte et beaucoup de connaissances humaines. Le fait que les langages de programmation ne soient pas ambigus est une très bonne chose! Je ne pense pas que vous vouliez que le sens des méthodes change selon le contexte:
find("user").where("name").and("email").equals("foo");
find("user").where("name").not().is().null();
?Non, vous ne pouvez pas couvrir la plupart des phrases anglaises correctes. D'autres ont essayé auparavant, et cela devient très compliqué très rapidement. Cela s'appelle la compréhension du langage naturel, mais personne n'essaye vraiment cela: nous essayons d'abord de résoudre des problèmes plus petits. Pour votre bibliothèque, vous avez essentiellement deux options:
la source
is()
ouequal()
seulementequals()
. Ne voyez pas votre problème avec les erreurs de rapport après cela.null()
deviendrait également un littéral à comparer, plutôt qu'une fonction de syntaxe.find("user").where("name").is().not().null();
devientfind("user").where("name").not().equals(null);
J'ai tendance à être un peu d'accord avec les messages des autres que ce n'est pas un excellent design. Cependant, je crois que j'ai différentes raisons.
Vous présentez ce que je considère comme une syntaxe concrète pour les requêtes SQL. Je crois fermement que la syntaxe concrète ne peut jamais aider une langue, seulement blesser si elle est mauvaise.
Cependant, la syntaxe abstraite est une autre histoire. La syntaxe abstraite définit la structure de votre langue et comment les phrases peuvent être combinées pour créer des phrases plus grandes. Je pense que le succès d'un langage dépend fortement de la qualité de sa définition de la syntaxe abstraite.
Mon problème avec l'API courante n'est pas qu'elle est ambiguë, ou peu claire, ou non expressive - c'est qu'elle cache le vrai langage et sa structure, et, ce faisant, finit par rendre les choses beaucoup plus compliquées qu'elles ne doivent l'être ( en introduisant des ambiguïtés, des erreurs de syntaxe non évidentes, etc.).
Puisque vous avez mentionné que vous fourniriez également une "API plus conventionnelle", il semble que vous sachiez déjà tout cela. À cela, je dis "Bien!" Mais cela ne signifie pas que vous ne pouvez pas également développer votre API couramment en parallèle! Une seule définition de syntaxe abstraite peut prendre en charge plusieurs syntaxes concrètes. Alors que vous devez garder à l'esprit que la syntaxe abstraite est la vraie affaire, une syntaxe concrète peut également être très utile.
la source
En plus des très bons points de Quentin Pradet, je doute des avantages allégués de cette langue.
Vraisemblablement, le but d'une grammaire proche du langage naturel est de la rendre accessible. Mais SQL est déjà assez proche du langage naturel. L'un d'eux est-il vraiment plus proche de l'anglais que l'autre?
Je ne vois pas vraiment l'avantage de votre grammaire, du point de vue de l'intuitivité ou de la lisibilité. En fait, la version SQL semble plus lisible (et plus facile à taper) en raison de son espace.
la source
Il y a un certain nombre de
mauvaisesdécisions de conception moins qu'idéales qui semblent avoir été prises en considérant cette API.La première est la question de l'utilité - à quoi sert-elle? Cela semble créer une structure de données qui se compilera dans un dialecte SQL. Par ailleurs, la grammaire semble être un ensemble limité de SQL. La question de "quel avantage cela sert-il par rapport à l'utilisation de SQL?" devient la clé. S'il est plus lourd d'écrire en utilisant l'interface fluide que d'écrire simplement une chaîne avec l'interpolation appropriée, alors on n'écrira pas en utilisant cette API.
L'anglais est ambigu. Tenter de modéliser une interface fluide en anglais est un mauvais choix (il vaut mieux utiliser le latin ). Lorsqu'il y a plusieurs analyses potentiellement valides du même ensemble d'appels, cela conduit à la confusion et à la surprise . Ni l'un ni l'autre n'est une bonne chose à avoir dans une API.
Il y a plus de parties dans SQL que cette API n'en expose. Les jointures (sous n'importe laquelle de leurs innombrables formes) sont notamment absentes de l'ensemble d'exemples. Les sous-requêtes (
foo in (select id from bar)
), les unions et les regroupements sont quelques-unes des choses qui sont souvent utilisées. Les regroupements complexes de logiques ne semblent pas être présents de manière intuitive.Si quelqu'un écrivait à l'aide de cette API et constatait ensuite que l'API n'est pas capable d'exprimer la requête souhaitée, un temps important sera perdu. C'est un mauvais choix d'utiliser des styles mixtes pour faire des requêtes dans une application (requêtes simples dans cette API, complexes en SQL brut) - et finalement celle qui est plus expressive sera utilisée.
Bien que la programmation soit répandue, la maîtrise de l'anglais ne l'est pas. Même avec une limitation de la langue à «SQL like», il existe des nuances sur la façon dont un locuteur natif lirait quelque chose et quelqu'un qui a l'anglais comme deuxième ou troisième langue.
Il y a une redondance inutile dans l'API pour le bien de l'anglais. En particulier
equal()
vsequals()
faire la même chose. Bien que je n'en sois pas certain, je crois queis()
c'est un no-op ajouté pour un anglais plus proche. J'accueille tout le monde pour écouter mes diatribes sur la redondance des méthodes dans ruby dans le chat - ne faites pas la même erreur.Asseyez-vous et écrivez un ensemble d'exemples complet des requêtes que vous souhaitez pouvoir utiliser. Déterminez qui vous gérerez tous ces exemples de manière non ambiguë, moins lourde que les requêtes elles-mêmes. Si vous ne le pouvez pas, demandez-vous s'il vaut la peine de suivre la voie de l'écriture de l'API. SQL est là où il est aujourd'hui (il n'est pas parfait, mais je n'ai rien trouvé de mieux) au cours de décennies de raffinement.
RFC 1925 - Les douze vérités du réseautage
la source