I disagree with the author. I've yet to see an abstraction layer that doesn't end up as the lowest common denominator of all databases supported or becomes a leaky abstraction.
Databases are different — accept it. I use PostgreSQL and Redis — there is really little they have in common and I use them for completely different purposes. I can't see how you could stuff all that into a single abstraction. I mean, in my Clojure code I use SQL transactions in one part of the program and Redis' optimistic locking (WATCH/MULTI/EXEC) in the other. They are _different_ and they are supposed to be different.
I also believe that the whole story about how difficult it is to "switch databases" is a red herring. If your code isn't a pile of spaghetti, then your database access functions are grouped together, not spread all over the place. This usually means that instead of abstracting the database with a generic database API, you abstract the database with your API, which only performs the operations you need.
If you do that, then a) switching databases isn't that difficult, b) your "database DSL" becomes your DSL, not somebody else's.
As a practical example, my code has a namespace called "distributed" which abstracts distributed synchronization using Redis. I can call (distributed/register-server), or (distributed/dequeue-job). The functions are very short, and really consist of redis-clojure calls with minimal database logic. Now that is a DSL I like.
Databases are different — accept it. I use PostgreSQL and Redis — there is really little they have in common and I use them for completely different purposes. I can't see how you could stuff all that into a single abstraction. I mean, in my Clojure code I use SQL transactions in one part of the program and Redis' optimistic locking (WATCH/MULTI/EXEC) in the other. They are _different_ and they are supposed to be different.
I also believe that the whole story about how difficult it is to "switch databases" is a red herring. If your code isn't a pile of spaghetti, then your database access functions are grouped together, not spread all over the place. This usually means that instead of abstracting the database with a generic database API, you abstract the database with your API, which only performs the operations you need.
If you do that, then a) switching databases isn't that difficult, b) your "database DSL" becomes your DSL, not somebody else's.
As a practical example, my code has a namespace called "distributed" which abstracts distributed synchronization using Redis. I can call (distributed/register-server), or (distributed/dequeue-job). The functions are very short, and really consist of redis-clojure calls with minimal database logic. Now that is a DSL I like.