Estou mexendo com uma abstração de consulta na API WebSQL / Phonegap Database, e me sinto atraído e duvidoso por definir uma API fluente que imita o uso da gramática natural da língua inglesa.
Pode ser mais fácil explicar isso por meio de exemplos. A seguir, todas as consultas válidas na minha gramática e os comentários explicam a semântica pretendida:
//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);
Edite com base no feedback de Quentin Pradet : Além disso, a API teria que suportar formas verbais no plural e no singular, portanto:
//a equals b
find("post").where("foo").equals(1);
//a and b (both) equal c
find("post").where("foo").and("bar").equal(2);
Por uma questão de dúvida, vamos supor que eu não tenha esgotado todas as construções possíveis aqui. Suponhamos também que eu possa cobrir as frases em inglês mais corretas - afinal, a gramática em si é limitada aos verbos e conjurações definidos pelo SQL.
Editar em relação ao agrupamento : uma "sentença" é um grupo e a precedência é como definida em SQL: da esquerda para a direita. Vários agrupamentos podem ser expressos com várias where
instruções:
//the conjunctive "and()" between where statements is optional
find("post")
.where("foo").and("bar").equal(2).and()
.where("baz").isLessThan(5);
Como você pode ver, a definição de cada método depende do contexto gramatical em que está. Por exemplo, o argumento para "métodos de conjunção" or()
e and()
pode ser deixado de fora, ou referir-se a um nome de campo ou valor esperado.
Para mim, isso parece muito intuitivo, mas gostaria que você ouvisse seus comentários: essa é uma API boa e útil ou devo recuar para uma implementação mais direta?
Para o registro: essa biblioteca também fornecerá uma API mais convencional e não fluente, com base em objetos de configuração.
fonte
... where foo = 1 or (bar = 2 and qux = 3)
:?where("name").equals("foo").or("bar")
como(name=="foo")or bar
. Então não é claro quando uma string representa um literal, e quando apresenta um nome de coluna, ...Respostas:
Eu acho que está muito errado. Eu estudo linguagem natural e é cheia de ambiguidade que só pode ser resolvida com contexto e muito conhecimento humano. O fato de as linguagens de programação não serem ambíguas é uma coisa muito boa! Eu não acho que você queira que o significado dos métodos mude de acordo com o contexto:
find("user").where("name").and("email").equals("foo");
find("user").where("name").not().is().null();
?Não, você não pode cobrir as frases em inglês mais corretas. Outros já tentaram antes, e isso fica muito complicado muito rapidamente. Isso se chama entendimento da linguagem natural, mas ninguém realmente tenta isso: estamos tentando resolver problemas menores primeiro. Para sua biblioteca, você basicamente tem duas opções:
fonte
is()
ouequal()
somenteequals()
. Não encontrou seu problema ao relatar erros após isso.null()
também se tornaria um literal para comparar, em vez de uma função de sintaxe.find("user").where("name").is().not().null();
tornafind("user").where("name").not().equals(null);
Costumo concordar um pouco com os posts de outras pessoas que esse não é um ótimo design. No entanto, acredito que tenho razões diferentes.
Você está apresentando o que eu vejo como uma sintaxe concreta para consultas SQL. Eu acredito firmemente que a sintaxe concreta nunca pode ajudar uma linguagem, apenas machuca se for ruim.
No entanto, a sintaxe abstrata é uma história diferente. A sintaxe abstrata define a estrutura do seu idioma e como as frases podem ser combinadas para criar frases maiores. Eu sinto que o sucesso de uma linguagem depende fortemente da qualidade de sua definição abstrata de sintaxe.
Meu problema com a API fluente não é ambíguo, claro ou não expressivo - oculta a linguagem real e sua estrutura e, ao fazê-lo, acaba tornando as coisas muito mais complicadas do que precisam ser ( introduzindo ambiguidades, erros de sintaxe não óbvios etc.).
Como você mencionou que também fornecerá uma "API mais convencional", parece que você já sabe tudo isso. Para isso eu digo "Bom!" Mas isso não significa que você também não pode desenvolver sua API fluente em paralelo! Uma única definição de sintaxe abstrata pode suportar várias sintaxes concretas. Embora você tenha em mente que a sintaxe abstrata é o negócio real, uma sintaxe concreta também pode ser muito útil.
fonte
Além dos pontos muito bons de Quentin Pradet, duvido dos alegados benefícios desse idioma.
Presumivelmente, o objetivo de uma gramática próxima à linguagem natural é torná-la acessível. Mas o SQL já está bem próximo da linguagem natural. Um deles é realmente mais próximo do inglês que o outro?
Realmente não vejo o benefício da sua gramática, do ponto de vista da intuitividade ou legibilidade. De fato, a versão SQL parece mais legível (e é mais fácil de digitar) devido ao seu espaço em branco.
fonte
Há várias decisões de design
ruinsque não são ideais que parecem ter sido tomadas ao considerar esta API.A primeira é a questão da utilidade - a que finalidade ela serve? Isso parece estar criando uma estrutura de dados que será compilada em um dialeto do SQL. Aliás, a gramática parece ser um conjunto limitado de SQL. A questão de "que vantagem isso serve ao usar apenas SQL?" torna-se chave. Se for mais complicado escrever usando a interface fluente do que apenas escrever uma string com a interpolação apropriada, não será possível escrever usando essa API.
Inglês é ambíguo. Tentar modelar uma interface fluente em inglês é uma má escolha (é melhor usar o latim ). Quando existem várias análises possivelmente válidas do mesmo conjunto de ligações, isso gera confusão e surpresa . Nenhuma dessas coisas é boa em uma API.
Há mais partes no SQL do que esta API está expondo. As junções (em qualquer uma de suas inúmeras formas) estão notavelmente ausentes no conjunto de exemplos. Subconsultas (
foo in (select id from bar)
), uniões e grupos de são algumas das coisas que são frequentemente usadas. Agrupamentos complexos de lógica não parecem estar presentes de maneira intuitiva.Se alguém estivesse escrevendo usando essa API e descobrisse que ela não é capaz de expressar a consulta desejada, um tempo significativo será perdido. É uma má escolha usar estilos mistos para fazer consultas em um aplicativo (consultas simples nesta API, complexas em sql bruto) - e, finalmente, o que for mais expressivo será usado.
Enquanto a programação é generalizada, a fluência em inglês não é. Mesmo com uma limitação do idioma para "como o SQL", há nuances de como um falante nativo leria algo e alguém que tem o inglês como segundo ou terceiro idioma.
Há redundância desnecessária na API por causa do inglês. Em particular
equal()
vsequals()
fazendo a mesma coisa. Embora eu não tenha certeza disso, acredito que esseis()
é um acréscimo no-op por causa de um inglês mais próximo. Congratulo-me com qualquer um que ouça meu discurso sobre redundância de métodos em ruby no chat - não cometa o mesmo erro.Sente-se e escreva um conjunto abrangente de exemplos das consultas que você deseja poder usar. Determine com quem você manipulará todos esses exemplos de maneira não ambígua e menos trabalhosa do que as próprias consultas. Se não puder, considere se vale a pena seguir o caminho de escrever a API. O SQL é onde está hoje (não é perfeito, mas não encontrei nada melhor) ao longo de décadas de aprimoramento.
RFC 1925 - As doze verdades da rede
fonte