JavaScript API – Using Natural Language Grammar in Fluent API

apijavascript

I'm tinkering with a query abstraction over WebSQL/Phonegap Database API, and I find myself both drawn to, and doubtful of, defining a fluent API that mimics the use of natural English language grammar.

It might be easiest to explain this via examples. The following are all valid queries in my grammar, and comments explain the intended semantic:

//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 based on Quentin Pradet's feedback: In addition it seems, the API would have to support both plural and singular verb forms, so:

//a equals b
find("post").where("foo").equals(1);

//a and b (both) equal c
find("post").where("foo").and("bar").equal(2);

For the sake of question, let's presume that I haven't exhausted all possible constructs here. Let's also presume that I can cover most correct English sentences – after all, the grammar itself is limited to the verbs and conjuctions defined by SQL.


Edit regarding grouping: One "sentence" is one group, and the precedence is as defined in SQL: left to right. Multiple groupings could be expressed with multiple where statements:

//the conjunctive "and()" between where statements is optional
find("post")
  .where("foo").and("bar").equal(2).and()
  .where("baz").isLessThan(5);

As you can see, the definition of each method is dependent on the grammatical context it is in. For example the argument to "conjunction methods" or() and and() can either be left out, or refer to a field name or expected value.

To me this feels very intuitive, but I would like you hear your feedback: is this a good, useful API, or should I backpedal to more straighforward implementation?

For the record: this library will also provide a more conventional, non-fluent API based on configuration objects.

Best Answer

I think it's very wrong. I study natural langage and it's full of ambiguity that can only be resolved with context and a lot of human knowledge. The fact that programming languages are not ambiguous is a very good thing! I don't think you want meaning of methods to change according to context:

  • This is adds more surprises since you bring ambiguity
  • Your users will want to use constructions that you will not have covered, eg. find("user").where("name").and("email").equals("foo");
  • It's hard to report errors: what can you do with find("user").where("name").not().is().null();?

Let's also presume that I can cover most correct English sentences - after all, the grammar itself is limited to the verbs and conjuctions defined by SQL.

No, you can't cover most correct English sentences. Others have tried before, and it gets very complicated very quickly. It's called Natural language understanding but nobody really tries that: we're trying to solve smaller problems first. For your library, you basically have two options:

  • either you restrict yourself to a subset of English: that gives you SQL,
  • or you try to cover "English" and you find out that it's not possible due to the ambiguity, complexity and diversity of the language.
Related Topic