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-transaction.cabal b/hasql-cursor-transaction.cabal
new file mode 100644
--- /dev/null
+++ b/hasql-cursor-transaction.cabal
@@ -0,0 +1,66 @@
+name:
+  hasql-cursor-transaction
+version:
+  0.5
+category:
+  Hasql, Database, PostgreSQL, Streaming
+synopsis:
+  An abstraction for simultaneous fetching from multiple PostgreSQL cursors
+homepage:
+  https://github.com/nikita-volkov/hasql-cursor-transaction 
+bug-reports:
+  https://github.com/nikita-volkov/hasql-cursor-transaction/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-transaction.git
+
+
+library
+  hs-source-dirs:
+    library
+  ghc-options:
+  default-extensions:
+    Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFunctor, DeriveGeneric, 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.CursorTransaction.Private.Prelude
+    Hasql.CursorTransaction.Private.Queries
+    Hasql.CursorTransaction.Private.Specs
+    Hasql.CursorTransaction.Private.Transactions
+    Hasql.CursorTransaction.Private.CursorTransaction
+  exposed-modules:
+    Hasql.CursorTransaction.Transactions
+    Hasql.CursorTransaction.Sessions
+    Hasql.CursorTransaction
+  build-depends:
+    -- database:
+    hasql >= 0.19 && < 0.20,
+    hasql-transaction >= 0.4.5.1 && < 0.5,
+    -- data:
+    bytestring-tree-builder == 0.2.*,
+    bytestring >= 0.10 && < 0.11,
+    -- control:
+    contravariant >= 1.3 && < 2,
+    transformers >= 0.3 && < 0.6,
+    -- general:
+    base-prelude >= 0.1.19 && < 2,
+    base >= 4.6 && < 5
diff --git a/library/Hasql/CursorTransaction.hs b/library/Hasql/CursorTransaction.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction.hs
@@ -0,0 +1,24 @@
+module Hasql.CursorTransaction
+(
+  -- * Types
+  A.CursorTransaction,
+  A.Cursor,
+  B.BatchSize,
+  B.EncodedParams,
+  -- * Cursor Transactions
+  A.withCursor,
+  A.fetchBatch,
+  A.transaction,
+  -- * Batch Sizes
+  B.batchSize_10,
+  B.batchSize_100,
+  B.batchSize_1000,
+  B.batchSize_10000,
+  -- * Encoded Params
+  B.encodedParams,
+)
+where
+
+import qualified Hasql.CursorTransaction.Private.CursorTransaction as A
+import qualified Hasql.CursorTransaction.Private.Specs as B
+
diff --git a/library/Hasql/CursorTransaction/Private/CursorTransaction.hs b/library/Hasql/CursorTransaction/Private/CursorTransaction.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Private/CursorTransaction.hs
@@ -0,0 +1,67 @@
+module Hasql.CursorTransaction.Private.CursorTransaction
+where
+
+import Hasql.CursorTransaction.Private.Prelude
+import qualified Hasql.Transaction as A
+import qualified Hasql.Encoders as D
+import qualified Hasql.Decoders as F
+import qualified Hasql.CursorTransaction.Private.Transactions as C
+import qualified Hasql.CursorTransaction.Private.Specs as G
+import qualified ByteString.TreeBuilder as E
+
+
+-- |
+-- Context for fetching from multiple cursors in an intertwined fashion.
+newtype CursorTransaction s result =
+  CursorTransaction (StateT Int A.Transaction result)
+  deriving (Functor, Applicative, Monad)
+
+-- |
+-- Cursor reference.
+newtype Cursor s =
+  Cursor ByteString
+
+declareCursor :: ByteString -> D.Params params -> params -> CursorTransaction s (Cursor s)
+declareCursor template encoder params =
+  CursorTransaction $
+  do
+    name <- fmap name (state ((,) <$> id <*> succ))
+    lift (C.declareCursor name template encoder params)
+    return (Cursor name)
+  where
+    name inc =
+      E.toByteString $
+      E.byteString "Hasql_CursorTransaction_" <> E.asciiIntegral inc
+
+closeCursor :: Cursor s -> CursorTransaction s ()
+closeCursor (Cursor name) =
+  transaction (C.closeCursor name)
+
+-- |
+-- Given a template, encoded params and a Cursor-handling continuation,
+-- executes it,
+-- while automatically declaring and closing the cursor behind the scenes.
+withCursor :: ByteString -> G.EncodedParams -> (forall s. Cursor s -> CursorTransaction s result) -> CursorTransaction s result
+withCursor template (G.EncodedParams (Supplied encoder params)) continuation =
+  do
+    cursor <- declareCursor template encoder params
+    result <- continuation cursor
+    closeCursor cursor
+    return result
+
+-- |
+-- Fetch from a cursor a batch of the given size and decode it using the specified result decoder.
+fetchBatch :: Cursor s -> G.BatchSize -> F.Result result -> CursorTransaction s result
+fetchBatch (Cursor name) batchSize decoder =
+  transaction (C.fetchFromCursor name batchSize decoder)
+
+-- |
+-- Lift a standard transaction.
+-- Note that the transaction must not execute other CursorTransactions.
+transaction :: A.Transaction result -> CursorTransaction s result
+transaction =
+  CursorTransaction . lift
+
+run :: (forall s. CursorTransaction s result) -> A.Transaction result
+run (CursorTransaction stack) =
+  evalStateT stack 1
diff --git a/library/Hasql/CursorTransaction/Private/Prelude.hs b/library/Hasql/CursorTransaction/Private/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Private/Prelude.hs
@@ -0,0 +1,53 @@
+module Hasql.CursorTransaction.Private.Prelude
+( 
+  module Exports,
+  Supplied(..),
+)
+where
+
+
+-- base-prelude
+-------------------------
+import BasePrelude as Exports hiding (assert, left, right, isLeft, isRight, error)
+
+-- transformers
+-------------------------
+import Control.Monad.IO.Class as Exports
+import Control.Monad.Trans.Class as Exports
+import Control.Monad.Trans.Cont as Exports hiding (shift)
+import Control.Monad.Trans.Except as Exports hiding (liftCallCC, liftListen, liftPass)
+import Control.Monad.Trans.Maybe as Exports hiding (liftCallCC, liftCatch, liftPass)
+import Control.Monad.Trans.Reader as Exports hiding (liftCallCC)
+import Control.Monad.Trans.State.Strict as Exports hiding (liftCatch, liftListen, liftPass)
+import Control.Monad.Trans.Writer.Strict as Exports hiding (liftCallCC, liftCatch)
+import Data.Functor.Identity as Exports
+
+-- contravariant
+-------------------------
+import Data.Functor.Contravariant as Exports
+import Data.Functor.Contravariant.Divisible as Exports
+
+-- bytestring
+-------------------------
+import Data.ByteString as Exports (ByteString)
+
+-- Custom
+-------------------------
+
+-- |
+-- A combination of a divisible functor with some input for it.
+-- Allows to use the 'Monoid' API for composition.
+data Supplied divisible =
+  forall input. Supplied !(divisible input) !input
+
+instance Divisible divisible => Monoid (Supplied divisible) where
+  mempty =
+    Supplied conquer ()
+  mappend (Supplied divisible1 input1) (Supplied divisible2 input2) =
+    Supplied divisible3 input3
+    where
+      divisible3 =
+        divide id divisible1 divisible2
+      input3 =
+        (input1, input2)
+
diff --git a/library/Hasql/CursorTransaction/Private/Queries.hs b/library/Hasql/CursorTransaction/Private/Queries.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Private/Queries.hs
@@ -0,0 +1,35 @@
+module Hasql.CursorTransaction.Private.Queries
+where
+
+import Hasql.CursorTransaction.Private.Prelude
+import qualified Hasql.Query as A
+import qualified Hasql.Encoders as B
+import qualified Hasql.Decoders as C
+import qualified Hasql.CursorTransaction.Private.Specs as F
+import qualified ByteString.TreeBuilder as D
+
+
+declareCursor :: ByteString -> ByteString -> B.Params a -> A.Query a ()
+declareCursor name sql encoder =
+  A.statement sql' encoder C.unit False
+  where
+    sql' =
+      D.toByteString $
+      "DECLARE " <> D.byteString name <> " NO SCROLL CURSOR FOR " <> D.byteString sql
+
+closeCursor :: ByteString -> A.Query () ()
+closeCursor name =
+  A.statement sql B.unit C.unit True
+  where
+    sql =
+      "CLOSE " <> name
+
+fetchFromCursor :: ByteString -> F.BatchSize -> C.Result result -> A.Query () result
+fetchFromCursor name (F.BatchSize batchSize) decoder =
+  A.statement sql encoder decoder True
+  where
+    sql =
+      D.toByteString $
+      "FETCH FORWARD " <> D.asciiIntegral batchSize <> " FROM " <> D.byteString name
+    encoder =
+      B.unit
diff --git a/library/Hasql/CursorTransaction/Private/Specs.hs b/library/Hasql/CursorTransaction/Private/Specs.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Private/Specs.hs
@@ -0,0 +1,49 @@
+module Hasql.CursorTransaction.Private.Specs
+where
+
+import Hasql.CursorTransaction.Private.Prelude
+import qualified Hasql.Encoders as A
+import qualified Hasql.Decoders as B
+
+
+-- |
+-- Spefifies how many rows to fetch in a single DB roundtrip.
+newtype BatchSize =
+  BatchSize Int64
+
+-- |
+-- Batch size of 10.
+batchSize_10 :: BatchSize
+batchSize_10 =
+  BatchSize 10
+
+-- |
+-- Batch size of 100.
+batchSize_100 :: BatchSize
+batchSize_100 =
+  BatchSize 100
+
+-- |
+-- Batch size of 1000.
+batchSize_1000 :: BatchSize
+batchSize_1000 =
+  BatchSize 1000
+
+-- |
+-- Batch size of 10000.
+batchSize_10000 :: BatchSize
+batchSize_10000 =
+  BatchSize 10000
+
+
+-- |
+-- A parameters encoder immediately supplied with parameters.
+newtype EncodedParams =
+  EncodedParams (Supplied A.Params)
+  deriving (Monoid)
+
+-- |
+-- Pack the params encoder and params into EncodedParams.
+encodedParams :: A.Params params -> params -> EncodedParams
+encodedParams encoder params =
+  EncodedParams (Supplied encoder params)
diff --git a/library/Hasql/CursorTransaction/Private/Transactions.hs b/library/Hasql/CursorTransaction/Private/Transactions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Private/Transactions.hs
@@ -0,0 +1,22 @@
+module Hasql.CursorTransaction.Private.Transactions
+where
+
+import Hasql.CursorTransaction.Private.Prelude
+import qualified Hasql.CursorTransaction.Private.Queries as A
+import qualified Hasql.CursorTransaction.Private.Specs as B
+import qualified Hasql.Transaction as C
+import qualified Hasql.Decoders as E
+import qualified Hasql.Encoders as F
+
+
+declareCursor :: ByteString -> ByteString -> F.Params params -> params -> C.Transaction ()
+declareCursor cursorName template paramsEncoder params =
+  C.query params (A.declareCursor cursorName template paramsEncoder)
+
+closeCursor :: ByteString -> C.Transaction ()
+closeCursor cursorName =
+  C.query () (A.closeCursor cursorName)
+
+fetchFromCursor :: ByteString -> B.BatchSize -> E.Result result -> C.Transaction result
+fetchFromCursor cursorName batchSize decoder =
+  C.query () (A.fetchFromCursor cursorName batchSize decoder)
diff --git a/library/Hasql/CursorTransaction/Sessions.hs b/library/Hasql/CursorTransaction/Sessions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Sessions.hs
@@ -0,0 +1,18 @@
+module Hasql.CursorTransaction.Sessions
+(
+  cursorTransaction,
+)
+where
+
+import Hasql.CursorTransaction.Private.Prelude
+import qualified Hasql.CursorTransaction.Private.CursorTransaction as A
+import qualified Hasql.Transaction as B
+import qualified Hasql.Session as C
+
+-- |
+-- Executes CursorTransaction in Session.
+-- 
+-- During the execution it establishes a Read transaction with the ReadCommitted isolation level.
+cursorTransaction :: (forall s. A.CursorTransaction s result) -> C.Session result
+cursorTransaction cursorTransaction =
+  B.run (A.run cursorTransaction) B.ReadCommitted B.Read
diff --git a/library/Hasql/CursorTransaction/Transactions.hs b/library/Hasql/CursorTransaction/Transactions.hs
new file mode 100644
--- /dev/null
+++ b/library/Hasql/CursorTransaction/Transactions.hs
@@ -0,0 +1,13 @@
+module Hasql.CursorTransaction.Transactions
+(
+  cursorTransaction,
+)
+where
+
+import qualified Hasql.CursorTransaction.Private.Transactions as A
+import qualified Hasql.CursorTransaction.Private.CursorTransaction as B
+
+-- |
+-- Executes CursorTransaction in Transaction.
+cursorTransaction =
+  B.run
