hasql-cursor-query (empty) → 0.4
raw patch · 17 files changed
+475/−0 lines, 17 filesdep +QuickCheckdep +basedep +base-preludesetup-changed
Dependencies added: QuickCheck, base, base-prelude, bytestring, contravariant, foldl, hasql, hasql-cursor-query, hasql-cursor-transaction, hasql-transaction, profunctors, quickcheck-instances, rebase, tasty, tasty-hunit, tasty-quickcheck, tasty-smallcheck
Files
- LICENSE +22/−0
- Setup.hs +2/−0
- hasql-cursor-query.cabal +100/−0
- library/Hasql/CursorQuery.hs +19/−0
- library/Hasql/CursorQuery/CursorTransactions.hs +7/−0
- library/Hasql/CursorQuery/Private/CursorQuery.hs +69/−0
- library/Hasql/CursorQuery/Private/CursorTransactions.hs +43/−0
- library/Hasql/CursorQuery/Private/Decoders.hs +11/−0
- library/Hasql/CursorQuery/Private/Prelude.hs +23/−0
- library/Hasql/CursorQuery/Private/Sessions.hs +17/−0
- library/Hasql/CursorQuery/Private/Transactions.hs +15/−0
- library/Hasql/CursorQuery/Sessions.hs +7/−0
- library/Hasql/CursorQuery/Transactions.hs +7/−0
- tasty/Main.hs +29/−0
- tasty/Main/CursorQueries.hs +41/−0
- tasty/Main/IO.hs +31/−0
- tasty/Main/Queries.hs +32/−0
+ LICENSE view
@@ -0,0 +1,22 @@+Copyright (c) 2016, Nikita Volkov++Permission is hereby granted, free of charge, to any person+obtaining a copy of this software and associated documentation+files (the "Software"), to deal in the Software without+restriction, including without limitation the rights to use,+copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the+Software is furnished to do so, subject to the following+conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hasql-cursor-query.cabal view
@@ -0,0 +1,100 @@+name:+ hasql-cursor-query+version:+ 0.4+category:+ Hasql, Database, PostgreSQL, Streaming+synopsis:+ A declarative abstraction over PostgreSQL Cursor+homepage:+ https://github.com/nikita-volkov/hasql-cursor-query +bug-reports:+ https://github.com/nikita-volkov/hasql-cursor-query/issues +author:+ Nikita Volkov <nikita.y.volkov@mail.ru>+maintainer:+ Nikita Volkov <nikita.y.volkov@mail.ru>+copyright:+ (c) 2016, Nikita Volkov+license:+ MIT+license-file:+ LICENSE+build-type:+ Simple+cabal-version:+ >=1.10+++source-repository head+ type:+ git+ location:+ git://github.com/nikita-volkov/hasql-cursor-query.git+++library+ hs-source-dirs:+ library+ ghc-options:+ default-extensions:+ Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+ default-language:+ Haskell2010+ other-modules:+ Hasql.CursorQuery.Private.Prelude+ Hasql.CursorQuery.Private.CursorQuery+ Hasql.CursorQuery.Private.Decoders+ Hasql.CursorQuery.Private.Transactions+ Hasql.CursorQuery.Private.CursorTransactions+ Hasql.CursorQuery.Private.Sessions+ exposed-modules:+ Hasql.CursorQuery.Transactions+ Hasql.CursorQuery.CursorTransactions+ Hasql.CursorQuery.Sessions+ Hasql.CursorQuery+ build-depends:+ -- database:+ hasql >= 0.19 && < 0.20,+ hasql-transaction >= 0.4.5.1 && < 0.5,+ hasql-cursor-transaction >= 0.5 && < 0.6,+ -- data:+ bytestring >= 0.10 && < 0.11,+ -- control:+ foldl > 1 && < 2,+ profunctors == 5.*,+ contravariant >= 1.3 && < 2,+ -- general:+ base-prelude >= 0.1.19 && < 2,+ base >= 4.6 && < 5+++test-suite tasty+ type:+ exitcode-stdio-1.0+ hs-source-dirs:+ tasty+ main-is:+ Main.hs+ other-modules:+ Main.CursorQueries+ Main.Queries+ Main.IO+ default-extensions:+ Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+ default-language:+ Haskell2010+ build-depends:+ -- database:+ hasql,+ hasql-cursor-query,+ -- testing:+ tasty == 0.11.*,+ tasty-quickcheck == 0.8.*,+ tasty-smallcheck == 0.8.*,+ tasty-hunit == 0.9.*,+ quickcheck-instances >= 0.3.11 && < 0.4,+ QuickCheck >= 2.8.1 && < 2.9,+ -- + foldl >= 1.2 && < 2,+ rebase < 2
+ library/Hasql/CursorQuery.hs view
@@ -0,0 +1,19 @@+-- |+-- A DSL for declaring queries.+module Hasql.CursorQuery+(+ A.CursorQuery,+ A.cursorQuery,+ A.ReducingDecoder,+ A.reducingDecoder,+ B.BatchSize,+ B.batchSize_10,+ B.batchSize_100,+ B.batchSize_1000,+ B.batchSize_10000,+)+where++import qualified Hasql.CursorQuery.Private.CursorQuery as A+import qualified Hasql.CursorTransaction as B+
+ library/Hasql/CursorQuery/CursorTransactions.hs view
@@ -0,0 +1,7 @@+module Hasql.CursorQuery.CursorTransactions+(+ cursorQuery,+)+where++import Hasql.CursorQuery.Private.CursorTransactions
+ library/Hasql/CursorQuery/Private/CursorQuery.hs view
@@ -0,0 +1,69 @@+module Hasql.CursorQuery.Private.CursorQuery+where++import Hasql.CursorQuery.Private.Prelude+import qualified Hasql.Encoders as A+import qualified Hasql.Decoders as B+import qualified Control.Foldl as D+import qualified Hasql.CursorTransaction as H+++-- |+-- A specification of a streaming query.+-- +-- Provides an abstraction over Postgres Cursor,+-- which allows to process result sets of any size in constant memory.+-- +-- Essentially it is a parametric query specification extended with a reduction strategy and a batch size,+-- where reduction strategy determines how to fold the rows into the final result,+-- and batch size determines how many rows to fetch during each roundtrip to the database.+data CursorQuery params result =+ CursorQuery !ByteString !(A.Params params) !(ReducingDecoder result) !H.BatchSize++instance Profunctor CursorQuery where+ dimap fn1 fn2 (CursorQuery template encoder decoder batchSize) =+ CursorQuery template (contramap fn1 encoder) (fmap fn2 decoder) batchSize++instance Functor (CursorQuery params) where+ fmap =+ rmap++-- |+-- Given an SQL template, a params encoder, a reducing result decoder and a batch-size,+-- constructs CursorQuery.+cursorQuery :: ByteString -> A.Params params -> ReducingDecoder result -> H.BatchSize -> CursorQuery params result+cursorQuery =+ CursorQuery+++-- |+-- A specification of how to decode and reduce multiple rows.+-- +-- Composable with the Applicative interface.+data ReducingDecoder reduction =+ forall row. ReducingDecoder !(B.Row row) !(D.Fold row reduction)++instance Functor ReducingDecoder where+ fmap fn (ReducingDecoder rowDecoder rowsFold) =+ ReducingDecoder rowDecoder (fmap fn rowsFold)++instance Applicative ReducingDecoder where+ pure reduction =+ ReducingDecoder (pure ()) (pure reduction)+ (<*>) (ReducingDecoder rowDecoder1 rowsFold1) (ReducingDecoder rowDecoder2 rowsFold2) =+ ReducingDecoder rowDecoder3 rowsFold3+ where+ rowDecoder3 =+ strictPair <$> rowDecoder1 <*> rowDecoder2+ where+ strictPair !a !b =+ (a, b)+ rowsFold3 =+ lmap fst rowsFold1 <*> lmap snd rowsFold2++-- |+-- Packs a row decoder and a fold over rows into ReducingDecoder.+reducingDecoder :: B.Row row -> D.Fold row reduction -> ReducingDecoder reduction+reducingDecoder =+ ReducingDecoder+
+ library/Hasql/CursorQuery/Private/CursorTransactions.hs view
@@ -0,0 +1,43 @@+module Hasql.CursorQuery.Private.CursorTransactions+where++import Hasql.CursorQuery.Private.Prelude+import qualified Hasql.CursorQuery.Private.CursorQuery as B+import qualified Hasql.CursorQuery.Private.Decoders as I+import qualified Hasql.Decoders as E+import qualified Hasql.Encoders as F+import qualified Hasql.CursorTransaction as G+import qualified Control.Foldl as D+++-- |+-- Fetch and fold the data from cursor until it dries out.+fetchAndFoldCursor :: G.Cursor s -> G.BatchSize -> E.Row row -> D.Fold row result -> G.CursorTransaction s result+fetchAndFoldCursor cursor batchSize rowDecoder (D.Fold progress enter exit) =+ fmap exit $+ fetchAndFoldMore enter+ where+ fetchAndFoldMore batch =+ do+ (null, fetchedBatch) <- fetchBatch+ if null+ then return batch+ else fetchAndFoldMore fetchedBatch+ where+ fetchBatch =+ fetchAndFoldCursorBatch cursor batchSize rowDecoder fold+ where+ fold =+ (,) <$> D.null <*> D.Fold progress batch id++fetchAndFoldCursorBatch :: G.Cursor s -> G.BatchSize -> E.Row row -> D.Fold row result -> G.CursorTransaction s result+fetchAndFoldCursorBatch cursor batchSize rowDecoder rowsFold =+ G.fetchBatch cursor batchSize (I.fold rowsFold rowDecoder)++-- |+-- Executes CursorQuery in CursorTransaction provided the parameters.+cursorQuery :: params -> B.CursorQuery params result -> G.CursorTransaction s result+cursorQuery params (B.CursorQuery template encoder (B.ReducingDecoder rowDecoder rowsFold) batchSize) =+ G.withCursor template (G.encodedParams encoder params) $+ \ cursor ->+ fetchAndFoldCursor cursor batchSize rowDecoder rowsFold
+ library/Hasql/CursorQuery/Private/Decoders.hs view
@@ -0,0 +1,11 @@+module Hasql.CursorQuery.Private.Decoders+where++import Hasql.CursorQuery.Private.Prelude+import qualified Hasql.Decoders as A+import qualified Control.Foldl as B+++fold :: B.Fold a b -> A.Row a -> A.Result b+fold (B.Fold progress enter exit) rowDecoder =+ fmap exit (A.foldlRows progress enter rowDecoder)
+ library/Hasql/CursorQuery/Private/Prelude.hs view
@@ -0,0 +1,23 @@+module Hasql.CursorQuery.Private.Prelude+( + module Exports,+)+where+++-- base-prelude+-------------------------+import BasePrelude as Exports hiding (assert, left, right, isLeft, isRight, error)++-- profunctors+-------------------------+import Data.Profunctor.Unsafe as Exports++-- contravariant+-------------------------+import Data.Functor.Contravariant as Exports+import Data.Functor.Contravariant.Divisible as Exports++-- bytestring+-------------------------+import Data.ByteString as Exports (ByteString)
+ library/Hasql/CursorQuery/Private/Sessions.hs view
@@ -0,0 +1,17 @@+module Hasql.CursorQuery.Private.Sessions+where++import Hasql.CursorQuery.Private.Prelude+import qualified Hasql.CursorQuery.Private.CursorQuery as B+import qualified Hasql.CursorQuery.Private.CursorTransactions as C+import qualified Hasql.CursorTransaction.Sessions as A+import qualified Hasql.Session as D+++-- |+-- Executes CursorQuery in Session provided the parameters.+-- +-- During the execution it establishes a Read transaction with the ReadCommitted isolation level.+cursorQuery :: params -> B.CursorQuery params result -> D.Session result+cursorQuery params cursorQuery =+ A.cursorTransaction (C.cursorQuery params cursorQuery)
+ library/Hasql/CursorQuery/Private/Transactions.hs view
@@ -0,0 +1,15 @@+module Hasql.CursorQuery.Private.Transactions+where++import Hasql.CursorQuery.Private.Prelude+import qualified Hasql.CursorQuery.Private.CursorQuery as B+import qualified Hasql.CursorQuery.Private.CursorTransactions as C+import qualified Hasql.Transaction as A+import qualified Hasql.CursorTransaction.Transactions as D+++-- |+-- Executes CursorQuery in Transaction provided the parameters.+cursorQuery :: params -> B.CursorQuery params result -> A.Transaction result+cursorQuery params cursorQuery =+ D.cursorTransaction (C.cursorQuery params cursorQuery)
+ library/Hasql/CursorQuery/Sessions.hs view
@@ -0,0 +1,7 @@+module Hasql.CursorQuery.Sessions+(+ cursorQuery,+)+where++import Hasql.CursorQuery.Private.Sessions
+ library/Hasql/CursorQuery/Transactions.hs view
@@ -0,0 +1,7 @@+module Hasql.CursorQuery.Transactions+(+ cursorQuery,+)+where++import Hasql.CursorQuery.Private.Transactions
+ tasty/Main.hs view
@@ -0,0 +1,29 @@+module Main where++import Rebase.Prelude+import Test.Tasty+import Test.Tasty.Runners+import Test.Tasty.HUnit+import qualified Hasql.Session as A+import qualified Hasql.CursorQuery.Sessions as C+import qualified Main.CursorQueries as D+import qualified Main.Queries as E+import qualified Main.IO as F+++main :: IO ()+main =+ defaultMain $+ localOption (NumThreads 1) $+ testGroup "All tests"+ [+ testCase "Amount" $+ do+ (count1, count2) <- F.session ((,) <$> A.query () E.countPGType <*> C.cursorQuery () D.countPGType)+ assertEqual (show (count1, count2)) count1 count2+ ,+ testCase "Equality" $+ do+ (result1, result2) <- F.session ((,) <$> A.query () E.slectOIDAndTypeName <*> C.cursorQuery () D.slectOIDAndTypeName)+ assertEqual (show (result1, result2)) result1 result2+ ]
+ tasty/Main/CursorQueries.hs view
@@ -0,0 +1,41 @@+module Main.CursorQueries where++import Rebase.Prelude+import Hasql.CursorQuery+import qualified Hasql.Encoders as A+import qualified Hasql.Decoders as B+import qualified Control.Foldl as C+++countPGType :: CursorQuery () Int+countPGType =+ cursorQuery sql encoder decoder batchSize_10+ where+ sql =+ "select oid, typname from pg_type"+ encoder =+ A.unit+ decoder =+ reducingDecoder rowDecoder fold+ where+ rowDecoder =+ (,) <$> B.value B.int8 <*> B.value B.text+ fold =+ C.length++slectOIDAndTypeName :: CursorQuery () [(Int64, Text)]+slectOIDAndTypeName =+ cursorQuery sql encoder decoder batchSize_10+ where+ sql =+ "select oid, typname from pg_type"+ encoder =+ A.unit+ decoder =+ reducingDecoder rowDecoder fold+ where+ rowDecoder =+ (,) <$> B.value B.int8 <*> B.value B.text+ fold =+ C.list+
+ tasty/Main/IO.hs view
@@ -0,0 +1,31 @@+module Main.IO where++import Rebase.Prelude+import qualified Hasql.Session as A+import qualified Hasql.Connection as B+++session :: A.Session a -> IO a+session session =+ withConnection (A.run session) >>=+ either (fail . show) (either (fail . show) return)+ where+ withConnection :: (B.Connection -> IO a) -> IO (Either B.ConnectionError a)+ withConnection handler =+ runExceptT $ acquire >>= \connection -> use connection <* release connection+ where+ acquire =+ ExceptT $ B.acquire settings+ where+ settings =+ B.settings host port user password database+ where+ host = "localhost"+ port = 5432+ user = "postgres"+ password = ""+ database = "postgres"+ use connection =+ lift $ handler connection+ release connection =+ lift $ B.release connection
+ tasty/Main/Queries.hs view
@@ -0,0 +1,32 @@+module Main.Queries where++import Rebase.Prelude+import Hasql.Query+import qualified Hasql.Encoders as A+import qualified Hasql.Decoders as B+++countPGType :: Query () Int+countPGType =+ statement sql encoder decoder True+ where+ sql =+ "select count(*) from pg_type"+ encoder =+ A.unit+ decoder =+ B.singleRow (B.value (fmap fromIntegral B.int8))+ +slectOIDAndTypeName :: Query () [(Int64, Text)]+slectOIDAndTypeName =+ statement sql encoder decoder True+ where+ sql =+ "select oid, typname from pg_type"+ encoder =+ A.unit+ decoder =+ B.rowsList rowDecoder+ where+ rowDecoder =+ (,) <$> B.value B.int8 <*> B.value B.text