Expanding on this a bit, Clojure, as a language, is fundamentally against the idea of ORMs in its design.
Objects / classes are not so much the problem, per se—it's specifically that ORMs fundamentally involve scattering uncoordinated mutable state throughout the application. A foundational thesis of Clojure is that mutation is a tremendous source of bugs, and should be avoided / thoughtfully limited.
Once you let the unmanaged mutation genie out of the bottle, it's almost impossible to put back in.
More concretely, I used to work extensively with Rails; I loved ActiveRecord (ORM) when I first started out—it makes basic things so easy.
Later I worked on a large Rails app supporting millions of users...we used ActiveRecord extensively, and had a very talented team. ActiveRecord worked fine most of the time, but I have bad memories of spending hours or even days tracking down user-reported bugs.
I'd try to figure out how to recreate the user's state locally, even cloning pieces of the production database to work with their exact DB data, but whatever state the program had gotten into was a large graph of (all!) mutable objects. How was that flag getting set? What code could have done it? When? And the answer is basically ANYTHING at ANY TIME that could possibly get a reference to the object. And web applications are far from the worst offenders in this space because the request / response cycle is (usually) fairly globally stateless.
Clojure is the exact opposite of that experience.
The state of a Clojure program will most likely comprised of data literals (think JSON data types, if you don't have experience with Clojure / Lisp data). Printable data literals. Connect to the errant server, serialize the state, read it from your machine, and you're there. It's coherent, stable, serializable, transmittable, simple.
Who can mutate your data? No one. You have an immutable reference (maybe others do too, but reading is a fundamentally safe operation). How does it change? Only along the explicit path of computations you're working through (it doesn't change, actually, you choose to hold onto a new reference to derived data when you want to).
Or, if you really need a mutable escape hatch (like, say, you're holding a handle to a database), every type of mutation in (core) Clojure has defined (and thoughtfully so) concurrency semantics. You won't see a bunch of notes in Clojure API docs that say things like "not thread safe" like you see in JavaDocs.
TLDR: Clojure will happily give you object-like read-only views into your database (like Datomic's `datomic.api/entity`), or help you write queries with a knowledge of your database schema, but most Clojure persistence solutions will explicitly coordinate mutation into a single 'site' because that's the only way maintain a coherent view of state-over-time. And that single-mutation-site story is the opposite of what ORMs (as commonly defined) do.
Objects / classes are not so much the problem, per se—it's specifically that ORMs fundamentally involve scattering uncoordinated mutable state throughout the application. A foundational thesis of Clojure is that mutation is a tremendous source of bugs, and should be avoided / thoughtfully limited.
Once you let the unmanaged mutation genie out of the bottle, it's almost impossible to put back in.
More concretely, I used to work extensively with Rails; I loved ActiveRecord (ORM) when I first started out—it makes basic things so easy.
Later I worked on a large Rails app supporting millions of users...we used ActiveRecord extensively, and had a very talented team. ActiveRecord worked fine most of the time, but I have bad memories of spending hours or even days tracking down user-reported bugs.
I'd try to figure out how to recreate the user's state locally, even cloning pieces of the production database to work with their exact DB data, but whatever state the program had gotten into was a large graph of (all!) mutable objects. How was that flag getting set? What code could have done it? When? And the answer is basically ANYTHING at ANY TIME that could possibly get a reference to the object. And web applications are far from the worst offenders in this space because the request / response cycle is (usually) fairly globally stateless.
Clojure is the exact opposite of that experience.
The state of a Clojure program will most likely comprised of data literals (think JSON data types, if you don't have experience with Clojure / Lisp data). Printable data literals. Connect to the errant server, serialize the state, read it from your machine, and you're there. It's coherent, stable, serializable, transmittable, simple.
Who can mutate your data? No one. You have an immutable reference (maybe others do too, but reading is a fundamentally safe operation). How does it change? Only along the explicit path of computations you're working through (it doesn't change, actually, you choose to hold onto a new reference to derived data when you want to).
Or, if you really need a mutable escape hatch (like, say, you're holding a handle to a database), every type of mutation in (core) Clojure has defined (and thoughtfully so) concurrency semantics. You won't see a bunch of notes in Clojure API docs that say things like "not thread safe" like you see in JavaDocs.
TLDR: Clojure will happily give you object-like read-only views into your database (like Datomic's `datomic.api/entity`), or help you write queries with a knowledge of your database schema, but most Clojure persistence solutions will explicitly coordinate mutation into a single 'site' because that's the only way maintain a coherent view of state-over-time. And that single-mutation-site story is the opposite of what ORMs (as commonly defined) do.