git.iko.soy/typeable/postgresql-simple
on master help sign in
Convert some mysql-simple documentation to postgresql-simple
5f045ccLeon P Smith
src/Database/PostgreSQL/Simple/QueryResults.hs+32−19
@@ -30,6 +30,7 @@ import Data.Either()
30import Database.PostgreSQL.Simple.Internal
30import Database.PostgreSQL.Simple.Internal
31import Database.PostgreSQL.Simple.Result (ResultError(..), Result(..))
31import Database.PostgreSQL.Simple.Result (ResultError(..), Result(..))
32import Database.PostgreSQL.Simple.Types (Only(..))
32import Database.PostgreSQL.Simple.Types (Only(..))
33+import qualified Database.PostgreSQL.LibPQ as LibPQ (Result)
33
34
34-- | A collection type that can be converted from a list of strings.
35-- | A collection type that can be converted from a list of strings.
35--
36--
@@ -42,41 +43,53 @@ import Database.PostgreSQL.Simple.Types (Only(..))
42--
43--
43-- @
44-- @
44-- instance ('Result' a, 'Result' b) => 'QueryResults' (a,b) where
45-- instance ('Result' a, 'Result' b) => 'QueryResults' (a,b) where
45−-- 'convertResults' [fa,fb] [va,vb] = (a,b)
46+-- 'convertResults' [fa,fb] [va,vb] = do
46−-- where !a = 'convert' fa va
47+-- !a <- 'convert' fa va
47−-- !b = 'convert' fb vb
48+-- !b <- 'convert' fb vb
49+-- 'return' (a,b)
48-- 'convertResults' fs vs = 'convertError' fs vs 2
50-- 'convertResults' fs vs = 'convertError' fs vs 2
49-- @
51-- @
50--
52--
51-- Notice that this instance evaluates each element to WHNF before
53-- Notice that this instance evaluates each element to WHNF before
52−-- constructing the pair. By doing this, we guarantee two important
54+-- constructing the pair. This property is important enough that its
53−-- properties:
55+-- a rule all 'QueryResult' instances should follow:
54--
56--
55−-- * Keep resource usage under control by preventing the construction
57+-- * Evaluate every 'Result' value to WHNF before constructing
56−-- of potentially long-lived thunks.
58+-- the result
57--
59--
58−-- * Ensure that any 'ResultError' that might arise is thrown
60+-- Doing so keeps resource usage under local control by preventing the
59−-- immediately, rather than some place later in application code
61+-- construction of potentially long-lived thunks that are forced
60−-- that cannot handle it.
62+-- (or not) by the consumer.
61--
63--
62−-- You can also declare Haskell types of your own to be instances of
64+-- This is important to postgresql-simple-0.0.4 because a wayward thunk
63−-- 'QueryResults'.
65+-- causes the entire LibPQ.'LibPQ.Result' to be retained. This could lead
66+-- to a memory leak, depending on how the thunk is consumed.
67+--
68+-- Note that instances can be defined outside of postgresql-simple,
69+-- which is often useful. For example, here is an attempt at an
70+-- instance for a user-defined pair:
64--
71--
65-- @
72-- @
66−--data User { firstName :: String, lastName :: String }
73+-- data User = User { firstName :: String, lastName :: String }
67--
74--
68−--instance 'QueryResults' User where
75+-- instance 'QueryResults' User where
69−-- 'convertResults' [fa,fb] [va,vb] = User a b
76+-- 'convertResults' [fa,qfb] [va,vb] = User \<$\> a \<*\> b
70−-- where !a = 'convert' fa va
77+-- where !a = 'convert' fa va
71−-- !b = 'convert' fb vb
78+-- !b = 'convert' fb vb
72−-- 'convertResults' fs vs = 'convertError' fs vs
79+-- 'convertResults' fs vs = 'convertError' fs vs 2
73-- @
80-- @
81+--
82+-- In this example, the bang patterns are not used correctly. They force
83+-- the data constructors of the 'Either' type, and are not forcing the
84+-- 'Result' values we need to force. This gives the consumer of the
85+-- 'QueryResult' the ability to cause the memory leak, which is an
86+-- undesirable state of affairs.
74
87
75class QueryResults a where
88class QueryResults a where
76 convertResults :: [Field] -> [Maybe ByteString] -> Either SomeException a
89 convertResults :: [Field] -> [Maybe ByteString] -> Either SomeException a
77 -- ^ Convert values from a row into a Haskell collection.
90 -- ^ Convert values from a row into a Haskell collection.
78 --
91 --
79− -- This function will throw a 'ResultError' if conversion of the
92+ -- This function will return a 'ResultError' if conversion of the
80 -- collection fails.
93 -- collection fails.
81
94
82instance (Result a) => QueryResults (Only a) where
95instance (Result a) => QueryResults (Only a) where