Quill Dotty Update

I guess one thing that’s not clear to me: does the naming strategy have to be present to generate the compile time query, or is it something we can do “dynamically” by generating a generic query at compile time and then transforming it with the naming strategy at runtime?

I assume most naming strategies are relatively simple, and won’t cause much perf issues if done at runtime. Although a downside of runtime naming is you won’t see the exact SQL being run in the compile logs, and instead see a pre-naming-strategy version of it

Well its part of the final SQL, and the dynamic inputs for compile time queries (i.e. lift) are actually inputs for SQL prepared statements. You can’t use variables for table/column names in prepared statements, so I don’t think its possible else its not really a proper “compile time query”.

This is also the same reason why its critical to have good error messages for both dynamic and static queries, you do often end up needing to create dyamic queries (i.e. there is no way in any standard SQL database to have ordering defined dynamically with inputs for a prepared statement, you basically have to generate at runtime completely different SQL queries if you want to order by ascending vs descending).

How about this. Let’s make a context that can be used statically but doesn’t have to be. It could look like this:

object MyContext extends PostgresJdbcContext[Literal]
import MyContext._
val q = quote {
  query[Person].filter(p => p.name == "Joe")
}
implicit val session = createSession(connection)
run(q)

but… you could still use the old-style, just without the ‘new’ keyword:

// Creates both the implicit session as well as the context
val ctx = PostgresJdbcContext[Literal](connection)
import ctx._
val q = quote {
  query[Person].filter(p => p.name == "Joe")
}
run(q)

If we extract execute___ methods out of Context but the rest of the sematics remain the same, we could support both styles. This would also substantially reduce migration effort of users.

Edit:
I think this refactor should be done in the Scala 2 Quill as well. Clubbing it together with Dotty is not needed.

3 Likes

As a bonus since the API’s are closer it means there is less of a migration effort needed.

This is what we do currently and it didn’t affect anything substantial. I can’t imagine use-case where you want to have different naming strategies in the same app and the same query (different queries could use different static objects).

AFAIU that’s not possible (without extracting execute) if your DB connection is configured in runtime, e.g. with env variables.

1 Like

If anyone is interested, I am doing a video series walking through how Quill in Dotty can be implemented from scratch with a group of brave Drexel students. This covers Parsing, Lifting, Unlifting, and producing a AST which is then transpiled. There’s quite a bit of content here (> 10 hours). Enjoy!

14 Likes

I think we will have Lazy Lifts and Dotty-Quill after all. I just implemented them.

This is just for static queries for now, I’ll think about doing to for Dynamic queries closer to the release or maybe afterward.

7 Likes