{-# LANGUAGE BangPatterns, OverloadedStrings #-} -- | -- Module: Database.MySQL.Simpe.QueryResults -- Copyright: (c) 2011 MailRank, Inc. -- License: BSD3 -- Maintainer: José Lorenzo Rodríguez -- 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 24 -- elements. module Database.MySQL.Nem.QueryResults ( QueryResults(..) , convertError ) where import Control.Exception (throw) import Database.MySQL.Base (ColumnDef(..), MySQLValue) import Database.MySQL.Nem.Result (ResultError(..), Result(..)) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as B8 -- | A collection type that can be converted from a MySQL row result. -- -- 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 -- Convert values from a row into a Haskell collection. -- -- This function will throw a 'ResultError' if conversion of the -- collection fails. where convertResults :: [ColumnDef] -> [MySQLValue] -> a 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 :: [ColumnDef] -- ^ Descriptors of fields to be converted. -> [MySQLValue] -- ^ 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 (map (B8.unpack . columnName) fs)) ("Tried to create a Tuple of " ++ show n ++ " elements") ("Mismatch between number of columns to convert and number in target type. Source: " ++ (show . length) vs ++ " columns, Target: " ++ show n ++ " elements")