Database interface

Tim Docker
Tue, 19 Aug 2003 19:47:20 +1000

Tom Pledger writes:

> By the way, how does the  a  in  a -> b -> IO (b, Bool)  work?
> It looks like it has something to do with the current row.  Does
> doquery have to accommodate any possible substitution for  a ?

I fired this off without thinking about it too much, and looking
at the prelude type signatures for fold. The list being folded over
is implied by the DB query, is accessible through the IO monad.
Hence a parameter is not required. It would really be:

doquery :: Process -> String -> b -> (b -> IO (b,Bool)) -> IO b

> I don't have a preference, but offer this view of the options:
>     With an exception, "Stop, and return the last b you saw."
>     With a boolean,    "Stop, and return this b."

I think I like the behavior where, when the bool in the tuple
is true, the b in the tuple is immediately returned from the
query. Exceptions would be propagated to the caller of doquery
without modification (but with appropriate cleanups).

One thing that I am unsure about is whether the column value
accessing functions that I specified before

   stringv :: Process -> CInt -> IO String
   doublev :: Process -> CInt -> IO Double
   intv    :: Process -> CInt -> IO Int

should return actions in the IO monad as above, or instead should
be in some other DBQuery monad, that trivially extends the IO monad,
but is only valid inside the doquery call. This would have the benefit
of restricting the column access functions to inside a query via the
type system.

I'd also probably use a typeclass to specify a single colv function.

   class DBCol a where
       colv :: DBQuery a

   instance DBCol String where...
   instance DBCol Double where...

   doquery :: Process -> String -> b -> (b -> DBQuery (b,Bool)) -> IO b

Any comments?