packages feed

esqueleto-streaming (empty) → 0.1.0.0

raw patch · 6 files changed

+139/−0 lines, 6 filesdep +basedep +conduitdep +esqueletosetup-changed

Dependencies added: base, conduit, esqueleto, persistent-postgresql, persistent-postgresql-streaming, resourcet, transformers

Files

+ CHANGELOG.md view
@@ -0,0 +1,6 @@+# Changelog for esqueleto-streaming++# 0.1.0.0++  * Exposed `Database.Esqueleto.PostgreSQL.Streaming`+    * Added `selectCursor`
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Supercede Ltd. (c) 2021++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Isaac van Bakel nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,17 @@+# esqueleto-streaming++This library allows for memory-constant streaming of the results of [`esqueleto`](https://hackage.haskell.org/package/esqueleto) queries from PostgreSQL databases.++This code makes use of the PostgreSQL-only [cursors](https://www.postgresql.org/docs/current/plpgsql-cursors.html), which allow for batched access to the result set of a query at speeds comparable to loading all the results into memory at once.++See the [main project README](https://github.com/SupercedeTech/persistent-postgresql-streaming/blob/main/README.md) for more.++## Streaming results from Esqueleto queries++The main function of this library is `selectCursor`, which can be used in place of [`select`](https://hackage.haskell.org/package/esqueleto-3.5.3.0/docs/Database-Esqueleto.html#v:select) to run an Esqueleto query. `selectCursor` runs in a `ConduitT` - consuming the conduit will pull results from the database in constant memory.++## FAQ++### Why is `selectCursor` so slow?++Have you configured PostgreSQL correctly? See the section in the [README](https://github.com/SupercedeTech/persistent-postgresql-streaming/blob/main/README.md) about it.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ esqueleto-streaming.cabal view
@@ -0,0 +1,36 @@+name:                esqueleto-streaming+version:             0.1.0.0+synopsis:            Memory-constant streaming of Esqueleto results from PostgreSQL+description:+  This library provides a set of APIs for performing queries in Esqueleto+  in constant memory, streaming the results using @conduit@.+  .+  The library relies on PostgreSQL-specific features to avoid loading all the+  results of a query into memory at once. This allows for accessing results of+  millions of rows from Haskell without a memory blow-up.+homepage:            https://github.com/SupercedeTech/persistent-postgresql-streaming#readme+license:             BSD3+license-file:        LICENSE+author:              Isaac van Bakel+maintainer:          support@supercede.com+copyright:           (c) 2021 Supercede Ltd.+category:            Conduit, Database+build-type:          Simple+extra-source-files:  CHANGELOG.md README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     Database.Esqueleto.PostgreSQL.Streaming+  build-depends:       base >= 4.7 && < 5+                     , conduit >= 1 && < 1.4+                     , esqueleto >= 3.5 && < 3.6+                     , persistent-postgresql-streaming >= 0.1 && < 0.2+                     , persistent-postgresql >= 2.13.2 && < 2.14+                     , resourcet >= 0.3 && < 2+                     , transformers >= 0.5 && < 0.6+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/SupercedeTech/persistent-postgresql-streaming
+ src/Database/Esqueleto/PostgreSQL/Streaming.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Database.Esqueleto.PostgreSQL.Streaming+  ( selectCursor+  ) where++import Control.Monad.IO.Class (MonadIO)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.Reader (ReaderT(..), ask)+import Control.Monad.Trans.Resource (MonadResource)+import Data.Conduit (ConduitT)+import Data.Conduit.Lift (runReaderC)+import Database.Esqueleto.Internal.Internal+import Database.Persist.Postgresql+import Database.Persist.Postgresql.Streaming.Internal (rawSelectStream)++-- | Execute an @esqueleto@ @SELECT@ query against a PostgreSQL backend and+-- return a stream of the results in constant memory, using the PostgreSQL+-- cursor feature.+--+-- NB: this function is likely to perform worse than 'select' on small+-- result sets.+--+-- NB: for large result sets, this function is likely to perform very poorly+-- unless you manually configure the @cursor_tuple_fraction@ setting to be+-- close to @1@. This setting decides how much PostgreSQL will prioritise+-- returning the first rows quickly vs. returning all rows efficiently. See+--+-- https://postgresqlco.nf/doc/en/param/cursor_tuple_fraction/+--+-- for more.+selectCursor+  ::+    ( SqlSelect a r+    , MonadIO m+    , MonadResource m+    , BackendCompatible (RawPostgresql SqlBackend) backend+    )+  => SqlQuery a+  -> ConduitT () r (ReaderT backend m) ()+selectCursor query = do+  backend@(RawPostgresql conn _) <- lift $ projectBackend <$> ask+  let (queryTextBuilder, vals) = toRawSql SELECT (conn, initialIdentState) query+      queryText = builderToText queryTextBuilder+  runReaderC backend+    (rawSelectStream sqlSelectProcessRow queryText vals)+