diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/hasql-cursor-query.cabal b/hasql-cursor-query.cabal
new file mode 100644
--- /dev/null
+++ b/hasql-cursor-query.cabal
@@ -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
diff --git a/library/Hasql/CursorQuery.hs b/library/Hasql/CursorQuery.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery.hs
@@ -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
+
diff --git a/library/Hasql/CursorQuery/CursorTransactions.hs b/library/Hasql/CursorQuery/CursorTransactions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/CursorTransactions.hs
@@ -0,0 +1,7 @@
+module Hasql.CursorQuery.CursorTransactions
+(
+  cursorQuery,
+)
+where
+
+import Hasql.CursorQuery.Private.CursorTransactions
diff --git a/library/Hasql/CursorQuery/Private/CursorQuery.hs b/library/Hasql/CursorQuery/Private/CursorQuery.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Private/CursorQuery.hs
@@ -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
+
diff --git a/library/Hasql/CursorQuery/Private/CursorTransactions.hs b/library/Hasql/CursorQuery/Private/CursorTransactions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Private/CursorTransactions.hs
@@ -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
diff --git a/library/Hasql/CursorQuery/Private/Decoders.hs b/library/Hasql/CursorQuery/Private/Decoders.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Private/Decoders.hs
@@ -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)
diff --git a/library/Hasql/CursorQuery/Private/Prelude.hs b/library/Hasql/CursorQuery/Private/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Private/Prelude.hs
@@ -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)
diff --git a/library/Hasql/CursorQuery/Private/Sessions.hs b/library/Hasql/CursorQuery/Private/Sessions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Private/Sessions.hs
@@ -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)
diff --git a/library/Hasql/CursorQuery/Private/Transactions.hs b/library/Hasql/CursorQuery/Private/Transactions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Private/Transactions.hs
@@ -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)
diff --git a/library/Hasql/CursorQuery/Sessions.hs b/library/Hasql/CursorQuery/Sessions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Sessions.hs
@@ -0,0 +1,7 @@
+module Hasql.CursorQuery.Sessions
+(
+  cursorQuery,
+)
+where
+
+import Hasql.CursorQuery.Private.Sessions
diff --git a/library/Hasql/CursorQuery/Transactions.hs b/library/Hasql/CursorQuery/Transactions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorQuery/Transactions.hs
@@ -0,0 +1,7 @@
+module Hasql.CursorQuery.Transactions
+(
+  cursorQuery,
+)
+where
+
+import Hasql.CursorQuery.Private.Transactions
diff --git a/tasty/Main.hs b/tasty/Main.hs
new file mode 100644
--- /dev/null
+++ b/tasty/Main.hs
@@ -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
+  ]
diff --git a/tasty/Main/CursorQueries.hs b/tasty/Main/CursorQueries.hs
new file mode 100644
--- /dev/null
+++ b/tasty/Main/CursorQueries.hs
@@ -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
+
diff --git a/tasty/Main/IO.hs b/tasty/Main/IO.hs
new file mode 100644
--- /dev/null
+++ b/tasty/Main/IO.hs
@@ -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
diff --git a/tasty/Main/Queries.hs b/tasty/Main/Queries.hs
new file mode 100644
--- /dev/null
+++ b/tasty/Main/Queries.hs
@@ -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
