{-# LANGUAGE BangPatterns, OverloadedStrings #-} -- | -- Module: Database.MySQL.Simpe.QueryResults -- Copyright: (c) 2011 MailRank, Inc. -- License: BSD3 -- Maintainer: Paul Rouse -- 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. module Database.MySQL.Simple.QueryResults ( QueryResults(..) , convertError ) where import Control.Exception (throw) import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as B import Database.MySQL.Base.Types (Field(fieldType, fieldName)) import Database.MySQL.Simple.Result (ResultError(..), Result(..)) import Database.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 = 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 2 -- @ class QueryResults a where convertResults :: [Field] -> [Maybe ByteString] -> a -- ^ Convert values from a row into a Haskell collection. -- -- This function will throw a 'ResultError' if conversion of the -- collection fails. instance (Result a) => QueryResults (Only a) where convertResults [fa] [va] = Only a where !a = convert fa va convertResults fs vs = convertError fs vs 1 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 instance (Result a, Result b, Result c) => QueryResults (a,b,c) where convertResults [fa,fb,fc] [va,vb,vc] = (a,b,c) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc convertResults fs vs = convertError fs vs 3 instance (Result a, Result b, Result c, Result d) => QueryResults (a,b,c,d) where convertResults [fa,fb,fc,fd] [va,vb,vc,vd] = (a,b,c,d) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd convertResults fs vs = convertError fs vs 4 instance (Result a, Result b, Result c, Result d, Result e) => QueryResults (a,b,c,d,e) where convertResults [fa,fb,fc,fd,fe] [va,vb,vc,vd,ve] = (a,b,c,d,e) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve convertResults fs vs = convertError fs vs 5 instance (Result a, Result b, Result c, Result d, Result e, Result f) => QueryResults (a,b,c,d,e,f) where convertResults [fa,fb,fc,fd,fe,ff] [va,vb,vc,vd,ve,vf] = (a,b,c,d,e,f) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf convertResults fs vs = convertError fs vs 6 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g) => QueryResults (a,b,c,d,e,f,g) where convertResults [fa,fb,fc,fd,fe,ff,fg] [va,vb,vc,vd,ve,vf,vg] = (a,b,c,d,e,f,g) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg convertResults fs vs = convertError fs vs 7 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h) => QueryResults (a,b,c,d,e,f,g,h) where convertResults [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 = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh convertResults fs vs = convertError fs vs 8 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i) => QueryResults (a,b,c,d,e,f,g,h,i) where convertResults [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 = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi convertResults fs vs = convertError fs vs 9 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j) => QueryResults (a,b,c,d,e,f,g,h,i,j) where convertResults [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 = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj convertResults fs vs = convertError fs vs 10 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k) => QueryResults (a,b,c,d,e,f,g,h,i,j,k) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk] = (a,b,c,d,e,f,g,h,i,j,k) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk convertResults fs vs = convertError fs vs 11 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl] = (a,b,c,d,e,f,g,h,i,j,k,l) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl convertResults fs vs = convertError fs vs 12 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm] = (a,b,c,d,e,f,g,h,i,j,k,l,m) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm convertResults fs vs = convertError fs vs 13 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn convertResults fs vs = convertError fs vs 14 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo convertResults fs vs = convertError fs vs 15 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; convertResults fs vs = convertError fs vs 16 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p, Result q) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp,vq] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; !q = convert fq vq; convertResults fs vs = convertError fs vs 17 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p, Result q, Result r) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq,fr] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp,vq,vr] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; !q = convert fq vq; !r = convert fr vr convertResults fs vs = convertError fs vs 18 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p, Result q, Result r, Result s) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq,fr,fs] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp,vq,vr,vs] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; !q = convert fq vq; !r = convert fr vr !s = convert fs vs; convertResults fs_ vs_ = convertError fs_ vs_ 19 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p, Result q, Result r, Result s, Result t, Result u, Result v) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq,fr,fs, ft,fu,fv] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp,vq,vr,vs, vt,vu,vv] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; !q = convert fq vq; !r = convert fr vr !s = convert fs vs; !t = convert ft vt; !u = convert fu vu !v = convert fv vv; convertResults fs_ vs_ = convertError fs_ vs_ 22 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p, Result q, Result r, Result s, Result t, Result u, Result v, Result w) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq,fr,fs, ft,fu,fv,fw] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp,vq,vr,vs, vt,vu,vv,vw] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; !q = convert fq vq; !r = convert fr vr !s = convert fs vs; !t = convert ft vt; !u = convert fu vu !v = convert fv vv; !w = convert fw vw; convertResults fs_ vs_ = convertError fs_ vs_ 23 instance (Result a, Result b, Result c, Result d, Result e, Result f, Result g, Result h, Result i, Result j, Result k, Result l, Result m, Result n, Result o, Result p, Result q, Result r, Result s, Result t, Result u, Result v, Result w, Result x) => QueryResults (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x) where convertResults [fa,fb,fc,fd,fe,ff,fg,fh,fi,fj,fk,fl,fm,fn,fo,fp,fq,fr,fs, ft,fu,fv,fw,fx] [va,vb,vc,vd,ve,vf,vg,vh,vi,vj,vk,vl,vm,vn,vo,vp,vq,vr,vs, vt,vu,vv,vw,vx] = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x) where !a = convert fa va; !b = convert fb vb; !c = convert fc vc !d = convert fd vd; !e = convert fe ve; !f = convert ff vf !g = convert fg vg; !h = convert fh vh; !i = convert fi vi !j = convert fj vj; !k = convert fk vk; !l = convert fl vl !m = convert fm vm; !n = convert fn vn; !o = convert fo vo !p = convert fp vp; !q = convert fq vq; !r = convert fr vr !s = convert fs vs; !t = convert ft vt; !u = convert fu vu !v = convert fv vv; !w = convert fw vw; !x = convert fx vx; convertResults fs_ vs_ = convertError fs_ vs_ 24 -- | 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. -> [Maybe ByteString] -- ^ 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. -> a convertError fs vs n = throw $ ConversionFailed (show (length fs) ++ " values: " ++ show (zip (map fieldType fs) (map (fmap ellipsis) vs))) (show n ++ " slots in target type") (show (map (B.unpack . fieldName) fs)) "mismatch between number of columns to convert and number in target type" ellipsis :: ByteString -> ByteString ellipsis bs | B.length bs > 15 = B.take 10 bs `B.append` "[...]" | otherwise = bs