{-# LANGUAGE RecordWildCards #-}-------------------------------------------------------------------------------- |-- Module: Database.PostgreSQL.Simple.FromRow-- Copyright: (c) 2012 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,fieldWith,numFieldsRemaining)whereimportControl.Applicative(Applicative(..),(<$>))importControl.Monad(replicateM)importData.ByteString(ByteString)importqualifiedData.ByteString.Char8asBimportDatabase.PostgreSQL.Simple.Types(Only(..))importqualifiedDatabase.PostgreSQL.LibPQasPQimportDatabase.PostgreSQL.Simple.InternalimportDatabase.PostgreSQL.Simple.CompatimportDatabase.PostgreSQL.Simple.FromFieldimportDatabase.PostgreSQL.Simple.OkimportDatabase.PostgreSQL.Simple.Types((:.)(..))importDatabase.PostgreSQL.Simple.TypeInfoimportControl.Monad.Trans.State.StrictimportControl.Monad.Trans.ReaderimportControl.Monad.Trans.Class-- | 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 be 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::RowParseragetvalue::PQ.Result->PQ.Row->PQ.Column->MaybeByteStringgetvalueresultrowcol=unsafeDupablePerformIO(PQ.getvalueresultrowcol)nfields::PQ.Result->PQ.Columnnfieldsresult=unsafeDupablePerformIO(PQ.nfieldsresult)getTypeInfoByCol::Row->PQ.Column->ConversionTypeInfogetTypeInfoByColRow{..}col=Conversion$\conn->dooid<-PQ.ftyperowresultcolOk<$>getTypeInfoconnoidgetTypenameByCol::Row->PQ.Column->ConversionByteStringgetTypenameByColrowcol=typname<$>getTypeInfoByColrowcolfieldWith::FieldParsera->RowParserafieldWithfieldP=RP$doletunCol(PQ.Colx)=fromIntegralx::Intr@Row{..}<-askcolumn<-liftgetlift(put(column+1))letncols=nfieldsrowresultif(column>=ncols)thenlift$lift$dovals<-mapM(getTypenameByColr)[0..ncols-1]leterr=ConversionFailed(show(unColncols)++" values: "++show(mapellipsisvals))Nothing""("at least "++show(unColcolumn+1)++" slots in target type")"mismatch between number of columns to \
\convert and number in target type"conversionErrorerrelsedolet!result=rowresult!typeOid=unsafeDupablePerformIO(PQ.ftyperesultcolumn)!field=Field{..}lift(lift(fieldPfield(getvalueresultrowcolumn)))field::FromFielda=>RowParserafield=fieldWithfromFieldellipsis::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