packages feed

mysql-haskell-nem (empty) → 0.1.0.0

raw patch · 7 files changed

+1062/−0 lines, 7 filesdep +basedep +bytestringdep +io-streamssetup-changed

Dependencies added: base, bytestring, io-streams, mysql-haskell, scientific, text, time

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright José Lorenzo Rodríguez (c) 2016++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Author name here nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Readme.md view
@@ -0,0 +1,41 @@+mysql-haskell-nem+=================++Provides a simpler interface for retrieving results when using the [mysql-haskell](http://hackage.haskell.org/package/mysql-haskell) package.++Guide+-----++The `Database.MySQL.Base` and `Database.MySQL.Nem` modules provides everything you need to start making queries:++```haskell+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Database.MySQL.Base+import Database.MySQL.Base.Nem+import Data.Text (unpack)+import qualified System.IO.Streams as Streams++main :: IO () +main = do+    conn <- connect+        defaultConnectInfo {ciUser = "username", ciPassword = "password", ciDatabase = "dbname"}++	results <- queryResults conn "SELECT email, name FROM users" >>=+	_ <-+		Streams.mapM_+			(\(email, name) -> print $ (Text.unpack email) ++ ":" ++ (name :: String) ) results >>=+		Streams.toList+```++It's recommended to use prepared statement to improve query speed:++```haskell+    ...+    s <- prepareStmt conn "SELECT * FROM some_table where person_age > ?"+    ...+    results <- queryStmtResutls s [MySQLInt32U 18]+    ...+```
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ mysql-haskell-nem.cabal view
@@ -0,0 +1,34 @@+name:                mysql-haskell-nem+version:             0.1.0.0+synopsis:            Adds a interface like mysql-simple to mysql-haskell.+description:         Please see README.md+homepage:            https://github.com/lorenzo/mysql-haskell-nem#readme+license:             BSD3+license-file:        LICENSE+author:              José Lorenzo Rodríguez+                   , Bryan O'Sullivan+                   , Paul Rouse+maintainer:          jose.zap@gmail.com+copyright:           2016 José Lorenzo Rodríguez+category:            Database+build-type:          Simple+extra-source-files:  Readme.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Database.MySQL.Nem+                     , Database.MySQL.Nem.QueryResults+                     , Database.MySQL.Nem.Result+  build-depends:       base >= 4.7 && < 5+                     , mysql-haskell+                     , bytestring+                     , text+                     , time+                     , scientific+                     , io-streams+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/lorenzo/mysql-haskell-nem
+ src/Database/MySQL/Nem.hs view
@@ -0,0 +1,74 @@+module Database.MySQL.Nem+  ( module Database.MySQL.Nem.QueryResults+  , module Database.MySQL.Nem.Result+   -- * Extracting results+   -- $result+  , queryResults+  , queryStmtResults+  ) where++import Database.MySQL.Base+import Database.MySQL.Nem.QueryResults+import Database.MySQL.Nem.Result+import qualified System.IO.Streams as Streams++-- | Execute a MySQL query which return a result-set converted to the specified+-- haskell type+--+-- Note that you must fully consumed the result-set before start a new query on+-- the same 'MySQLConn', or an 'UnconsumedResultSet' will be thrown.+-- if you want to skip the result-set, use 'Stream.skipToEof'.+--+queryResults+  :: (QueryResults r)+  => MySQLConn -> Query -> IO (Streams.InputStream r)+queryResults conn qry = do+  (defs, results) <- query_ conn qry+  Streams.map (convertResults defs) results++-- | Execute prepared query statement with parameters, expecting resultset.+--+--+-- Note that you must fully consumed the result-set before start a new query on+-- the same 'MySQLConn', or an 'UnconsumedResultSet' will be thrown.+-- if you want to skip the result-set, use 'Stream.skipToEof'.+--+queryStmtResults+  :: (QueryResults r)+  => MySQLConn -> StmtID -> [MySQLValue] -> IO (Streams.InputStream r)+queryStmtResults conn qry params = do+  (defs, results) <- queryStmt conn qry params+  Streams.map (convertResults defs) results+--+-- $result+--+-- The 'queryResults' and 'queryStmtResults' functions return a list of values in the+-- 'QueryResults' typeclass. This class performs automatic extraction+-- and type conversion of rows from a query result.+--+-- Here is a simple example of how to extract results:+--+-- > import qualified Data.Text as Text+-- > import Database.MySQL.Nem+-- > import qualified System.IO.Streams as Streams+-- >+-- > xs <- queryResults conn "select name,age from users"+-- > Streams.mapM_+-- >    \(name,age) ->+-- >       putStrLn $ Text.unpack name ++ " is " ++ show (age :: Int)+-- >    xs+--+-- Notice two important details about this code:+--+-- * The number of columns we ask for in the query template must+--   exactly match the number of elements we specify in a row of the+--   result tuple.  If they do not match, a 'ResultError' exception+--   will be thrown.+--+-- * Sometimes, the compiler needs our help in specifying types. It+--   can infer that @name@ must be a 'Text', due to our use of the+--   @unpack@ function. However, we have to tell it the type of @age@,+--   as it has no other information to determine the exact type.+--+--   For converting to your custom data types. Check the documentation for+--   the QueryResults package.
+ src/Database/MySQL/Nem/QueryResults.hs view
@@ -0,0 +1,711 @@+{-# 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")
+ src/Database/MySQL/Nem/Result.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE DeriveDataTypeable, FlexibleInstances #-}++-- |+-- Module:      Database.MySQL.Simple.Result+-- Copyright:   (c) 2011 MailRank, Inc.+-- License:     BSD3+-- Maintainer:  José Lorenzo Rodríguez+-- Stability:   experimental+-- Portability: portable+--+-- The 'Result' typeclass, for converting a single value in a row+-- returned by a SQL query into a more useful Haskell representation.+--+-- A Haskell numeric type is considered to be compatible with all+-- MySQL numeric types that are less accurate than it. For instance,+-- the Haskell 'Double' type is compatible with the MySQL 'Long' type+-- because it can represent a 'Long' exactly. On the other hand, since+-- a 'Double' might lose precision if representing a 'LongLong', the+-- two are /not/ considered compatible.+module Database.MySQL.Nem.Result+  ( ResultError(..)+  , Result(..)+  ) where++import Control.Exception (Exception, throw)+import Data.Int+import Data.Scientific (Scientific, fromFloatDigits)+import Data.Time.Calendar (Day)+import Data.Time.LocalTime (LocalTime)+import Data.Typeable (Typeable)+import Database.MySQL.Base (MySQLValue(..), ColumnDef(..))+import qualified Data.ByteString as ByteString (ByteString, unpack)+import qualified Data.Text as Text (Text, unpack)++-- | Exception thrown if conversion from a SQL value to a Haskell+-- value fails.+data ResultError+  = Incompatible { errColumnName :: String+                 , errHaskellType :: String+                 , errMessage :: String}+  | ConversionFailed { errColumnName :: String+                     , errHaskellType :: String+                     , errMessage :: String}+  deriving (Eq, Show, Typeable)++instance Exception ResultError++-- | A type that may be converted from a SQL type.+class Result a  where+  convert :: ColumnDef -> MySQLValue -> a -- Convert a MySQLValue to another value++instance (Result a) =>+         Result (Maybe a) where+  convert def val =+    case val of+      MySQLNull -> Nothing+      _ -> Just $ convert def val++instance Result Int where+  convert = intConvert "Int"++instance Result Int8 where+  convert def val =+    case val of+      MySQLInt8U i -> fromIntegral i+      MySQLInt8 i -> fromIntegral i+      _ -> throw $ conversionFailed "Int8" val def++instance Result Int16 where+  convert def val =+    case val of+      MySQLInt8U i -> fromIntegral i+      MySQLInt16U i -> fromIntegral i+      MySQLInt8 i -> fromIntegral i+      MySQLInt16 i -> fromIntegral i+      _ -> throw $ conversionFailed "Int16" val def++instance Result Int32 where+  convert def val =+    case val of+      MySQLInt8U i -> fromIntegral i+      MySQLInt16U i -> fromIntegral i+      MySQLInt32U i -> fromIntegral i+      MySQLInt8 i -> fromIntegral i+      MySQLInt16 i -> fromIntegral i+      MySQLInt32 i -> fromIntegral i+      _ -> throw $ conversionFailed "Int32" val def++instance Result Int64 where+  convert = intConvert "Int64"++instance Result Float where+  convert def val =+    case val of+      MySQLFloat f -> f+      _ -> throw $ conversionFailed "Float" val def++instance Result Double where+  convert def val =+    case val of+      MySQLDouble d -> d+      _ -> throw $ conversionFailed "Double" val def++instance Result Text.Text where+  convert def val =+    case val of+      MySQLText t -> t+      _ -> throw $ conversionFailed "Text" val def++instance Result String where+  convert def val =+    case val of+      MySQLText t -> Text.unpack t+      _ -> throw $ conversionFailed "String" val def++instance Result ByteString.ByteString where+  convert def val =+    case val of+      MySQLBytes t -> t+      _ -> throw $ conversionFailed "ByteString" val def++instance Result Day where+  convert def val =+    case val of+      MySQLDate d -> d+      _ -> throw $ conversionFailed "Day" val def++instance Result LocalTime where+  convert def val =+    case val of+      MySQLDateTime d -> d+      MySQLTimeStamp d -> d+      _ -> throw $ conversionFailed "LocalTime" val def++instance Result Scientific where+  convert def val =+    case val of+      MySQLDecimal d -> d+      MySQLFloat f -> fromFloatDigits f+      MySQLDouble f -> fromFloatDigits f+      MySQLInt8U i -> fromIntegral i+      MySQLInt16U i -> fromIntegral i+      MySQLInt32U i -> fromIntegral i+      MySQLInt64U i -> fromIntegral i+      MySQLInt8 i -> fromIntegral i+      MySQLInt16 i -> fromIntegral i+      MySQLInt32 i -> fromIntegral i+      MySQLInt64 i -> fromIntegral i+      _ -> throw $ conversionFailed "Scientific" val def++intConvert+  :: Num a+  => String -> ColumnDef -> MySQLValue -> a+intConvert t def val =+  case val of+    MySQLInt8U i -> fromIntegral i+    MySQLInt16U i -> fromIntegral i+    MySQLInt32U i -> fromIntegral i+    MySQLInt64U i -> fromIntegral i+    MySQLInt8 i -> fromIntegral i+    MySQLInt16 i -> fromIntegral i+    MySQLInt32 i -> fromIntegral i+    MySQLInt64 i -> fromIntegral i+    _ -> throw $ conversionFailed t val def++conversionFailed t v def =+  Incompatible+    (show . ByteString.unpack . columnName $ def)+    t+    ("Could not convert: " ++ show v)