postgresql-lo-stream 0.1.0.0 → 0.1.1.0
raw patch · 3 files changed
+118/−118 lines, 3 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Database.PostgreSQL.LargeObjects.Stream: newLargeObjectBS :: Connection -> ByteString -> IO Oid
- Database.PostgreSQL.LargeObjects.Stream: newLargeObjectLBS :: Connection -> ByteString -> IO (Oid, Int)
- Database.PostgreSQL.LargeObjects.Stream: newLargeObjectStream :: Connection -> InputStream ByteString -> IO (Oid, Int)
- Database.PostgreSQL.LargeObjects.Stream: streamLargeObject :: Connection -> Oid -> OutputStream Builder -> IO ()
- Database.PostgreSQL.LargeObjects.Stream: streamLargeObjectRange :: Connection -> Oid -> Int -> Int -> OutputStream Builder -> IO ()
- Database.PostgreSQL.LargeObjects.Stream: withLargeObject :: Connection -> Oid -> IOMode -> (LoFd -> IO a) -> IO a
- Database.PostgreSQL.LargeObjects.Stream: withLargeObjectLBS :: Connection -> Oid -> (ByteString -> IO ()) -> IO ()
+ Database.PostgreSQL.Simple.LargeObjects.Stream: newLargeObjectBS :: Connection -> ByteString -> IO Oid
+ Database.PostgreSQL.Simple.LargeObjects.Stream: newLargeObjectLBS :: Connection -> ByteString -> IO (Oid, Int)
+ Database.PostgreSQL.Simple.LargeObjects.Stream: newLargeObjectStream :: Connection -> InputStream ByteString -> IO (Oid, Int)
+ Database.PostgreSQL.Simple.LargeObjects.Stream: streamLargeObject :: Connection -> Oid -> OutputStream Builder -> IO ()
+ Database.PostgreSQL.Simple.LargeObjects.Stream: streamLargeObjectRange :: Connection -> Oid -> Int -> Int -> OutputStream Builder -> IO ()
+ Database.PostgreSQL.Simple.LargeObjects.Stream: withLargeObject :: Connection -> Oid -> IOMode -> (LoFd -> IO a) -> IO a
+ Database.PostgreSQL.Simple.LargeObjects.Stream: withLargeObjectLBS :: Connection -> Oid -> (ByteString -> IO ()) -> IO ()
Files
- postgresql-lo-stream.cabal +2/−2
- src/Database/PostgreSQL/LargeObjects/Stream.hs +0/−116
- src/Database/PostgreSQL/Simple/LargeObjects/Stream.hs +116/−0
postgresql-lo-stream.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: postgresql-lo-stream-version: 0.1.0.0+version: 0.1.1.0 synopsis: Utilities for streaming PostgreSQL LargeObjects description: Functions for streaming large objects to and from PostgreSQL homepage: https://github.com/obsidiansystems/posgresql-lo-stream@@ -15,7 +15,7 @@ extra-source-files: README.md library- exposed-modules: Database.PostgreSQL.LargeObjects.Stream+ exposed-modules: Database.PostgreSQL.Simple.LargeObjects.Stream other-extensions: LambdaCase build-depends: base >=4.11 && <4.12 , bytestring >=0.10 && <0.11
− src/Database/PostgreSQL/LargeObjects/Stream.hs
@@ -1,116 +0,0 @@-{-# LANGUAGE LambdaCase #-}-module Database.PostgreSQL.LargeObjects.Stream where--import Control.Exception.Lifted (AssertionFailed (..), bracket, throwIO)-import Control.Monad.Loops (whileJust_)-import Control.Monad.State as State-import qualified Data.ByteString as BS-import Data.ByteString.Builder (byteString)-import qualified Data.ByteString.Builder as BS-import qualified Data.ByteString.Lazy as LBS-import Data.IORef (modifyIORef, newIORef, readIORef)-import Data.Semigroup ((<>))-import Database.PostgreSQL.Simple-import Database.PostgreSQL.Simple.LargeObjects (LoFd, Oid (..))-import qualified Database.PostgreSQL.Simple.LargeObjects as Sql-import System.IO (IOMode (ReadMode, WriteMode))-import System.IO.Streams (makeOutputStream)-import qualified System.IO.Streams as Streams---- | Given a strict ByteString, create a postgres large object and fill it with those contents.-newLargeObjectBS- :: Connection- -> BS.ByteString- -> IO Oid-newLargeObjectBS conn contents = do- oid <- Sql.loCreat conn- n <- withLargeObject conn oid WriteMode $ \lofd -> Sql.loWrite conn lofd contents- let l = BS.length contents- when (n /= l) . throwIO . AssertionFailed $- "newLargeObjectBS: loWrite reported writing " <> show n <> " bytes, expected " <> show l <> "."- return oid---- | Given a lazy ByteString, create a postgres large object and fill it with those contents.--- Also returns the total length of the data written.-newLargeObjectLBS- :: Connection- -> LBS.ByteString- -> IO (Oid, Int)-newLargeObjectLBS conn = newLargeObjectStream conn <=< Streams.fromLazyByteString---- | Create a new large object from an input stream, returning its object id and overall size.-newLargeObjectStream- :: Connection- -> Streams.InputStream BS.ByteString- -> IO (Oid, Int)-newLargeObjectStream conn s = do- oid <- Sql.loCreat conn- t <- withLargeObject conn oid WriteMode $ \lofd -> do- whileJust_ (Streams.read s) $ \chunk -> do- n <- Sql.loWrite conn lofd chunk- let l = BS.length chunk- when (n /= l) . throwIO . AssertionFailed $- "newLargeObjectStream: loWrite reported writing " <> show n <> " bytes, expected " <> show l <> "."- Sql.loTell conn lofd- return (oid, t)---- | Act on a large object given by id, opening and closing the file descriptor appropriately.-withLargeObject- :: Connection- -> Oid- -> IOMode- -> (LoFd -> IO a)- -> IO a-withLargeObject conn oid mode f =- bracket (Sql.loOpen conn oid mode)- (\lofd -> Sql.loClose conn lofd)- f---- | Stream the contents of a database large object to the given output stream. Useful with Snap's 'addToOutput'.-streamLargeObject- :: Connection- -> Oid- -> Streams.OutputStream BS.Builder- -> IO ()-streamLargeObject conn oid os =- withLargeObject conn oid ReadMode $ \lofd ->- fix $ \again -> do- chunk <- Sql.loRead conn lofd 8192 -- somewhat arbitrary- case BS.length chunk of- 0 -> return ()- _ -> do- Streams.write (Just $ byteString chunk) os- again---- | Stream the contents of a database large object to the given output stream. Useful with Snap's 'addToOutput'.-streamLargeObjectRange- :: Connection- -> Oid- -> Int- -> Int- -> Streams.OutputStream BS.Builder- -> IO ()-streamLargeObjectRange conn oid start end os =- withLargeObject conn oid ReadMode $ \lofd -> do- _ <- Sql.loSeek conn lofd Sql.AbsoluteSeek start- let again n = do- let nextChunkSize = min 8192 (end - n)- chunk <- Sql.loRead conn lofd nextChunkSize- case BS.length chunk of- 0 -> return ()- k -> do- Streams.write (Just $ byteString chunk) os- again (n + k)- again start---- | Act on the contents of a LargeObject as a Lazy ByteString-withLargeObjectLBS :: Connection -> Oid -> (LBS.ByteString -> IO ()) -> IO ()-withLargeObjectLBS conn oid f = do- lo <- newIORef mempty- cb <- makeOutputStream $ \case- Just chunk -> modifyIORef lo $ \chunks -> chunks <> chunk- Nothing -> do- payload <- readIORef lo- f $ BS.toLazyByteString payload- streamLargeObject conn oid cb- Streams.write Nothing cb
+ src/Database/PostgreSQL/Simple/LargeObjects/Stream.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE LambdaCase #-}+module Database.PostgreSQL.Simple.LargeObjects.Stream where++import Control.Exception.Lifted (AssertionFailed (..), bracket, throwIO)+import Control.Monad.Loops (whileJust_)+import Control.Monad.State as State+import qualified Data.ByteString as BS+import Data.ByteString.Builder (byteString)+import qualified Data.ByteString.Builder as BS+import qualified Data.ByteString.Lazy as LBS+import Data.IORef (modifyIORef, newIORef, readIORef)+import Data.Semigroup ((<>))+import Database.PostgreSQL.Simple+import Database.PostgreSQL.Simple.LargeObjects (LoFd, Oid (..))+import qualified Database.PostgreSQL.Simple.LargeObjects as Sql+import System.IO (IOMode (ReadMode, WriteMode))+import System.IO.Streams (makeOutputStream)+import qualified System.IO.Streams as Streams++-- | Given a strict ByteString, create a postgres large object and fill it with those contents.+newLargeObjectBS+ :: Connection+ -> BS.ByteString+ -> IO Oid+newLargeObjectBS conn contents = do+ oid <- Sql.loCreat conn+ n <- withLargeObject conn oid WriteMode $ \lofd -> Sql.loWrite conn lofd contents+ let l = BS.length contents+ when (n /= l) . throwIO . AssertionFailed $+ "newLargeObjectBS: loWrite reported writing " <> show n <> " bytes, expected " <> show l <> "."+ return oid++-- | Given a lazy ByteString, create a postgres large object and fill it with those contents.+-- Also returns the total length of the data written.+newLargeObjectLBS+ :: Connection+ -> LBS.ByteString+ -> IO (Oid, Int)+newLargeObjectLBS conn = newLargeObjectStream conn <=< Streams.fromLazyByteString++-- | Create a new large object from an input stream, returning its object id and overall size.+newLargeObjectStream+ :: Connection+ -> Streams.InputStream BS.ByteString+ -> IO (Oid, Int)+newLargeObjectStream conn s = do+ oid <- Sql.loCreat conn+ t <- withLargeObject conn oid WriteMode $ \lofd -> do+ whileJust_ (Streams.read s) $ \chunk -> do+ n <- Sql.loWrite conn lofd chunk+ let l = BS.length chunk+ when (n /= l) . throwIO . AssertionFailed $+ "newLargeObjectStream: loWrite reported writing " <> show n <> " bytes, expected " <> show l <> "."+ Sql.loTell conn lofd+ return (oid, t)++-- | Act on a large object given by id, opening and closing the file descriptor appropriately.+withLargeObject+ :: Connection+ -> Oid+ -> IOMode+ -> (LoFd -> IO a)+ -> IO a+withLargeObject conn oid mode f =+ bracket (Sql.loOpen conn oid mode)+ (\lofd -> Sql.loClose conn lofd)+ f++-- | Stream the contents of a database large object to the given output stream. Useful with Snap's 'addToOutput'.+streamLargeObject+ :: Connection+ -> Oid+ -> Streams.OutputStream BS.Builder+ -> IO ()+streamLargeObject conn oid os =+ withLargeObject conn oid ReadMode $ \lofd ->+ fix $ \again -> do+ chunk <- Sql.loRead conn lofd 8192 -- somewhat arbitrary+ case BS.length chunk of+ 0 -> return ()+ _ -> do+ Streams.write (Just $ byteString chunk) os+ again++-- | Stream the contents of a database large object to the given output stream. Useful with Snap's 'addToOutput'.+streamLargeObjectRange+ :: Connection+ -> Oid+ -> Int+ -> Int+ -> Streams.OutputStream BS.Builder+ -> IO ()+streamLargeObjectRange conn oid start end os =+ withLargeObject conn oid ReadMode $ \lofd -> do+ _ <- Sql.loSeek conn lofd Sql.AbsoluteSeek start+ let again n = do+ let nextChunkSize = min 8192 (end - n)+ chunk <- Sql.loRead conn lofd nextChunkSize+ case BS.length chunk of+ 0 -> return ()+ k -> do+ Streams.write (Just $ byteString chunk) os+ again (n + k)+ again start++-- | Act on the contents of a LargeObject as a Lazy ByteString+withLargeObjectLBS :: Connection -> Oid -> (LBS.ByteString -> IO ()) -> IO ()+withLargeObjectLBS conn oid f = do+ lo <- newIORef mempty+ cb <- makeOutputStream $ \case+ Just chunk -> modifyIORef lo $ \chunks -> chunks <> chunk+ Nothing -> do+ payload <- readIORef lo+ f $ BS.toLazyByteString payload+ streamLargeObject conn oid cb+ Streams.write Nothing cb