{-# LANGUAGE RecordWildCards #-}-------------------------------------------------------------------------------- |-- Module: Database.PostgreSQL.Simple.FromRow-- Copyright: (c) 2011 Leon P Smith-- License: BSD3-- Maintainer: Leon P Smith <leon@melding-monads.com>-- Stability: experimental-- Portability: portable---- The 'FromRow' typeclass, for converting a row of results-- returned by a SQL query into a more useful Haskell representation.---- Predefined instances are provided for tuples containing up to ten-- elements.------------------------------------------------------------------------------moduleDatabase.PostgreSQL.Simple.FromRow(FromRow(..),RowParser,field,numFieldsRemaining)whereimportControl.Applicative(Applicative(..),(<$>))importControl.Exception(SomeException(..))importControl.Monad(replicateM)importData.ByteString(ByteString)importqualifiedData.ByteString.Char8asBimportDatabase.PostgreSQL.Simple.Types(Only(..))importDatabase.PostgreSQL.Simple.OkimportqualifiedDatabase.PostgreSQL.LibPQasPQimportDatabase.PostgreSQL.Simple.InternalimportDatabase.PostgreSQL.Simple.FromFieldimportDatabase.PostgreSQL.Simple.Types((:.)(..))importControl.Monad.Trans.State.StrictimportControl.Monad.Trans.ReaderimportControl.Monad.Trans.ClassimportData.Vector((!))-- | A collection type that can be converted from a sequence of fields.-- Instances are provided for tuples up to 10 elements and lists of any length.---- Note that instances can defined outside of postgresql-simple, which is-- often useful. For example, here's an instance for a user-defined pair:---- @data User = User { name :: String, fileQuota :: Int }---- instance 'FromRow' User where-- fromRow = User \<$\> 'field' \<*\> 'field'-- @---- The number of calls to 'field' must match the number of fields returned-- in a single row of the query result. Otherwise, a 'ConversionFailed'-- exception will be thrown.---- Note that 'field' evaluates it's result to WHNF, so the caveats listed in-- previous versions of postgresql-simple no longer apply. Instead, look-- at the caveats associated with user-defined implementations of 'fromRow'.classFromRowawherefromRow::RowParserafield::FromFielda=>RowParserafield=RP$doletunCol(PQ.Colx)=fromIntegralx::IntRow{..}<-askcolumn<-liftgetlift(put(column+1))letncols=nfieldsrowresultif(column>=ncols)thendoletvals=map(\c->(typenames!(unColc),fmapellipsis(getvaluerowresultrowc)))[0..ncols-1]convertError=ConversionFailed(show(unColncols)++" values: "++showvals)("at least "++show(unColcolumn+1)++" slots in target type")"mismatch between number of columns to \
\convert and number in target type"lift(lift(Errors[SomeExceptionconvertError]))elsedolettypename=typenames!unColcolumnresult=rowresultfield=Field{..}lift(lift(fromFieldfield(getvalueresultrowcolumn)))ellipsis::ByteString->ByteStringellipsisbs|B.lengthbs>15=B.take10bs`B.append`"[...]"|otherwise=bsnumFieldsRemaining::RowParserIntnumFieldsRemaining=RP$doRow{..}<-askcolumn<-liftgetreturn$!(\(PQ.Colx)->fromIntegralx)(nfieldsrowresult-column)instance(FromFielda)=>FromRow(Onlya)wherefromRow=Only<$>fieldinstance(FromFielda,FromFieldb)=>FromRow(a,b)wherefromRow=(,)<$>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc)=>FromRow(a,b,c)wherefromRow=(,,)<$>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd)=>FromRow(a,b,c,d)wherefromRow=(,,,)<$>field<*>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd,FromFielde)=>FromRow(a,b,c,d,e)wherefromRow=(,,,,)<$>field<*>field<*>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd,FromFielde,FromFieldf)=>FromRow(a,b,c,d,e,f)wherefromRow=(,,,,,)<$>field<*>field<*>field<*>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd,FromFielde,FromFieldf,FromFieldg)=>FromRow(a,b,c,d,e,f,g)wherefromRow=(,,,,,,)<$>field<*>field<*>field<*>field<*>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd,FromFielde,FromFieldf,FromFieldg,FromFieldh)=>FromRow(a,b,c,d,e,f,g,h)wherefromRow=(,,,,,,,)<$>field<*>field<*>field<*>field<*>field<*>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd,FromFielde,FromFieldf,FromFieldg,FromFieldh,FromFieldi)=>FromRow(a,b,c,d,e,f,g,h,i)wherefromRow=(,,,,,,,,)<$>field<*>field<*>field<*>field<*>field<*>field<*>field<*>field<*>fieldinstance(FromFielda,FromFieldb,FromFieldc,FromFieldd,FromFielde,FromFieldf,FromFieldg,FromFieldh,FromFieldi,FromFieldj)=>FromRow(a,b,c,d,e,f,g,h,i,j)wherefromRow=(,,,,,,,,,)<$>field<*>field<*>field<*>field<*>field<*>field<*>field<*>field<*>field<*>fieldinstanceFromFielda=>FromRow[a]wherefromRow=don<-numFieldsRemainingreplicateMnfieldinstance(FromRowa,FromRowb)=>FromRow(a:.b)wherefromRow=(:.)<$>fromRow<*>fromRow