[Haskell-cafe] Subject: A universal data store interface
Bardur Arantsson
spam at scientician.net
Tue Feb 14 00:13:45 CET 2012
On 02/13/2012 09:36 PM, Michael Snoyman wrote:
> You make it sound like your options are "use the crippled abstraction
> layer" or "use the full-powered database layer." You're leaving out
> two very important points:
>
> 1. There's a reason the abstraction layer exists: it can be clumsy to
> go directly to the full-powered database for simple stuff.
That's simply a reason to make access to the *full-powered database*
easier, not a reason to make access to *every database* identical. Doing
that is a mistake *unless* you're going to avoid SQL entirely but
somehow still retain the full database power. For example, SQLite
requires entirely different SQL contortions to get certain types of
fields in query results from the way PostgreSQL does it. That means
you'll have to change your program a lot even if you use e.g. HDBC for
database access.
My experience is roughly similar to Paul R's. You often give up too much
by going with "generic" ORM and such.
That's not to say you can't make working with each particular DB much
more pleasant that it is currently -- postgresql-libpq, for example, is
almost useless as an application-level API, and I'm working on (no
guarantees!) a little postgresql-libpq-conduit thingy which will
hopefully make issuing queries and iterating over results a much more
pleasant experience without burdening you will all kinds of ridiculously
low-level detail, and at the same time will NOT shield you from the
low-level detail that actually *matters*.
The Database Supported Haskell stuff
(http://hackage.haskell.org/package/DSH) also seems relevant to this
discussion, since this does seem like it could actually leverage the
immense power of (some) databases without having to bother too much with
low-level DB access.
> 2. You can bypass the abstraction layer whenever you want.
>
> I like to describe Persistent's goal as doing 95% of what you need,
> and getting out of your way for the other 5%. You can write raw SQL
> queries with Persistent. I use this for implementing full-text search.
> I haven't needed to write deep analytical tools recently, but if I
> did, I would use raw SQL for that too.
Yes, but then you end up being fully tied to the database *anyway*, so
why not just make *that* easier and safer from the start?
(I realize that this is a hard problem in practice. It's certainly NOT
small enough for a GSoC, IMO.)
>
> Persistent's advantage over going directly to the database is concise,
> type-safe code. Are you really telling me that `runSql "SELECT * FROM
> foo where id=?" [someId]` plus a bunch of marshal code is better then
> `get someId`?
>
For starters you should probably never do a "SELECT *" (which is what
one assumes Persistent would/will do) -- on an SQL database the
performance characteristics and locking behavior may change dramatically
over time... while on $generic-NoSQL database there may not really any
other option, and the performance characteristics *won't* necessarily
change too dramatically. This is an example of why introducing something
like Persistent (or ORMs in general) may be a non-trivial decision.
Besides, you probably won't need a lot of marshalling code if you know
what the query result field types are going to be (you should!). You
just pattern-match, e.g.
processQueryResult [SqlInteger i, SqlByte j, SqlText x] =
... -- do whatever to i,j and x
processQueryResult _ = error "Invalid columns in query result"
Yes, this means you'll need to know exactly how the table was created
(but not in the case of SQLite -- there you MAY have to add various
casts to the SQL or to manually convert from SqlText to your intended
Haskell datatype).
I don't think anyone denies that having a compile-time guarantee of a
successful match would be a bad thing.
It's just that this are is far more complicated than people give it
credit for.
More information about the Haskell-Cafe
mailing list