In all the examples I have seen the results from esqueleto are projected into a list of tuples or to entities records.
For example:
previousLogItems
What esqueleto is actually doing here is a little complicated. Here is the type for select
:
select :: (SqlSelect a r, MonadIO m) => SqlQuery a -> SqlReadT m [r]
This takes an SqlQuery a
(a monad wrapping the value you return
), and returns an SqlReadT m [r]
(a monad wrapping a list of results). When you return
your Custom
type, the following happens:
a
type to persistent's internal SQL representation[r]
To make this work for custom types, you'll need to instantiate SqlSelect, and define conversion functions to and from the persistent types:
data Custom' = Custom' (Value Text) (Value Int)
data Custom = Custom
{ title :: Text
, id :: Int
}
instance SqlSelect Custom' Custom where
sqlSelectCols esc (Custom' a b) = (mconcat [ta, ", ", tb], va ++ vb)
where
(ta, va) = sqlSelectCols esc a
(tb, vb) = sqlSelectCols esc b
sqlSelectColCount _ = 2
sqlSelectProcessRow [PersistText a, PersistInt64 b] = Right $ Custom a b
sqlSelectProcessRow _ = Left "Error: Incorrect rows to translate to Custom"
(note that I wasn't actually able to test any of the above, so it might have bugs)
One thing to note is that in the above example, the a
and r
types are not the same (Custom'
vs Custom
). This is because inside of a select
, all of the values you're working with are of type Value
, not their actual types.