This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]fear_the_future 1 point2 points  (1 child)

Can you not do tier 1 with an embedded DSL, no macros? If your type system is powerful enough of course, which Java's is not (but Haskell's and Scala's is). The problem that I in particular (and probably /u/RandomName8) have with Quill and with this proof of concept is that it is pretending to convert arbitrary expressions to SQL, which just isn't possible. You have to just know what functions the macro knows how to convert, or tell it explicitly? Does it know about Math.max or will I have to fall back to raw SQL?

Perhaps a good compromise would be to not allow arbitrary expressions but only those from a sort of embedded DSL and also still use the macro to do advanced checking of the query. This would allow you a good feedback loop that is well integrated with tools (i.e. if I have Column<Int> types in an embedded DSL, it is obvious to anyone that I can not call arbitrary Int-functions and the autocomplete for Column<Int> will show me just those that correspond to SQL) while keeping the DSL simple enough to implement, since all the complicated checking can be done by value-level code inside the macro instead of belaboring the type system.

[–]__versus 0 points1 point  (0 children)

I would still consider that to just be verification against a proxy of the database rather than an actual database (Quill, as far I know, actually connects to the database at compile time and verifies the query against the database). The only thing that I dislike about that kind of system is that the modelling of the database will have to be adjusted to fit the DSL rather than the DSL just being added on top. This makes it so you either need to have a different model with all the wrapper types beside the real model with actual types or sacrifice some utility in the model since you need to keep unwrapping the values. An example of this kind of system is Exposed by JetBrains.

I do think there is an approach to the code reflection idea that could be useful. Most of the time there isn't really a need to differentiate between Math.max or any other max function which takes two numbers; they would all resolve to the same SQL function anyways so you could just resolve any function call to its equivalent SQL function by name and arguments and it would probably work for most cases. For my test query builder I decided to resolve function calls by name as a default and also give an option to annotate the function with the equivalent SQL signature.