{-# LANGUAGE BangPatterns, OverloadedStrings #-}-- |-- Module: Database.MySQL.Simpe.QueryResults-- Copyright: (c) 2011 MailRank, Inc.-- License: BSD3-- Maintainer: Bryan O'Sullivan <bos@serpentine.com>-- Stability: experimental-- Portability: portable---- The 'QueryResults' 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.MySQL.Simple.QueryResults(QueryResults(..),convertError)whereimportControl.Exception(throw)importData.ByteString(ByteString)importqualifiedData.ByteString.Char8asBimportDatabase.MySQL.Base.Types(Field(fieldType))importDatabase.MySQL.Simple.Result(ResultError(..),Result(..))importDatabase.MySQL.Simple.Types(Only(..))-- | A collection type that can be converted from a list of strings.---- Instances should use the 'convert' method of the 'Result' class-- to perform conversion of each element of the collection.---- This example instance demonstrates how to convert a two-column row-- into a Haskell pair. Each field in the metadata is paired up with-- each value from the row, and the two are passed to 'convert'.---- @-- instance ('Result' a, 'Result' b) => 'QueryResults' (a,b) where-- 'convertResults' [fa,fb] [va,vb] = (a,b)-- where !a = 'convert' fa va-- !b = 'convert' fb vb-- 'convertResults' fs vs = 'convertError' fs vs 2-- @---- Notice that this instance evaluates each element to WHNF before-- constructing the pair. By doing this, we guarantee two important-- properties:---- * Keep resource usage under control by preventing the construction-- of potentially long-lived thunks.---- * Ensure that any 'ResultError' that might arise is thrown-- immediately, rather than some place later in application code-- that cannot handle it.---- You can also declare Haskell types of your own to be instances of-- 'QueryResults'.---- @--data User { firstName :: String, lastName :: String }----instance 'QueryResults' User where-- 'convertResults' [fa,fb] [va,vb] = User a b-- where !a = 'convert' fa va-- !b = 'convert' fb vb-- 'convertResults' fs vs = 'convertError' fs vs-- @classQueryResultsawhereconvertResults::[Field]->[MaybeByteString]->a-- ^ Convert values from a row into a Haskell collection.---- This function will throw a 'ResultError' if conversion of the-- collection fails.instance(Resulta)=>QueryResults(Onlya)whereconvertResults[fa][va]=Onlyawhere!a=convertfavaconvertResultsfsvs=convertErrorfsvs1instance(Resulta,Resultb)=>QueryResults(a,b)whereconvertResults[fa,fb][va,vb]=(a,b)where!a=convertfava;!b=convertfbvbconvertResultsfsvs=convertErrorfsvs2instance(Resulta,Resultb,Resultc)=>QueryResults(a,b,c)whereconvertResults[fa,fb,fc][va,vb,vc]=(a,b,c)where!a=convertfava;!b=convertfbvb;!c=convertfcvcconvertResultsfsvs=convertErrorfsvs3instance(Resulta,Resultb,Resultc,Resultd)=>QueryResults(a,b,c,d)whereconvertResults[fa,fb,fc,fd][va,vb,vc,vd]=(a,b,c,d)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvdconvertResultsfsvs=convertErrorfsvs4instance(Resulta,Resultb,Resultc,Resultd,Resulte)=>QueryResults(a,b,c,d,e)whereconvertResults[fa,fb,fc,fd,fe][va,vb,vc,vd,ve]=(a,b,c,d,e)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvd;!e=convertfeveconvertResultsfsvs=convertErrorfsvs5instance(Resulta,Resultb,Resultc,Resultd,Resulte,Resultf)=>QueryResults(a,b,c,d,e,f)whereconvertResults[fa,fb,fc,fd,fe,ff][va,vb,vc,vd,ve,vf]=(a,b,c,d,e,f)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvd;!e=convertfeve;!f=convertffvfconvertResultsfsvs=convertErrorfsvs6instance(Resulta,Resultb,Resultc,Resultd,Resulte,Resultf,Resultg)=>QueryResults(a,b,c,d,e,f,g)whereconvertResults[fa,fb,fc,fd,fe,ff,fg][va,vb,vc,vd,ve,vf,vg]=(a,b,c,d,e,f,g)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvd;!e=convertfeve;!f=convertffvf!g=convertfgvgconvertResultsfsvs=convertErrorfsvs7instance(Resulta,Resultb,Resultc,Resultd,Resulte,Resultf,Resultg,Resulth)=>QueryResults(a,b,c,d,e,f,g,h)whereconvertResults[fa,fb,fc,fd,fe,ff,fg,fh][va,vb,vc,vd,ve,vf,vg,vh]=(a,b,c,d,e,f,g,h)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvd;!e=convertfeve;!f=convertffvf!g=convertfgvg;!h=convertfhvhconvertResultsfsvs=convertErrorfsvs8instance(Resulta,Resultb,Resultc,Resultd,Resulte,Resultf,Resultg,Resulth,Resulti)=>QueryResults(a,b,c,d,e,f,g,h,i)whereconvertResults[fa,fb,fc,fd,fe,ff,fg,fh,fi][va,vb,vc,vd,ve,vf,vg,vh,vi]=(a,b,c,d,e,f,g,h,i)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvd;!e=convertfeve;!f=convertffvf!g=convertfgvg;!h=convertfhvh;!i=convertfiviconvertResultsfsvs=convertErrorfsvs9instance(Resulta,Resultb,Resultc,Resultd,Resulte,Resultf,Resultg,Resulth,Resulti,Resultj)=>QueryResults(a,b,c,d,e,f,g,h,i,j)whereconvertResults[fa,fb,fc,fd,fe,ff,fg,fh,fi,fj][va,vb,vc,vd,ve,vf,vg,vh,vi,vj]=(a,b,c,d,e,f,g,h,i,j)where!a=convertfava;!b=convertfbvb;!c=convertfcvc!d=convertfdvd;!e=convertfeve;!f=convertffvf!g=convertfgvg;!h=convertfhvh;!i=convertfivi!j=convertfjvjconvertResultsfsvs=convertErrorfsvs10-- | Throw a 'ConversionFailed' exception, indicating a mismatch-- between the number of columns in the 'Field' and row, and the-- number in the collection to be converted to.convertError::[Field]-- ^ Descriptors of fields to be converted.->[MaybeByteString]-- ^ Contents of the row to be converted.->Int-- ^ Number of columns expected for conversion. For-- instance, if converting to a 3-tuple, the number to-- provide here would be 3.->aconvertErrorfsvsn=throw$ConversionFailed(show(lengthfs)++" values: "++show(zip(mapfieldTypefs)(map(fmapellipsis)vs)))(shown++" slots in target type")"mismatch between number of columns to convert and number in target type"ellipsis::ByteString->ByteStringellipsisbs|B.lengthbs>15=B.take10bs`B.append`"[...]"|otherwise=bs