Of course it's a bit painful and error prone, given SQL is a textual language, but as HoneySQL (https://github.com/seancorfield/honeysql) shows, you can represent SQL statements as data and generate them programmatically in a safe manner. I think it's compatible with https://babashka.org/ so you don't need a full Java environment to use it.
such a rewrite is a lot more predictable endeavor, then building the initial solution, that it's a great problem to have :)
meanwhile, your UI don't have to change and a lot of your other glue code or business-logic code don't have to change either, IF you haven't hardcoded direct calls to SQLite everywhere in your program :)
eg. I used HoneySQL with great success! My queries are safely assembled from Clojure data structures and I had a single function, which I used to format them to the desired SQL dialect H2DB/SQLite/MySQL/Postgres, execute them and parse the results back into Clojure data structures and even take care of lazily paginating through long result sets, without burdening the consumer of the data with such details.
https://github.com/seancorfield/honeysql
I used it to quickly iterate on the development of migration SQL scripts for a MySQL DB, which was running in production on RDS.
I might have switched to H2 DB later, because that was more compatible with MariaDB, but I could use the same Clojure code, representing the SQL queries, because HoneySQL can emit different syntaxes. Heck, we are even using it to generate queries for the SQL-variant provided by the QuickBooks HTTP API! :)
https://www.hugsql.org/ it's pretty good too, btw! it's just a bit too much magic for me personally :)
Also, you should really look into JetBrains database tooling, like the one in IntelliJ Ultimate or their standalone DataGrip product! It's freaking amazing, compared to other tools I tried. If you are an Emacs person, then I think even with some inferior shells to the command-line interfaces of the various SQL system, you can go very far a lot more conveniently, than thru some ORMs.
Either way, one secret to developing SQL queries comfortably is to utilize some more modern features, like the WITH clause, to provide test data to your queries: https://www.sqlite.org/lang_with.html
You can use it to just type up some static data, but you can also compute test data dynamically and even randomly!
Other little-known feature is the RETURNING clause for INSERT/UPDATE/DELETE: https://www.sqlite.org/lang_returning.html
It can highly simplify your host-code, which embeds SQL, because you don't have to introduce UUID keys everywhere, just so you can generate them without coordination.
Edit: I know there are ways to avoid N+1 problems with ORMs, but it seems to more easily sneak into code when your SQL queries look just like your application level code and you could easily enumerate over some SQL result, perform some action, and think that it builds an efficient query.
I've recently been working with a hobby project where I use the Clojure HoneySQL[2] library which essentially lets you build SQL queries as you normally would, but in Clojure's EDN syntax. It treats SQL queries as data. You can super easily evaluate them to get the resulting raw SQL query strings. There is no magic behind it and it encourages you to use the full power of your db.
[1] https://theartofpostgresql.com/blog/2019-09-the-r-in-orm/ [2] https://github.com/seancorfield/honeysql
I would highly recommend learning the spirit of Clojure first:
https://changelog.com/posts/rich-hickeys-greatest-hits
https://www.youtube.com/watch?v=vK1DazRK_a0
There are a few classes of tech that are uniquely Clojure:
Data driven DSLs:
- https://github.com/noprompt/garden
- https://github.com/weavejester/hiccup
- https://github.com/seancorfield/honeysql
Hyper normalised relational databases:
- https://github.com/replikativ/datahike
Advanced SPA tech (hyper normalised data driven):
- http://fulcro.fulcrologic.com/
- https://wilkerlucio.github.io/pathom/v2
Once you understand the spirit and rationale for Clojure it becomes apparent why other communities don't have this kind of tech yetOnce it gets down to practical things I recommend using clj-Kondo with type hints, Cursive for Intellji, make sure you learn how to hot code inject new code into your running program using your editor shortcuts, and TDD in Clojure is also excellent and immediate: https://cursive-ide.com/userguide/testing.html
Also look out for GraalVM and Babashka we're using it to compile fast native binaries out of Clojure