Hi Christopher, 2013/6/23 Christopher Deckers <[email protected]>
> Hi Lukas, > > While not very active, I did keep an eye on this discussion, and I too > found your answer to be very valuable. I am glad to see it making it > somewhere in the manual. > Thanks for joining again. You have mentioned some notable aspects. I'll respond to your other very interesting mail about long-term strategies later. > Languages have reserved keywords, so mapping a language to another is > likely to clash on some reserved keywords. The amount of clash depends on > the languages that we consider and tricks we can apply. One consideration > is about the target languages: should we have the same considerations for > jOOQ used in Java and jOOQ used in say Scala? I will use "Scala" as a > generic way of saying "other languages" throughout the discussion. Of > course I understand that jOOQ's primary target is Java, but I am curious. > Yes, we should, even if they're only secondary influences. But jOOQ should be as Scala and Groovy interoperable as possible. The only conflict I had with Scala so far was the "val" reserved word, which I solved by duplicating "DSL.val()" into "DSL.value()" for our Scala friends. Note that in the worst case, Scala offers quoting using backticks. I.e. DSL.`val`() is a possible way to access a Java method that would otherwise not be accessible in Scala. This is viable for "remote" keywords, not for frequently used ones, such as AND or SELECT, of course. > *1. By introducing artificial keywords. Examples* >> >> SQL: UPDATE t SET a = 1, b = 2 >> jOOQ: update(t).set(a, 1).set(b, 2) >> > Note that this example also shows missing operator overloading >> capabilities, where "=" is replaced by "," >> > > Would jOOQ on Scala be able to more closely match such construct if one > wanted to? > Not every operator can be overloaded in Scala. In particular, I think that these cannot be overoaded: = , == !=, but I'm not 100% sure. Groovy has hird-wired rules for operator "overloading": http://groovy.codehaus.org/Operator+Overloading I had recently found an interesting PhD thesis on Scala's potential of being a host to internal domain specific languages, like jOOQ: http://biblion.epfl.ch/EPFL/theses/2011/5007/EPFL_TH5007.pdf Interestingly, the thesis also internalises SQL, albeit only very superficially. Scala 2.10 also offers Macros, but from what I have seen so far, I am not sure how they can be leveraged. I simply don't understand the current Macro documentation. > SQL: ORDER BY >> jOOQ: orderBy() >> > > Would jOOQ on Scala be able to more closely match such construct? I guess > that would mean having ORDER(BY(xxx)) and then BY could be problematic if > used in other places. > Scala's ability to omit parentheses in certain cases will lure you into thinking that these things will be useful. This topic is dealt with extensively in the above thesis. Let's look at your example (pseudo Scala, might not be entirely correct): ================================ object ScalaDSL { def BY(Field f) : ByField = ... def BY(SortField f) : BySortField = ... } trait SelectOrderByStep { def ORDER(ByField f) = ... } ================================ A lot of types like ByField and BySortField would be introduced. These types are only used for DSL syntax implementation. They have no other meaning but can be reused among clauses, e.g. PARTITION BY, GROUP BY. Another option to implement "ORDER BY field": ================================ trait SelectOrderStep { def ORDER : SelectOrderByStep; } trait SelectOrderByStep { def BY(Field f) : ... def BY(SortField f) : ... } ================================ This becomes a bit different with "three-letter" keyword combinations. Let's take Oracle's ORDER SIBLINGS BY, for instance. The above would then be enhanced to: ================================ trait SelectOrderStep { def ORDER : SelectOrderByStep; def ORDER(SIBLINGS s) : SelectOrderByStep; } object SIBLINGS {} trait SelectOrderByStep { def BY(Field f) : ... def BY(SortField f) : ... } ================================ But the problem here is the fact that introducing a SIBLINGS syntactic element will also introduce ambiguities when writing ================================ ORDER SIBLINGS BY f // is the above: ORDER().SIBLINGS().BY(f) // or is it: ORDER(SIBLINGS).BY(f) // apparently, Scala's lexer doesn't know, and the compiler cannot // disambiguate this, according to the language reference. Disambiguation: (ORDER SIBLINGS) BY f ================================ Having exprimented already for a couple of hours (and having read that thesis), I don't think that a truly satisfiable solution where all nasty dots and parentheses can be omitted, is possible in an API that makes heavy use of overloading, such as jOOQ's. The rules are too complex to handle in productive code, and if you don't handle them, you will resort to code that is worse to read, write and maintain than jOOQ's, i.e. ORDER(BY(f)) or ORDER().BY(f) or (ORDER SIBLINGS) BY f. The worst thing about these techniques is the fact that, *IF* you get something wrong, syntactically, enjoy finding your mistake if you're running a SQL statement like this one: http://blog.jooq.org/2011/11/14/jooq-meta-a-hard-core-sql-proof-of-concept Feel free to experiment with Scala yourself, though. I'm sure I haven't seen it all, yet :-) > *6. By using descriptive methods, or a comma* >> >> Most SQL operators have to be mapped to descriptive method names in Java: >> >> SQL: = >> jOOQ: equal(), eq() >> > > What is the rule with verbs? Should it be 3rd person, like "equals()" (if > there were no collisions with Java's equals)? > eq() elegantly solves this problem :-) As you've correctly guessed, collision with Java's equals() was the problem here. If verbs *had* to be chosen, I would probably have to change greaterThan() into isGreaterThan(), choosing IS to be consistent with IS NULL, IS DISTINCT FROM, etc. Thus, isEqual() would be the "SQL way" to write out "=" That might be a change worth considering for jOOQ 4.0, in a greater context. > SQL: <> >> jOOQ: notEqual(), ne() >> > > Would jOOQ on Scala be able to more closely match such construct? > Yes. See my other mail or the manual: http://www.jooq.org/doc/3.0/manual/sql-building/scala-sql-building > *7. That cannot be worked around* >> >> This is what has been keeping me from implementing CTE so far. >> >> SQL: WITH a(x, y) AS (SELECT 1, 2) SELECT a.x, a.y FROM a >> > > What is the problem with the above expression? > The problem is that a is not well-defined in SELECT a.x, a.y or in FROM a. The above would have to be written as: Table<?> a = select(val(1), val(2)).asTable("a", "x", "y"); with(a) .select(a.field("x"), a.field("y")) .from(a); It would work, of course. But it wouldn't feel exactly like SQL. And you would lose all typesafety. > *Discussion* >> >> a) by using synonyms >> > > This is the worst suggestion in my view. > Yes, I agree with you. :-) As an excuse... at the time I implemented this, I wasn't aware of the fact that jOOQ might eventually go that far. I think, decode() was in there since version 1.0. At least, it's contained in the first Maven-published version: http://grepcode.com/file/repo1.maven.org/maven2/org.jooq/jooq/1.5.7/org/jooq/Field.java#Field.decode%28org.jooq.Field%2Corg.jooq.Field%2Corg.jooq.Field%5B%5D%29 So, let's consider decode() an early "API blunder" b) by appending "disambiguators" such as case_ or case$ or case >> > > I don't mind hard rules, like "any keyword that may clash with Java > keyword is going to be suffixed with '_'". I prefer suffix, because code > completion would work when I start typing "case". > Agreed on the suffix. But I'd really like to avoid this as long as possible. It's quite an "ugly" solution for something as frequent as a CASE expression. > c) by introducing artificial spelling, such as casë, casǝ, casɇ ;-) >> > > OK, this *IS* the worst suggestion :) > You forgot \uFF43\uFF41\uFF53\uFF45: case > Great! I was looking for those letters, just didn't find them. Hey, you only need the e, as in case. That way, IDE auto-completion can still help the poor developers, in case they don't remember FF45 ;-) d) by changing the API to be all-uppercase: SELECT(), CASE(), ORDER_BY() >> > > My initial reaction was "ouch, this is ugly Java", but I do write SQL all > caps, so having the DSL part be all caps to map SQL is really not that bad. > Yes, and it would stress the fact that jOOQ is really actually SQL embedded in Java, more typesafely and with more features than SQLJ. e) by changing the API to be camel-case with an upper-case initial letter: >> Select(), Case(), OrderBy() >> > > This is odd, because it is neither the Java convention nor SQL. > I have seen it once or twice in a SQL Server / .NET context, although T-SQL uses UPPERCASE in their conventions: http://msdn.microsoft.com/en-us/library/ms177563.aspx But in .NET, method names are often PascalCased: http://msdn.microsoft.com/en-us/library/ms229043.aspx It wouldn't be the worst solution, but still odd. > d) and e) are massive changes. >> > > Apart from being an incompatible API, what is the complexity? User manual > mainly? > Massive in the amount of work for me :-) (and for users if it wasn't backwards-compatible) You're right, there isn't much complexity. It would simply mean: - Creating a code-generator that generates delegate methods for one syntax, delegating to the other - Creating a section in the manual explaining that both are possible - Creating some indicative integration tests If it can be guaranteed, that for every orderBy(), there shall also be an ORDER_BY(), the above would be sufficient. And using our new annotations (those for the BNF), it will be easy to discover, which methods need to be duplicated. If people wanted to reduce their jOOQ binary footprint, they could rebuild jOOQ, omitting the duplication. Of course, such a strategy would also indicate, that your suggestion is the only viable way to implement case_(), else_(), for_() in the camelCase API. Any other ideas? >> > > Apart from silly ideas like "cASE", not really :) > caze? elze? ca$e? el$e? esac? esle? -- You received this message because you are subscribed to the Google Groups "jOOQ User Group" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
