packages feed

hasql 0.7.1 → 0.7.2

raw patch · 8 files changed

+153/−98 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

hasql.cabal view
@@ -1,7 +1,7 @@ name:   hasql version:-  0.7.1+  0.7.2 synopsis:   A minimalistic general high level API for relational databases description:@@ -88,9 +88,10 @@     Haskell2010   other-modules:     Hasql.Prelude-    Hasql.QParser+    Hasql.QQ.Parser     Hasql.CxRow     Hasql.TH+    Hasql.QQ   exposed-modules:     Hasql   build-depends:
hspec-postgres/Main.hs view
@@ -12,6 +12,19 @@ main =    hspec $ do +    context "Multivalue clauses" $ do+      -- See http://www.postgresql.org/docs/current/interactive/functions-comparisons.html++      it "contains" $ do+        flip shouldBe (Right True) =<< do+          session $ +            fmap runIdentity $ H.tx Nothing $ H.singleEx $ [H.stmt|SELECT 2 = ANY (?)|] [1,2,3 :: Int]++      it "contains not" $ do+        flip shouldBe (Right False) =<< do+          session $ +            fmap runIdentity $ H.tx Nothing $ H.singleEx $ [H.stmt|SELECT 2 != ALL (?)|] [1,2,3 :: Int]+     context "Tx" $ do        it "does not commit if in uncommitting mode" $ do
hspec/Main.hs view
@@ -20,7 +20,14 @@ main =    hspec $ do     context "Quasi quoter" $ do-      it "generates a proper statement" $ do+      it "supports free variables" $ do+        let a = 'a'+            b = 'b'+            in+              (flip shouldBe)+                (HB.Stmt "SELECT (? + ?)" (V.fromList [HB.encodeValue a, HB.encodeValue b]) True)+                ([H.stmt| SELECT ($a + $b) |] :: HB.Stmt X)+      it "supports ordered placeholders" $ do         (flip shouldBe)           (HB.Stmt "SELECT (? + ?)" (V.fromList [HB.encodeValue 'a', HB.encodeValue 'b']) True)           ([H.stmt| SELECT (? + ?) |] 'a' 'b' :: HB.Stmt X)
library/Hasql.hs view
@@ -28,7 +28,7 @@    -- * Statement   Bknd.Stmt,-  stmt,+  QQ.stmt,    -- * Statement Execution   Ex,@@ -61,16 +61,12 @@ import Hasql.Prelude import qualified Hasql.Backend as Bknd import qualified Hasql.CxRow as CxRow-import qualified Hasql.QParser as QParser+import qualified Hasql.QQ as QQ import qualified ListT import qualified Data.Pool as Pool-import qualified Data.Text as Text import qualified Data.Vector as Vector import qualified Data.Vector.Mutable as MVector-import qualified Language.Haskell.TH as TH-import qualified Language.Haskell.TH.Quote as TH import qualified Language.Haskell.TH.Syntax as TH-import qualified Hasql.TH as THUtil   -- * Resources@@ -389,42 +385,3 @@     ListT.uncons .      (unsafeCoerce :: TxStreamListT s m r -> ListT.ListT m r) ---- * Statements quasi-quotation------------------------------ |--- Produces a lambda-expression, --- which takes as many parameters as there are placeholders in the quoted text--- and results in a 'Bknd.Stmt'. --- --- E.g.:--- --- >selectSum :: Int -> Int -> Stmt c--- >selectSum = [stmt|SELECT (? + ?)|]--- -stmt :: TH.QuasiQuoter-stmt = -  TH.QuasiQuoter-    (parseExp)-    (const $ fail "Pattern context is not supported")-    (const $ fail "Type context is not supported")-    (const $ fail "Declaration context is not supported")-  where-    parseExp s =-      do-        (t, n) <- either (fail . showString "Parsing failure: ") return (QParser.parse (fromString s))-        return $ statementF (Text.unpack t) (fromIntegral n)-    statementF s n =-      TH.LamE-        (map TH.VarP argNames)-        (THUtil.purify [|Bknd.Stmt $(pure statementE) $(pure argsE) True|])-      where-        argNames = -          map (TH.mkName . ('_' :) . show) [1 .. n]-        statementE = -          TH.LitE (TH.StringL s)-        argsE =-          THUtil.vectorE $-          map (\x -> THUtil.purify [| Bknd.encodeValue $(TH.varE x) |]) $-          argNames
library/Hasql/Prelude.hs view
@@ -13,6 +13,7 @@ ------------------------- import Control.Monad.Trans.State.Strict as Exports hiding (liftCallCC, liftCatch, liftListen, liftPass) import Control.Monad.Trans.Reader as Exports hiding (liftCallCC, liftCatch, liftListen, liftPass)+import Control.Monad.Trans.Writer as Exports hiding (liftCallCC, liftCatch, liftListen, liftPass) import Control.Monad.Trans.Maybe as Exports hiding (liftCallCC, liftCatch, liftListen, liftPass) import Control.Monad.Trans.Class as Exports import Control.Monad.IO.Class as Exports
− library/Hasql/QParser.hs
@@ -1,50 +0,0 @@-module Hasql.QParser where--import Hasql.Prelude hiding (takeWhile)-import Data.Attoparsec.Text hiding (Result)-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Builder as TLB----- |--- Produces a whitespace-cleaned text and a count of placeholders in it.-parse :: Text -> Either String (Text, Int)-parse = -  parseOnly $ singleTemplate--singleTemplate :: Parser (Text, Int)-singleTemplate =-  template <* -  ((endOfInput) <|>-   (() <$ skipSpace <* char ';' <* fail "A semicolon detected. Only single statements are allowed"))--template :: Parser (Text, Int)-template =-  flip runStateT 0 $ do-    lift $ skipSpace-    fmap (TL.toStrict . TLB.toLazyText . mconcat) $ -      many $ -        (mempty <$ lift trailingWhitespace) <|>-        (TLB.singleton ' ' <$ lift (takeWhile1 isSpace)) <|>-        (TLB.fromText <$> lift stringLit) <|>-        (TLB.singleton <$> lift (char '?') <* modify succ) <|>-        (TLB.singleton <$> lift (notChar ';'))--trailingWhitespace :: Parser ()-trailingWhitespace =-  () <$ takeWhile1 isSpace <* endOfInput--stringLit :: Parser Text-stringLit =-  do-    quote <- -      char '"' <|> char '\''-    content <- -      fmap mconcat $ many $ -        TLB.fromText <$> string "\\\\" <|> -        TLB.fromText <$> string (fromString ['\\', quote]) <|> -        TLB.singleton <$> notChar quote-    char quote-    return $ TL.toStrict . TLB.toLazyText $-      TLB.singleton quote <> content <> TLB.singleton quote
+ library/Hasql/QQ.hs view
@@ -0,0 +1,61 @@+module Hasql.QQ where++import Hasql.Prelude+import Hasql.TH+import Language.Haskell.TH+import Language.Haskell.TH.Quote+import Language.Haskell.TH.Syntax+import qualified Data.Text as Text+import qualified Hasql.QQ.Parser as Parser+import qualified Hasql.Backend as Bknd+++-- |+-- Produces a lambda-expression, +-- which takes as many parameters as there are placeholders in the quoted text+-- and results in a 'Bknd.Stmt'. +-- +-- E.g.:+-- +-- >selectSum :: Int -> Int -> Stmt c+-- >selectSum = [stmt|SELECT (? + ?)|]+-- +-- It also allows to directly refer to free variables like so:+-- +-- >selectSum :: Int -> Int -> Stmt c+-- >selectSum a b = [stmt|SELECT ($a + $b)|]+stmt :: QuasiQuoter+stmt = +  QuasiQuoter+    (parseExp)+    (const $ fail "Pattern context is not supported")+    (const $ fail "Type context is not supported")+    (const $ fail "Declaration context is not supported")+  where+    parseExp =+      fmap (uncurry statementF) .+      either (fail . showString "Parsing failure: ") return .+      Parser.parse .+      fromString+    statementF t params =+      LamE+        (map VarP argNames)+        (purify [|Bknd.Stmt $(pure statementE) $(pure argsE) True|])+      where+        (varNames, argNames) =+          (\(a, b) -> (reverse a, reverse b)) $ +          flip execState ([], []) $ forM_ params $ \case+            Parser.ParamName n ->+              modify $ \(a, b) -> (mkName (Text.unpack n) : a, b)+            Parser.OrderedPlaceholder ->+              modify $ \(a, b) -> +                let n = mkName $ '_' : show (length b + 1)+                    in (n : a, n : b)+            Parser.IndexedPlaceholder i ->+              fail "Indexed placeholders are not supported"+        statementE = +          LitE (StringL (Text.unpack t))+        argsE =+          vectorE $+          map (\x -> purify [| Bknd.encodeValue $(varE x) |]) $+          varNames
+ library/Hasql/QQ/Parser.hs view
@@ -0,0 +1,65 @@+module Hasql.QQ.Parser where++import Hasql.Prelude hiding (takeWhile)+import Data.Attoparsec.Text hiding (Result)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB+++type Result =+  (Text, [Param])++data Param =+  ParamName Text |+  OrderedPlaceholder |+  IndexedPlaceholder Int++-- |+-- Produces a whitespace-cleaned text and a count of placeholders in it.+parse :: Text -> Either String (Text, [Param])+parse = +  parseOnly $ singleTemplate++singleTemplate :: Parser (Text, [Param])+singleTemplate =+  template <* +  ((endOfInput) <|>+   (() <$ skipSpace <* char ';' <* fail "A semicolon detected, but only single statements are allowed"))++template :: Parser (Text, [Param])+template =+  runWriterT $ do+    lift $ skipSpace+    fmap (TL.toStrict . TLB.toLazyText . mconcat) $ +      many $ +        (mempty <$ lift (takeWhile1 isSpace <* endOfInput)) <|>+        (TLB.singleton ' ' <$ lift (takeWhile1 isSpace)) <|>+        (TLB.fromText <$> lift stringLit) <|>+        (TLB.singleton '?' <$ (lift param >>= tell . pure)) <|>+        (TLB.singleton <$> lift (notChar ';'))++stringLit :: Parser Text+stringLit =+  do+    quote <- +      char '"' <|> char '\''+    content <- +      fmap mconcat $ many $ +        TLB.fromText <$> string "\\\\" <|> +        TLB.fromText <$> string (fromString ['\\', quote]) <|> +        TLB.singleton <$> notChar quote+    char quote+    return $ TL.toStrict . TLB.toLazyText $+      TLB.singleton quote <> content <> TLB.singleton quote++param :: Parser Param+param =+  (char '$' *> ((ParamName <$> paramName) <|> (IndexedPlaceholder <$> decimal))) <|>+  (OrderedPlaceholder <$ char '?')++paramName :: Parser Text+paramName =+  T.cons <$> satisfy isLower <*> takeWhile (\c -> isAlphaNum c || elem c extraChars)+  where+    extraChars = "_'" :: [Char]