packages feed

mongoDB 2.5.0.0 → 2.6.0.0

raw patch · 9 files changed

+189/−52 lines, 9 filesdep +dnsdep +faildep +http-types

Dependencies added: dns, fail, http-types

Files

CHANGELOG.md view
@@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. This project adheres to [Package Versioning Policy](https://wiki.haskell.org/Package_versioning_policy). +## [2.6.0.0] - 2020-01-03++## Added+- MonadFail. It's a standard for newer versions of Haskell,+- Open replica sets over tls.++## Fixed+- Support for unix domain socket connection,+- Stubborn listener threads.+ ## [2.5.0.0] - 2019-06-14  ### Fixed
Database/MongoDB/Admin.hs view
@@ -33,6 +33,7 @@ #endif import Control.Concurrent (forkIO, threadDelay) import Control.Monad (forever, unless, liftM)+import Control.Monad.Fail(MonadFail) import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Data.Maybe (maybeToList) import Data.Set (Set)@@ -76,7 +77,7 @@     db <- thisDatabase     useDb admin $ runCommand ["renameCollection" =: db <.> from, "to" =: db <.> to, "dropTarget" =: True] -dropCollection :: (MonadIO m) => Collection -> Action m Bool+dropCollection :: (MonadIO m, MonadFail m) => Collection -> Action m Bool -- ^ Delete the given collection! Return True if collection existed (and was deleted); return False if collection did not exist (and no action). dropCollection coll = do     resetIndexCache
Database/MongoDB/Connection.hs view
@@ -17,22 +17,25 @@     Host(..), PortID(..), defaultPort, host, showHostPort, readHostPort,     readHostPortM, globalConnectTimeout, connect, connect',     -- * Replica Set-    ReplicaSetName, openReplicaSet, openReplicaSet',+    ReplicaSetName, openReplicaSet, openReplicaSet', openReplicaSetTLS, openReplicaSetTLS', +    openReplicaSetSRV, openReplicaSetSRV', openReplicaSetSRV'', openReplicaSetSRV''',      ReplicaSet, primary, secondaryOk, routedHost, closeReplicaSet, replSetName ) where  import Prelude hiding (lookup) import Data.IORef (IORef, newIORef, readIORef) import Data.List (intersect, partition, (\\), delete)+import Data.Maybe (fromJust)  #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif -import Control.Monad (forM_)+import Control.Monad (forM_, guard)+import Control.Monad.Fail(MonadFail) import System.IO.Unsafe (unsafePerformIO) import System.Timeout (timeout)-import Text.ParserCombinators.Parsec (parse, many1, letter, digit, char, eof,+import Text.ParserCombinators.Parsec (parse, many1, letter, digit, char, anyChar, eof,                                       spaces, try, (<|>)) import qualified Data.List as List @@ -47,12 +50,13 @@ import qualified Data.Bson as B import qualified Data.Text as T -import Database.MongoDB.Internal.Network (HostName, PortID(..), connectTo)+import Database.MongoDB.Internal.Network (Host(..), HostName, PortID(..), connectTo, lookupSeedList, lookupReplicaSetName) import Database.MongoDB.Internal.Protocol (Pipe, newPipe, close, isClosed) import Database.MongoDB.Internal.Util (untilSuccess, liftIOE,                                        updateAssocs, shuffle, mergesortM) import Database.MongoDB.Query (Command, Failure(ConnectionFailure), access,                               slaveOk, runCommand, retrieveServerData)+import qualified Database.MongoDB.Transport.Tls as TLS (connect)  adminCommand :: Command -> Pipe -> IO Document -- ^ Run command against admin database on server connected to pipe. Fail if connection fails.@@ -62,10 +66,6 @@     failureToIOError (ConnectionFailure e) = e     failureToIOError e = userError $ show e --- * Host--data Host = Host HostName PortID  deriving (Show, Eq, Ord)- defaultPort :: PortID -- ^ Default MongoDB port = 27017 defaultPort = PortNumber 27017@@ -76,14 +76,15 @@  showHostPort :: Host -> String -- ^ Display host as \"host:port\"--- TODO: Distinguish Service and UnixSocket port-showHostPort (Host hostname port) = hostname ++ ":" ++ portname  where-    portname = case port of-        PortNumber p -> show p+-- TODO: Distinguish Service port+showHostPort (Host hostname (PortNumber port)) = hostname ++ ":" ++ show port+#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)+showHostPort (Host _        (UnixSocket path)) = "unix:" ++ path+#endif -readHostPortM :: (Monad m) => String -> m Host+readHostPortM :: (MonadFail m) => String -> m Host -- ^ Read string \"hostname:port\" as @Host hosthame (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Fail if string does not match either syntax.--- TODO: handle Service and UnixSocket port+-- TODO: handle Service port readHostPortM = either (fail . show) return . parse parser "readHostPort" where     hostname = many1 (letter <|> digit <|> char '-' <|> char '.')     parser = do@@ -91,13 +92,19 @@         h <- hostname         try (spaces >> eof >> return (host h)) <|> do             _ <- char ':'-            port :: Int <- read <$> many1 digit-            spaces >> eof-            return $ Host h (PortNumber $ fromIntegral port)+            try (  do port :: Int <- read <$> many1 digit+                      spaces >> eof+                      return $ Host h (PortNumber $ fromIntegral port))+#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)+              <|>  do guard (h == "unix")+                      p <- many1 anyChar+                      eof+                      return $ Host "" (UnixSocket p)+#endif  readHostPort :: String -> Host -- ^ Read string \"hostname:port\" as @Host hostname (PortNumber port)@ or \"hostname\" as @host hostname@ (default port). Error if string does not match either syntax.-readHostPort = runIdentity . readHostPortM+readHostPort = fromJust . readHostPortM  type Secs = Double @@ -124,12 +131,14 @@  type ReplicaSetName = Text +data TransportSecurity = Secure | Unsecure+ -- | Maintains a connection (created on demand) to each server in the named replica set-data ReplicaSet = ReplicaSet ReplicaSetName (MVar [(Host, Maybe Pipe)]) Secs+data ReplicaSet = ReplicaSet ReplicaSetName (MVar [(Host, Maybe Pipe)]) Secs TransportSecurity  replSetName :: ReplicaSet -> Text -- ^ name of connected replica set-replSetName (ReplicaSet rsName _ _) = rsName+replSetName (ReplicaSet rsName _ _ _) = rsName  openReplicaSet :: (ReplicaSetName, [Host]) -> IO ReplicaSet -- ^ Open connections (on demand) to servers in replica set. Supplied hosts is seed list. At least one of them must be a live member of the named replica set, otherwise fail. The value of 'globalConnectTimeout' at the time of this call is the timeout used for future member connect attempts. To use your own value call 'openReplicaSet\'' instead.@@ -137,19 +146,62 @@  openReplicaSet' :: Secs -> (ReplicaSetName, [Host]) -> IO ReplicaSet -- ^ Open connections (on demand) to servers in replica set. Supplied hosts is seed list. At least one of them must be a live member of the named replica set, otherwise fail. Supplied seconds timeout is used for connect attempts to members.-openReplicaSet' timeoutSecs (rsName, seedList) = do+openReplicaSet' timeoutSecs (rs, hosts) = _openReplicaSet timeoutSecs (rs, hosts, Unsecure)++openReplicaSetTLS :: (ReplicaSetName, [Host]) -> IO ReplicaSet +-- ^ Open secure connections (on demand) to servers in the replica set. Supplied hosts is seed list. At least one of them must be a live member of the named replica set, otherwise fail. The value of 'globalConnectTimeout' at the time of this call is the timeout used for future member connect attempts. To use your own value call 'openReplicaSetTLS\'' instead.+openReplicaSetTLS  rsSeed = readIORef globalConnectTimeout >>= flip openReplicaSetTLS' rsSeed++openReplicaSetTLS' :: Secs -> (ReplicaSetName, [Host]) -> IO ReplicaSet +-- ^ Open secure connections (on demand) to servers in replica set. Supplied hosts is seed list. At least one of them must be a live member of the named replica set, otherwise fail. Supplied seconds timeout is used for connect attempts to members.+openReplicaSetTLS' timeoutSecs (rs, hosts) = _openReplicaSet timeoutSecs (rs, hosts, Secure)++_openReplicaSet :: Secs -> (ReplicaSetName, [Host], TransportSecurity) -> IO ReplicaSet+_openReplicaSet timeoutSecs (rsName, seedList, transportSecurity) = do      vMembers <- newMVar (map (, Nothing) seedList)-    let rs = ReplicaSet rsName vMembers timeoutSecs+    let rs = ReplicaSet rsName vMembers timeoutSecs transportSecurity     _ <- updateMembers rs     return rs +openReplicaSetSRV :: HostName -> IO ReplicaSet +-- ^ Open non-secure connections (on demand) to servers in a replica set. The seedlist and replica set name is fetched from the SRV and TXT DNS records for the given hostname. The value of 'globalConnectTimeout' at the time of this call is the timeout used for future member connect attempts. To use your own value call 'openReplicaSetSRV\'\'\'' instead.+openReplicaSetSRV hostname = do +    timeoutSecs <- readIORef globalConnectTimeout+    _openReplicaSetSRV timeoutSecs Unsecure hostname++openReplicaSetSRV' :: HostName -> IO ReplicaSet +-- ^ Open secure connections (on demand) to servers in a replica set. The seedlist and replica set name is fetched from the SRV and TXT DNS records for the given hostname. The value of 'globalConnectTimeout' at the time of this call is the timeout used for future member connect attempts. To use your own value call 'openReplicaSetSRV\'\'\'\'' instead.+openReplicaSetSRV' hostname = do +    timeoutSecs <- readIORef globalConnectTimeout+    _openReplicaSetSRV timeoutSecs Secure hostname++openReplicaSetSRV'' :: Secs -> HostName -> IO ReplicaSet +-- ^ Open non-secure connections (on demand) to servers in a replica set. The seedlist and replica set name is fetched from the SRV and TXT DNS records for the given hostname. Supplied seconds timeout is used for connect attempts to members.+openReplicaSetSRV'' timeoutSecs = _openReplicaSetSRV timeoutSecs Unsecure++openReplicaSetSRV''' :: Secs -> HostName -> IO ReplicaSet +-- ^ Open secure connections (on demand) to servers in a replica set. The seedlist and replica set name is fetched from the SRV and TXT DNS records for the given hostname. Supplied seconds timeout is used for connect attempts to members.+openReplicaSetSRV''' timeoutSecs = _openReplicaSetSRV timeoutSecs Secure++_openReplicaSetSRV :: Secs -> TransportSecurity -> HostName -> IO ReplicaSet +_openReplicaSetSRV timeoutSecs transportSecurity hostname = do +    replicaSetName <- lookupReplicaSetName hostname +    hosts <- lookupSeedList hostname +    case (replicaSetName, hosts) of +        (Nothing, _) -> throwError $ userError "Failed to lookup replica set name"+        (_, [])  -> throwError $ userError "Failed to lookup replica set seedlist"+        (Just rsName, _) -> +            case transportSecurity of +                Secure -> openReplicaSetTLS' timeoutSecs (rsName, hosts)+                Unsecure -> openReplicaSet' timeoutSecs (rsName, hosts)+ closeReplicaSet :: ReplicaSet -> IO () -- ^ Close all connections to replica set-closeReplicaSet (ReplicaSet _ vMembers _) = withMVar vMembers $ mapM_ (maybe (return ()) close . snd)+closeReplicaSet (ReplicaSet _ vMembers _ _) = withMVar vMembers $ mapM_ (maybe (return ()) close . snd)  primary :: ReplicaSet -> IO Pipe -- ^ Return connection to current primary of replica set. Fail if no primary available.-primary rs@(ReplicaSet rsName _ _) = do+primary rs@(ReplicaSet rsName _ _ _) = do     mHost <- statedPrimary <$> updateMembers rs     case mHost of         Just host' -> connection rs Nothing host'@@ -185,7 +237,7 @@  updateMembers :: ReplicaSet -> IO ReplicaInfo -- ^ Fetch replica info from any server and update members accordingly-updateMembers rs@(ReplicaSet _ vMembers _) = do+updateMembers rs@(ReplicaSet _ vMembers _ _) = do     (host', info) <- untilSuccess (fetchReplicaInfo rs) =<< readMVar vMembers     modifyMVar vMembers $ \members -> do         let ((members', old), new) = intersection (map readHostPort $ at "hosts" info) members@@ -199,7 +251,7 @@  fetchReplicaInfo :: ReplicaSet -> (Host, Maybe Pipe) -> IO ReplicaInfo -- Connect to host and fetch replica info from host creating new connection if missing or closed (previously failed). Fail if not member of named replica set.-fetchReplicaInfo rs@(ReplicaSet rsName _ _) (host', mPipe) = do+fetchReplicaInfo rs@(ReplicaSet rsName _ _ _) (host', mPipe) = do     pipe <- connection rs mPipe host'     info <- adminCommand ["isMaster" =: (1 :: Int)] pipe     case B.lookup "setName" info of@@ -209,11 +261,15 @@  connection :: ReplicaSet -> Maybe Pipe -> Host -> IO Pipe -- ^ Return new or existing connection to member of replica set. If pipe is already known for host it is given, but we still test if it is open.-connection (ReplicaSet _ vMembers timeoutSecs) mPipe host' =+connection (ReplicaSet _ vMembers timeoutSecs transportSecurity) mPipe host' =     maybe conn (\p -> isClosed p >>= \bad -> if bad then conn else return p) mPipe  where     conn =  modifyMVar vMembers $ \members -> do-        let new = connect' timeoutSecs host' >>= \pipe -> return (updateAssocs host' (Just pipe) members, pipe)+        let (Host h p) = host'+        let conn' = case transportSecurity of +                        Secure   -> TLS.connect h p +                        Unsecure -> connect' timeoutSecs host'+        let new = conn' >>= \pipe -> return (updateAssocs host' (Just pipe) members, pipe)         case List.lookup host' members of             Just (Just pipe) -> isClosed pipe >>= \bad -> if bad then new else return (members, pipe)             _ -> new
Database/MongoDB/GridFS.hs view
@@ -26,6 +26,7 @@ import Control.Applicative((<$>))  import Control.Monad(when)+import Control.Monad.Fail(MonadFail) import Control.Monad.IO.Class import Control.Monad.Trans(lift) @@ -69,7 +70,7 @@  data File = File {bucket :: Bucket, document :: Document} -getChunk :: (Monad m, MonadIO m) => File -> Int -> Action m (Maybe S.ByteString)+getChunk :: (MonadFail m, MonadIO m) => File -> Int -> Action m (Maybe S.ByteString) -- ^ Get a chunk of a file getChunk (File bucket doc) i = do   files_id <- B.look "_id" doc@@ -98,7 +99,7 @@   doc <- fetch $ select sel $ files bucket   return $ File bucket doc -deleteFile :: (MonadIO m) => File -> Action m ()+deleteFile :: (MonadIO m, MonadFail m) => File -> Action m () -- ^ Delete files in the bucket deleteFile (File bucket doc) = do   files_id <- B.look "_id" doc@@ -110,7 +111,7 @@ putChunk bucket files_id i chunk = do   insert_ (chunks bucket) ["files_id" =: files_id, "n" =: i, "data" =: Binary (L.toStrict chunk)] -sourceFile :: (Monad m, MonadIO m) => File -> Producer (Action m) S.ByteString+sourceFile :: (MonadFail m, MonadIO m) => File -> Producer (Action m) S.ByteString -- ^ A producer for the contents of a file sourceFile file = yieldChunk 0 where   yieldChunk i = do
Database/MongoDB/Internal/Network.hs view
@@ -1,7 +1,8 @@ -- | Compatibility layer for network package, including newtype 'PortID'-{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, OverloadedStrings #-} -module Database.MongoDB.Internal.Network (PortID(..), N.HostName, connectTo) where+module Database.MongoDB.Internal.Network (Host(..), PortID(..), N.HostName, connectTo, +                                          lookupReplicaSetName, lookupSeedList) where   #if !MIN_VERSION_network(2, 9, 0)@@ -18,10 +19,22 @@  #endif +import Data.ByteString.Char8 (pack, unpack)+import Data.List (dropWhileEnd, lookup)+import Data.Maybe (fromMaybe)+import Data.Text (Text)+import Network.DNS.Lookup (lookupSRV, lookupTXT)+import Network.DNS.Resolver (defaultResolvConf, makeResolvSeed, withResolver)+import Network.HTTP.Types.URI (parseQueryText) + -- | Wraps network's 'PortNumber' -- Used to ease compatibility between older and newer network versions.-newtype PortID = PortNumber N.PortNumber deriving (Enum, Eq, Integral, Num, Ord, Read, Real, Show)+data PortID = PortNumber N.PortNumber+#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)+            | UnixSocket String+#endif+            deriving (Eq, Ord, Show)   #if !MIN_VERSION_network(2, 9, 0)@@ -32,6 +45,10 @@           -> IO Handle          -- Connected Socket connectTo hostname (PortNumber port) = N.connectTo hostname (N.PortNumber port) +#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)+connectTo _ (UnixSocket path) = N.connectTo "" (N.UnixSocket path)+#endif+ #else  -- Copied implementation from network 2.8's 'connectTo', but using our 'PortID' newtype.@@ -49,4 +66,42 @@           N.connect sock (N.SockAddrInet port (hostAddress he))           N.socketToHandle sock ReadWriteMode         )++#if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32)+connectTo _ (UnixSocket path) = do+    bracketOnError+        (N.socket N.AF_UNIX N.Stream 0)+        (N.close)+        (\sock -> do+          N.connect sock (N.SockAddrUnix path)+          N.socketToHandle sock ReadWriteMode+        ) #endif++#endif++-- * Host++data Host = Host N.HostName PortID  deriving (Show, Eq, Ord)++lookupReplicaSetName :: N.HostName -> IO (Maybe Text)+-- ^ Retrieves the replica set name from the TXT DNS record for the given hostname+lookupReplicaSetName hostname = do +  rs <- makeResolvSeed defaultResolvConf+  res <- withResolver rs $ \resolver -> lookupTXT resolver (pack hostname)+  case res of +    Left _ -> pure Nothing +    Right [] -> pure Nothing +    Right (x:_) ->+      pure $ fromMaybe (Nothing :: Maybe Text) (lookup "replicaSet" $ parseQueryText x)++lookupSeedList :: N.HostName -> IO [Host]+-- ^ Retrieves the replica set seed list from the SRV DNS record for the given hostname+lookupSeedList hostname = do +  rs <- makeResolvSeed defaultResolvConf+  res <- withResolver rs $ \resolver -> lookupSRV resolver $ pack $ "_mongodb._tcp." ++ hostname+  case res of +    Left _ -> pure []+    Right srv -> pure $ map (\(_, _, por, tar) -> +      let tar' = dropWhileEnd (=='.') (unpack tar) +      in Host tar' (PortNumber . fromIntegral $ por)) srv
Database/MongoDB/Internal/Protocol.hs view
@@ -48,10 +48,10 @@ import GHC.Conc (ThreadStatus(..), threadStatus) import Control.Monad (forever) import Control.Monad.STM (atomically)-import Control.Concurrent (ThreadId, killThread, forkFinally)+import Control.Concurrent (ThreadId, killThread, forkIOWithUnmask) import Control.Concurrent.STM.TChan (TChan, newTChan, readTChan, writeTChan, isEmptyTChan) -import Control.Exception.Lifted (onException, throwIO, try)+import Control.Exception.Lifted (SomeException, mask_, onException, throwIO, try)  import qualified Data.ByteString.Lazy as L @@ -103,6 +103,12 @@                 , maxWriteBatchSize   :: Int                 } +-- | @'forkUnmaskedFinally' action and_then@ behaves the same as @'forkFinally' action and_then@, except that @action@ is run completely unmasked, whereas with 'forkFinally', @action@ is run with the same mask as the parent thread.+forkUnmaskedFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId+forkUnmaskedFinally action and_then =+  mask_ $ forkIOWithUnmask $ \unmask ->+    try (unmask action) >>= and_then+ -- | Create new Pipeline over given handle. You should 'close' pipeline when finished, which will also close handle. If pipeline is not closed but eventually garbage collected, it will be closed along with handle. newPipeline :: ServerData -> Transport -> IO Pipeline newPipeline serverData stream = do@@ -124,9 +130,9 @@      rec         let pipe = Pipeline{..}-        listenThread <- forkFinally (listen pipe) $ \_ -> do-                                                       putMVar finished ()-                                                       drainReplies+        listenThread <- forkUnmaskedFinally (listen pipe) $ \_ -> do+                                                              putMVar finished ()+                                                              drainReplies      _ <- mkWeakMVar vStream $ do         killThread listenThread
Database/MongoDB/Query.hs view
@@ -49,6 +49,7 @@ import Prelude hiding (lookup) import Control.Exception (Exception, throwIO) import Control.Monad (unless, replicateM, liftM, liftM2)+import Control.Monad.Fail(MonadFail) import Data.Default.Class (Default(..)) import Data.Int (Int32, Int64) import Data.Either (lefts, rights)@@ -1065,7 +1066,7 @@ -- Returns a single updated document (new option is set to true). -- -- see 'findAndModifyOpts' if you want to use findAndModify in a differnt way-findAndModify :: MonadIO m+findAndModify :: (MonadIO m, MonadFail m)               => Query               -> Document -- ^ updates               -> Action m (Either String Document)@@ -1080,7 +1081,7 @@  -- | runs the findAndModify command, -- allows more options than 'findAndModify'-findAndModifyOpts :: MonadIO m+findAndModifyOpts :: (MonadIO m, MonadFail m)                   => Query                   ->FindAndModifyOpts                   -> Action m (Either String (Maybe Document))@@ -1105,8 +1106,8 @@     return $ case lookupErr result of         Just e -> leftErr e         Nothing -> case lookup "value" result of-            Left err   -> leftErr $ "no document found: " `mappend` err-            Right mdoc -> case mdoc of+            Nothing   -> leftErr "no document found"+            Just mdoc -> case mdoc of                 Just doc@(_:_) -> Right (Just doc)                 Just [] -> case famOpts of                     FamUpdate { famUpsert = True, famNew = False } -> Right Nothing@@ -1118,9 +1119,10 @@         `mappend` "\nerror: " `mappend` err      -- return Nothing means ok, Just is the error message-    lookupErr result = case lookup "lastErrorObject" result of-        Right errObject -> lookup "err" errObject-        Left err -> Just err+    lookupErr :: Document -> Maybe String+    lookupErr result = do+        errObject <- lookup "lastErrorObject" result+        lookup "err" errObject  explain :: (MonadIO m) => Query -> Action m Document -- ^ Return performance stats of query execution@@ -1301,7 +1303,7 @@ type Pipeline = [Document] -- ^ The Aggregate Pipeline -aggregate :: MonadIO m => Collection -> Pipeline -> Action m [Document]+aggregate :: (MonadIO m, MonadFail m) => Collection -> Pipeline -> Action m [Document] -- ^ Runs an aggregate and unpacks the result. See <http://docs.mongodb.org/manual/core/aggregation/> for details. aggregate aColl agg = do     aggregateCursor aColl agg def >>= rest@@ -1312,7 +1314,7 @@ instance Default AggregateConfig where   def = AggregateConfig {} -aggregateCursor :: MonadIO m => Collection -> Pipeline -> AggregateConfig -> Action m Cursor+aggregateCursor :: (MonadIO m, MonadFail m) => Collection -> Pipeline -> AggregateConfig -> Action m Cursor -- ^ Runs an aggregate and unpacks the result. See <http://docs.mongodb.org/manual/core/aggregation/> for details. aggregateCursor aColl agg _ = do     response <- runCommand ["aggregate" =: aColl, "pipeline" =: agg, "cursor" =: ([] :: Document)]
Database/MongoDB/Transport/Tls.hs view
@@ -34,8 +34,7 @@ import Control.Exception (bracketOnError) import Control.Monad (when, unless) import System.IO-import Database.MongoDB (Pipe)-import Database.MongoDB.Internal.Protocol (newPipeWith)+import Database.MongoDB.Internal.Protocol (Pipe, newPipeWith) import Database.MongoDB.Transport (Transport(Transport)) import qualified Database.MongoDB.Transport as T import System.IO.Error (mkIOError, eofErrorType)
mongoDB.cabal view
@@ -1,5 +1,5 @@ Name:           mongoDB-Version:        2.5.0.0+Version:        2.6.0.0 Synopsis:       Driver (client) for MongoDB, a free, scalable, fast, document                 DBMS Description:    This package lets you connect to MongoDB servers and@@ -57,6 +57,9 @@                     , base16-bytestring >= 0.1.1.6                     , base64-bytestring >= 1.0.0.1                     , nonce >= 1.0.5+                    , fail+                    , dns+                    , http-types    if flag(_old-network)      -- "Network.BSD" is only available in network < 2.9@@ -127,7 +130,11 @@                     , lifted-base >= 0.1.0.3                     , transformers-base >= 0.4.1                     , hashtables >= 1.1.2.0+                    , fail+                    , dns+                    , http-types                     , criterion+                    , tls >= 1.3.0    if flag(_old-network)      -- "Network.BSD" is only available in network < 2.9