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 +30/−0
- Readme.md +41/−0
- Setup.hs +2/−0
- mysql-haskell-nem.cabal +34/−0
- src/Database/MySQL/Nem.hs +74/−0
- src/Database/MySQL/Nem/QueryResults.hs +711/−0
- src/Database/MySQL/Nem/Result.hs +170/−0
+ 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)