From b42710839a6d1a8ce3b22c0d40da521bd06b8fb8 Mon Sep 17 00:00:00 2001 From: Andrea Condoluci Date: Wed, 1 Apr 2020 15:11:17 +0200 Subject: [PATCH] Improve documentation --- Database/MongoDB/Admin.hs | 45 ++++++--- Database/MongoDB/Connection.hs | 24 ++--- Database/MongoDB/GridFS.hs | 2 +- Database/MongoDB/Internal/Network.hs | 2 +- Database/MongoDB/Internal/Protocol.hs | 10 +- Database/MongoDB/Query.hs | 129 ++++++++++++++------------ Database/MongoDB/Transport.hs | 4 +- 7 files changed, 121 insertions(+), 95 deletions(-) diff --git a/Database/MongoDB/Admin.hs b/Database/MongoDB/Admin.hs index bf322c8..09186f7 100644 --- a/Database/MongoDB/Admin.hs +++ b/Database/MongoDB/Admin.hs @@ -1,4 +1,4 @@ --- | Database administrative functions +-- | Database administrative functions. {-# LANGUAGE CPP, FlexibleContexts, OverloadedStrings, RecordWildCards #-} @@ -72,13 +72,13 @@ createCollection :: (MonadIO m) => [CollectionOption] -> Collection -> Action m createCollection opts col = runCommand $ ["create" =: col] ++ map coptElem opts renameCollection :: (MonadIO m) => Collection -> Collection -> Action m Document --- ^ Rename first collection to second collection +-- ^ Rename first collection to second collection. renameCollection from to = do db <- thisDatabase useDb admin $ runCommand ["renameCollection" =: db <.> from, "to" =: db <.> to, "dropTarget" =: True] 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). +-- ^ 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 r <- runCommand ["drop" =: coll] @@ -87,7 +87,7 @@ dropCollection coll = do fail $ "dropCollection failed: " ++ show r validateCollection :: (MonadIO m) => Collection -> Action m Document --- ^ This operation takes a while +-- ^ Validate the given collection, scanning the data and indexes for correctness. This operation takes a while. validateCollection coll = runCommand ["validate" =: coll] -- ** Index @@ -112,7 +112,7 @@ idxDocument Index{..} db = [ "dropDups" =: iDropDups ] ++ (maybeToList $ fmap ((=:) "expireAfterSeconds") iExpireAfterSeconds) index :: Collection -> Order -> Index --- ^ Spec of index of ordered keys on collection. Name is generated from keys. Unique and dropDups are False. +-- ^ Spec of index of ordered keys on collection. 'iName' is generated from keys. 'iUnique' and 'iDropDups' are @False@. index coll keys = Index coll keys (genName keys) False False Nothing genName :: Order -> IndexName @@ -133,19 +133,19 @@ createIndex :: (MonadIO m) => Index -> Action m () createIndex idx = insert_ "system.indexes" . idxDocument idx =<< thisDatabase dropIndex :: (MonadIO m) => Collection -> IndexName -> Action m Document --- ^ Remove the index +-- ^ Remove the index from the given collection. dropIndex coll idxName = do resetIndexCache runCommand ["deleteIndexes" =: coll, "index" =: idxName] getIndexes :: MonadIO m => Collection -> Action m [Document] --- ^ Get all indexes on this collection +-- ^ Get all indexes on this collection. getIndexes coll = do db <- thisDatabase rest =<< find (select ["ns" =: db <.> coll] "system.indexes") dropIndexes :: (MonadIO m) => Collection -> Action m Document --- ^ Drop all indexes on this collection +-- ^ Drop all indexes on this collection. dropIndexes coll = do resetIndexCache runCommand ["deleteIndexes" =: coll, "index" =: ("*" :: Text)] @@ -192,13 +192,13 @@ resetIndexCache = do -- ** User allUsers :: MonadIO m => Action m [Document] --- ^ Fetch all users of this database +-- ^ Fetch all users of this database. allUsers = map (exclude ["_id"]) `liftM` (rest =<< find (select [] "system.users") {sort = ["user" =: (1 :: Int)], project = ["user" =: (1 :: Int), "readOnly" =: (1 :: Int)]}) addUser :: (MonadIO m) => Bool -> Username -> Password -> Action m () --- ^ Add user with password with read-only access if bool is True or read-write access if bool is False +-- ^ Add user with password with read-only access if the boolean argument is @True@, or read-write access if its is @False@ addUser readOnly user pass = do mu <- findOne (select ["user" =: user] "system.users") let usr = merge ["readOnly" =: readOnly, "pwd" =: pwHash user pass] (maybe ["user" =: user] id mu) @@ -211,11 +211,11 @@ removeUser user = delete (select ["user" =: user] "system.users") -- ** Database admin :: Database --- ^ \"admin\" database +-- ^ The \"admin\" database, which stores user authorization and authentication data plus other system collections. admin = "admin" cloneDatabase :: (MonadIO m) => Database -> Host -> Action m Document --- ^ Copy database from given host to the server I am connected to. Fails and returns @"ok" = 0@ if we don't have permission to read from given server (use copyDatabase in this case). +-- ^ Copy database from given host to the server I am connected to. Fails and returns @"ok" = 0@ if we don't have permission to read from given server (use 'copyDatabase' in this case). cloneDatabase db fromHost = useDb db $ runCommand ["clone" =: showHostPort fromHost] copyDatabase :: (MonadIO m) => Database -> Host -> Maybe (Username, Password) -> Database -> Action m Document @@ -239,9 +239,11 @@ repairDatabase db = useDb db $ runCommand ["repairDatabase" =: (1 :: Int)] -- ** Server serverBuildInfo :: (MonadIO m) => Action m Document +-- ^ Return a document containing the parameters used to compile the server instance. serverBuildInfo = useDb admin $ runCommand ["buildinfo" =: (1 :: Int)] serverVersion :: (MonadIO m) => Action m Text +-- ^ Return the version of the server instance. serverVersion = at "version" `liftM` serverBuildInfo -- * Diagnostics @@ -249,15 +251,19 @@ serverVersion = at "version" `liftM` serverBuildInfo -- ** Collection collectionStats :: (MonadIO m) => Collection -> Action m Document +-- ^ Return some storage statistics for the given collection. collectionStats coll = runCommand ["collstats" =: coll] dataSize :: (MonadIO m) => Collection -> Action m Int +-- ^ Return the total uncompressed size (in bytes) in memory of all records in the given collection. Does not include indexes. dataSize c = at "size" `liftM` collectionStats c storageSize :: (MonadIO m) => Collection -> Action m Int +-- ^ Return the total bytes allocated to the given collection. Does not include indexes. storageSize c = at "storageSize" `liftM` collectionStats c totalIndexSize :: (MonadIO m) => Collection -> Action m Int +-- ^ The total size in bytes of all indexes in this collection. totalIndexSize c = at "totalIndexSize" `liftM` collectionStats c totalSize :: MonadIO m => Collection -> Action m Int @@ -270,34 +276,45 @@ totalSize coll = do -- ** Profiling -data ProfilingLevel = Off | Slow | All deriving (Show, Enum, Eq) +-- | The available profiler levels. +data ProfilingLevel + = Off -- ^ No data collection. + | Slow -- ^ Data collected only for slow operations. The slow operation time threshold is 100ms by default, but can be changed using 'setProfilingLevel'. + | All -- ^ Data collected for all operations. + deriving (Show, Enum, Eq) getProfilingLevel :: (MonadIO m) => Action m ProfilingLevel +-- ^ Get the profiler level. getProfilingLevel = (toEnum . at "was") `liftM` runCommand ["profile" =: (-1 :: Int)] type MilliSec = Int setProfilingLevel :: (MonadIO m) => ProfilingLevel -> Maybe MilliSec -> Action m () +-- ^ Set the profiler level, and optionally the slow operation time threshold (in milliseconds). setProfilingLevel p mSlowMs = runCommand (["profile" =: fromEnum p] ++ ("slowms" =? mSlowMs)) >> return () -- ** Database dbStats :: (MonadIO m) => Action m Document +-- ^ Return some storage statistics for the given database. dbStats = runCommand ["dbstats" =: (1 :: Int)] currentOp :: (MonadIO m) => Action m (Maybe Document) --- ^ See currently running operation on the database, if any +-- ^ See currently running operation on the database, if any. currentOp = findOne (select [] "$cmd.sys.inprog") +-- | An operation indentifier. type OpNum = Int killOp :: (MonadIO m) => OpNum -> Action m (Maybe Document) +-- ^ Terminate the operation specified by the given 'OpNum'. killOp op = findOne (select ["op" =: op] "$cmd.sys.killop") -- ** Server serverStatus :: (MonadIO m) => Action m Document +-- ^ Return a document with an overview of the state of the database. serverStatus = useDb admin $ runCommand ["serverStatus" =: (1 :: Int)] diff --git a/Database/MongoDB/Connection.hs b/Database/MongoDB/Connection.hs index 0082543..5631244 100644 --- a/Database/MongoDB/Connection.hs +++ b/Database/MongoDB/Connection.hs @@ -75,7 +75,8 @@ host :: HostName -> Host host hostname = Host hostname defaultPort showHostPort :: Host -> String --- ^ Display host as \"host:port\" +-- ^ Display host as \"host:port\". + -- TODO: Distinguish Service port showHostPort (Host hostname (PortNumber port)) = hostname ++ ":" ++ show port #if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32) @@ -84,6 +85,7 @@ showHostPort (Host _ (UnixSocket path)) = "unix:" ++ path 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 port readHostPortM = either (fail . show) return . parse parser "readHostPort" where hostname = many1 (letter <|> digit <|> char '-' <|> char '.' <|> char '_') @@ -109,16 +111,16 @@ readHostPort = fromJust . readHostPortM type Secs = Double globalConnectTimeout :: IORef Secs --- ^ 'connect' (and 'openReplicaSet') fails if it can't connect within this many seconds (default is 6 seconds). Use 'connect\'' (and 'openReplicaSet\'') if you want to ignore this global and specify your own timeout. Note, this timeout only applies to initial connection establishment, not when reading/writing to the connection. +-- ^ 'connect' (and 'openReplicaSet') fails if it can't connect within this many seconds (default is 6 seconds). Use 'connect'' (and 'openReplicaSet'') if you want to ignore this global and specify your own timeout. Note, this timeout only applies to initial connection establishment, not when reading/writing to the connection. globalConnectTimeout = unsafePerformIO (newIORef 6) {-# NOINLINE globalConnectTimeout #-} connect :: Host -> IO Pipe --- ^ Connect to Host returning pipelined TCP connection. Throw IOError if connection refused or no response within 'globalConnectTimeout'. +-- ^ Connect to Host returning pipelined TCP connection. Throw 'IOError' if connection refused or no response within 'globalConnectTimeout'. connect h = readIORef globalConnectTimeout >>= flip connect' h connect' :: Secs -> Host -> IO Pipe --- ^ Connect to Host returning pipelined TCP connection. Throw IOError if connection refused or no response within given number of seconds. +-- ^ Connect to Host returning pipelined TCP connection. Throw 'IOError' if connection refused or no response within given number of seconds. connect' timeoutSecs (Host hostname port) = do mh <- timeout (round $ timeoutSecs * 1000000) (connectTo hostname port) handle <- maybe (ioError $ userError "connect timed out") return mh @@ -137,11 +139,11 @@ data TransportSecurity = Secure | Unsecure data ReplicaSet = ReplicaSet ReplicaSetName (MVar [(Host, Maybe Pipe)]) Secs TransportSecurity replSetName :: ReplicaSet -> Text --- ^ name of connected replica set +-- ^ Get the name of connected replica set. 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. +-- ^ 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. openReplicaSet rsSeed = readIORef globalConnectTimeout >>= flip openReplicaSet' rsSeed openReplicaSet' :: Secs -> (ReplicaSetName, [Host]) -> IO ReplicaSet @@ -149,7 +151,7 @@ openReplicaSet' :: Secs -> (ReplicaSetName, [Host]) -> IO ReplicaSet 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. +-- ^ 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 @@ -164,23 +166,23 @@ _openReplicaSet timeoutSecs (rsName, seedList, transportSecurity) = do 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. +-- ^ 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. +-- ^ 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. +-- ^ 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. +-- ^ 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 diff --git a/Database/MongoDB/GridFS.hs b/Database/MongoDB/GridFS.hs index 5515ace..0c1ce15 100644 --- a/Database/MongoDB/GridFS.hs +++ b/Database/MongoDB/GridFS.hs @@ -53,7 +53,7 @@ md5BlockSizeInBytes = 64 data Bucket = Bucket {files :: Text, chunks :: Text} --- ^ Files are stored in "buckets". You open a bucket with openDefaultBucket or openBucket +-- ^ Files are stored in /buckets/. You open a bucket with 'openDefaultBucket' or 'openBucket'. openDefaultBucket :: (Monad m, MonadIO m) => Action m Bucket -- ^ Open the default 'Bucket' (named "fs") diff --git a/Database/MongoDB/Internal/Network.hs b/Database/MongoDB/Internal/Network.hs index 11190b1..74f1659 100644 --- a/Database/MongoDB/Internal/Network.hs +++ b/Database/MongoDB/Internal/Network.hs @@ -28,7 +28,7 @@ import Network.DNS.Resolver (defaultResolvConf, makeResolvSeed, withResolver) import Network.HTTP.Types.URI (parseQueryText) --- | Wraps network's 'PortNumber' +-- | Wraps network's 'PortNumber'. -- Used to ease compatibility between older and newer network versions. data PortID = PortNumber N.PortNumber #if !defined(mingw32_HOST_OS) && !defined(cygwin32_HOST_OS) && !defined(_WIN32) diff --git a/Database/MongoDB/Internal/Protocol.hs b/Database/MongoDB/Internal/Protocol.hs index 5368f35..0f786f9 100644 --- a/Database/MongoDB/Internal/Protocol.hs +++ b/Database/MongoDB/Internal/Protocol.hs @@ -385,8 +385,8 @@ data Request = qFullCollection :: FullCollection, qSkip :: Int32, -- ^ Number of initial matching documents to skip qBatchSize :: Int32, -- ^ The number of document to return in each batch response from the server. 0 means use Mongo default. Negative means close cursor after first batch and use absolute value as batch size. - qSelector :: Document, -- ^ \[\] = return all documents in collection - qProjector :: Document -- ^ \[\] = return whole document + qSelector :: Document, -- ^ @[]@ = return all documents in collection + qProjector :: Document -- ^ @[]@ = return whole document } | GetMore { gFullCollection :: FullCollection, gBatchSize :: Int32, @@ -394,13 +394,15 @@ data Request = deriving (Show, Eq) data QueryOption = - TailableCursor -- ^ Tailable means cursor is not closed when the last data is retrieved. Rather, the cursor marks the final object's position. You can resume using the cursor later, from where it was located, if more data were received. Like any "latent cursor", the cursor may become invalid at some point – for example if the final object it references were deleted. Thus, you should be prepared to requery on CursorNotFound exception. + TailableCursor -- ^ Tailable means cursor is not closed when the last data is retrieved. Rather, the cursor marks the final object's position. You can resume using the cursor later, from where it was located, if more data were received. Like any "latent cursor", the cursor may become invalid at some point – for example if the final object it references were deleted. Thus, you should be prepared to requery on @CursorNotFound@ exception. | SlaveOK -- ^ Allow query of replica slave. Normally these return an error except for namespace "local". | NoCursorTimeout -- ^ The server normally times out idle cursors after 10 minutes to prevent a memory leak in case a client forgets to close a cursor. Set this option to allow a cursor to live forever until it is closed. | AwaitData -- ^ Use with TailableCursor. If we are at the end of the data, block for a while rather than returning no data. After a timeout period, we do return as normal. + -- | Exhaust -- ^ Stream the data down full blast in multiple "more" packages, on the assumption that the client will fully read all data queried. Faster when you are pulling a lot of data and know you want to pull it all down. Note: the client is not allowed to not read all the data unless it closes the connection. -- Exhaust commented out because not compatible with current `Pipeline` implementation - | Partial -- ^ Get partial results from a _mongos_ if some shards are down, instead of throwing an error. + + | Partial -- ^ Get partial results from a /mongos/ if some shards are down, instead of throwing an error. deriving (Show, Eq) -- *** Binary format diff --git a/Database/MongoDB/Query.hs b/Database/MongoDB/Query.hs index 7b9bf51..5fc2eec 100644 --- a/Database/MongoDB/Query.hs +++ b/Database/MongoDB/Query.hs @@ -113,7 +113,7 @@ import Data.Maybe (fromMaybe) -- * Monad type Action = ReaderT MongoContext --- ^ A monad on top of m (which must be a MonadIO) that may access the database and may fail with a DB 'Failure' +-- ^ A monad on top of m (which must be a MonadIO) that may access the database and may fail with a DB 'Failure'. access :: (MonadIO m) => Pipe -> AccessMode -> Database -> Action m a -> m a -- ^ Run action against database on server at other end of pipe. Use access mode for any reads and writes. @@ -136,17 +136,17 @@ data Failure = instance Exception Failure type ErrorCode = Int --- ^ Error code from getLastError or query failure +-- ^ Error code from @getLastError@ or query failure. --- | Type of reads and writes to perform +-- | Type of reads and writes to perform. data AccessMode = ReadStaleOk -- ^ Read-only action, reading stale data from a slave is OK. | UnconfirmedWrites -- ^ Read-write action, slave not OK, every write is fire & forget. - | ConfirmWrites GetLastError -- ^ Read-write action, slave not OK, every write is confirmed with getLastError. + | ConfirmWrites GetLastError -- ^ Read-write action, slave not OK, every write is confirmed with @getLastError@. deriving Show type GetLastError = Document --- ^ Parameters for getLastError command. For example @[\"w\" =: 2]@ tells the server to wait for the write to reach at least two servers in replica set before acknowledging. See for more options. +-- ^ Parameters for @getLastError@ command. For example @[\"w\" =: 2]@ tells the server to wait for the write to reach at least two servers in replica set before acknowledging. See for more options. class Result a where isFailed :: a -> Bool @@ -198,9 +198,13 @@ writeMode (ConfirmWrites z) = Confirm z -- | Values needed when executing a db operation data MongoContext = MongoContext { - mongoPipe :: Pipe, -- ^ operations read/write to this pipelined TCP connection to a MongoDB server - mongoAccessMode :: AccessMode, -- ^ read/write operation will use this access mode - mongoDatabase :: Database } -- ^ operations query/update this database + -- | operations read/write to this pipelined TCP connection to a MongoDB server + mongoPipe :: Pipe, + -- | read/write operation will use this access mode + mongoAccessMode :: AccessMode, + -- | operations query/update this database + mongoDatabase :: Database +} mongoReadMode :: MongoContext -> ReadMode mongoReadMode = readMode . mongoAccessMode @@ -414,7 +418,7 @@ write notice = asks mongoWriteMode >>= \mode -> case mode of -- ** Insert insert :: (MonadIO m) => Collection -> Document -> Action m Value --- ^ Insert document into collection and return its \"_id\" value, which is created automatically if not supplied +-- ^ Insert document into collection and return its @_id@ value, which is created automatically if not supplied insert col doc = do doc' <- liftIO $ assignId doc res <- insertBlock [] col (0, [doc']) @@ -423,30 +427,30 @@ insert col doc = do Right r -> return $ head r insert_ :: (MonadIO m) => Collection -> Document -> Action m () --- ^ Same as 'insert' except don't return _id +-- ^ Same as 'insert' except don't return @_id@ insert_ col doc = insert col doc >> return () insertMany :: (MonadIO m) => Collection -> [Document] -> Action m [Value] --- ^ Insert documents into collection and return their \"_id\" values, +-- ^ Insert documents into collection and return their @_id@ values, -- which are created automatically if not supplied. -- If a document fails to be inserted (eg. due to duplicate key) --- then remaining docs are aborted, and LastError is set. +-- then remaining docs are aborted, and @LastError@ is set. -- An exception will be throw if any error occurs. insertMany = insert' [] insertMany_ :: (MonadIO m) => Collection -> [Document] -> Action m () --- ^ Same as 'insertMany' except don't return _ids +-- ^ Same as 'insertMany' except don't return @_id@ values insertMany_ col docs = insertMany col docs >> return () insertAll :: (MonadIO m) => Collection -> [Document] -> Action m [Value] --- ^ Insert documents into collection and return their \"_id\" values, +-- ^ Insert documents into collection and return their @_id@ values, -- which are created automatically if not supplied. If a document fails -- to be inserted (eg. due to duplicate key) then remaining docs -- are still inserted. insertAll = insert' [KeepGoing] insertAll_ :: (MonadIO m) => Collection -> [Document] -> Action m () --- ^ Same as 'insertAll' except don't return _ids +-- ^ Same as 'insertAll' except don't return @_id@ values. insertAll_ col docs = insertAll col docs >> return () insertCommandDocument :: [InsertOption] -> Collection -> [Document] -> Document -> Document @@ -462,7 +466,7 @@ takeRightsUpToLeft l = E.rights $ takeWhile E.isRight l insert' :: (MonadIO m) => [InsertOption] -> Collection -> [Document] -> Action m [Value] --- ^ Insert documents into collection and return their \"_id\" values, which are created automatically if not supplied +-- ^ Insert documents into collection and return their @_id@ values, which are created automatically if not supplied insert' opts col docs = do p <- asks mongoPipe let sd = P.serverData p @@ -577,7 +581,7 @@ sizeOfDocument :: Document -> Int sizeOfDocument d = fromIntegral $ LBS.length $ runPut $ putDocument d assignId :: Document -> IO Document --- ^ Assign a unique value to _id field if missing +-- ^ Assign a unique value to @_id@ field if missing assignId doc = if any (("_id" ==) . label) doc then return doc else (\oid -> ("_id" =: oid) : doc) `liftM` genObjectId @@ -586,7 +590,7 @@ assignId doc = if any (("_id" ==) . label) doc save :: (MonadIO m) => Collection -> Document -> Action m () --- ^ Save document to collection, meaning insert it if its new (has no \"_id\" field) or upsert it if its not new (has \"_id\" field) +-- ^ Save document to collection, meaning insert it if its new (has no @_id@ field) or upsert it if its not new (has @_id@ field) save col doc = case look "_id" doc of Nothing -> insert_ col doc Just i -> upsert (Select ["_id" := i] col) doc @@ -632,12 +636,12 @@ updateCommandDocument col ordered updates writeConcern = ] {-| Bulk update operation. If one update fails it will not update the remaining - - documents. Current returned value is only a place holder. With mongodb server - - before 2.6 it will send update requests one by one. In order to receive - - error messages in versions under 2.6 you need to user confirmed writes. - - Otherwise even if the errors had place the list of errors will be empty and - - the result will be success. After 2.6 it will use bulk update feature in - - mongodb. + documents. Current returned value is only a place holder. With mongodb server + before 2.6 it will send update requests one by one. In order to receive + error messages in versions under 2.6 you need to user confirmed writes. + Otherwise even if the errors had place the list of errors will be empty and + the result will be success. After 2.6 it will use bulk update feature in + mongodb. -} updateMany :: (MonadIO m) => Collection @@ -646,11 +650,11 @@ updateMany :: (MonadIO m) updateMany = update' True {-| Bulk update operation. If one update fails it will proceed with the - - remaining documents. With mongodb server before 2.6 it will send update - - requests one by one. In order to receive error messages in versions under - - 2.6 you need to use confirmed writes. Otherwise even if the errors had - - place the list of errors will be empty and the result will be success. - - After 2.6 it will use bulk update feature in mongodb. + remaining documents. With mongodb server before 2.6 it will send update + requests one by one. In order to receive error messages in versions under + 2.6 you need to use confirmed writes. Otherwise even if the errors had + place the list of errors will be empty and the result will be success. + After 2.6 it will use bulk update feature in mongodb. -} updateAll :: (MonadIO m) => Collection @@ -846,9 +850,9 @@ deleteHelper opts (Select sel col) = do liftIO $ runReaderT (void $ write (Delete (db <.> col) opts sel)) ctx {-| Bulk delete operation. If one delete fails it will not delete the remaining - - documents. Current returned value is only a place holder. With mongodb server - - before 2.6 it will send delete requests one by one. After 2.6 it will use - - bulk delete feature in mongodb. + documents. Current returned value is only a place holder. With mongodb server + before 2.6 it will send delete requests one by one. After 2.6 it will use + bulk delete feature in mongodb. -} deleteMany :: (MonadIO m) => Collection @@ -857,9 +861,9 @@ deleteMany :: (MonadIO m) deleteMany = delete' True {-| Bulk delete operation. If one delete fails it will proceed with the - - remaining documents. Current returned value is only a place holder. With - - mongodb server before 2.6 it will send delete requests one by one. After 2.6 - - it will use bulk delete feature in mongodb. + remaining documents. Current returned value is only a place holder. With + mongodb server before 2.6 it will send delete requests one by one. After 2.6 + it will use bulk delete feature in mongodb. -} deleteAll :: (MonadIO m) => Collection @@ -998,15 +1002,15 @@ readModeOption StaleOk = [SlaveOK] -- | Use 'select' to create a basic query with defaults, then modify if desired. For example, @(select sel col) {limit = 10}@ data Query = Query { - options :: [QueryOption], -- ^ Default = [] + options :: [QueryOption], -- ^ Default = @[]@ selection :: Selection, - project :: Projector, -- ^ \[\] = all fields. Default = [] + project :: Projector, -- ^ @[]@ = all fields. Default = @[]@ skip :: Word32, -- ^ Number of initial matching documents to skip. Default = 0 limit :: Limit, -- ^ Maximum number of documents to return, 0 = no limit. Default = 0 - sort :: Order, -- ^ Sort results by this order, [] = no sort. Default = [] - snapshot :: Bool, -- ^ If true assures no duplicates are returned, or objects missed, which were present at both the start and end of the query's execution (even if the object were updated). If an object is new during the query, or deleted during the query, it may or may not be returned, even with snapshot mode. Note that short query responses (less than 1MB) are always effectively snapshotted. Default = False + sort :: Order, -- ^ Sort results by this order, @[]@ = no sort. Default = @[]@ + snapshot :: Bool, -- ^ If true assures no duplicates are returned, or objects missed, which were present at both the start and end of the query's execution (even if the object were updated). If an object is new during the query, or deleted during the query, it may or may not be returned, even with snapshot mode. Note that short query responses (less than 1MB) are always effectively snapshotted. Default = @False@ batchSize :: BatchSize, -- ^ The number of document to return in each batch response from the server. 0 means use Mongo default. Default = 0 - hint :: Order -- ^ Force MongoDB to use this index, [] = no hint. Default = [] + hint :: Order -- ^ Force MongoDB to use this index, @[]@ = no hint. Default = @[]@ } deriving (Show, Eq) type Projector = Document @@ -1035,7 +1039,7 @@ find q@Query{selection, batchSize} = do newCursor db (coll selection) batchSize dBatch findOne :: (MonadIO m) => Query -> Action m (Maybe Document) --- ^ Fetch first document satisfying query or Nothing if none satisfy it +-- ^ Fetch first document satisfying query or @Nothing@ if none satisfy it findOne q = do pipe <- asks mongoPipe qr <- queryRequest False q {limit = 1} @@ -1047,14 +1051,17 @@ fetch :: (MonadIO m) => Query -> Action m Document -- ^ Same as 'findOne' except throw 'DocNotFound' if none match fetch q = findOne q >>= maybe (liftIO $ throwIO $ DocNotFound $ selection q) return -data FindAndModifyOpts = FamRemove Bool - | FamUpdate - { famUpdate :: Document - , famNew :: Bool - , famUpsert :: Bool - } - deriving Show +-- | Options for @findAndModify@ +data FindAndModifyOpts + = FamRemove Bool -- ^ remove the selected document when the boolean is @True@ + | FamUpdate + { famUpdate :: Document -- ^ update the the selected document + , famNew :: Bool -- ^ return the document with the modifications made on the update + , famUpsert :: Bool -- ^ create a new document if no documents match the query + } + deriving Show +-- | Default options used by 'findAndModify'. defFamUpdateOpts :: Document -> FindAndModifyOpts defFamUpdateOpts ups = FamUpdate { famNew = True @@ -1062,10 +1069,10 @@ defFamUpdateOpts ups = FamUpdate , famUpdate = ups } --- | runs the findAndModify command as an update without an upsert and new set to true. --- Returns a single updated document (new option is set to true). +-- | Run the @findAndModify@ command as an update without an upsert and new set to @True@. +-- Return a single updated document (@new@ option is set to @True@). -- --- see 'findAndModifyOpts' if you want to use findAndModify in a differnt way +-- See 'findAndModifyOpts' for more options. findAndModify :: (MonadIO m, MonadFail m) => Query -> Document -- ^ updates @@ -1079,11 +1086,11 @@ findAndModify q ups = do Nothing -> Left "findAndModify: impossible null result" Just doc -> Right doc --- | runs the findAndModify command, --- allows more options than 'findAndModify' +-- | Run the @findAndModify@ command +-- (allows more options than 'findAndModify') findAndModifyOpts :: (MonadIO m, MonadFail m) => Query - ->FindAndModifyOpts + -> FindAndModifyOpts -> Action m (Either String (Maybe Document)) findAndModifyOpts (Query { selection = Select sel collection @@ -1335,12 +1342,12 @@ data Group = Group { gKey :: GroupKey, -- ^ Fields to group by gReduce :: Javascript, -- ^ @(doc, agg) -> ()@. The reduce function reduces (aggregates) the objects iterated. Typical operations of a reduce function include summing and counting. It takes two arguments, the current document being iterated over and the aggregation value, and updates the aggregate value. gInitial :: Document, -- ^ @agg@. Initial aggregation value supplied to reduce - gCond :: Selector, -- ^ Condition that must be true for a row to be considered. [] means always true. - gFinalize :: Maybe Javascript -- ^ @agg -> () | result@. An optional function to be run on each item in the result set just before the item is returned. Can either modify the item (e.g., add an average field given a count and a total) or return a replacement object (returning a new object with just _id and average fields). + gCond :: Selector, -- ^ Condition that must be true for a row to be considered. @[]@ means always true. + gFinalize :: Maybe Javascript -- ^ @agg -> () | result@. An optional function to be run on each item in the result set just before the item is returned. Can either modify the item (e.g., add an average field given a count and a total) or return a replacement object (returning a new object with just @_id@ and average fields). } deriving (Show, Eq) data GroupKey = Key [Label] | KeyF Javascript deriving (Show, Eq) --- ^ Fields to group by, or function (@doc -> key@) returning a "key object" to be used as the grouping key. Use KeyF instead of Key to specify a key that is not an existing member of the object (or, to access embedded members). +-- ^ Fields to group by, or function (@doc -> key@) returning a "key object" to be used as the grouping key. Use 'KeyF' instead of 'Key' to specify a key that is not an existing member of the object (or, to access embedded members). groupDocument :: Group -> Document -- ^ Translate Group data into expected document form @@ -1359,17 +1366,17 @@ group g = at "retval" `liftM` runCommand ["group" =: groupDocument g] -- ** MapReduce -- | Maps every document in collection to a list of (key, value) pairs, then for each unique key reduces all its associated values to a single result. There are additional parameters that may be set to tweak this basic operation. --- This implements the latest version of map-reduce that requires MongoDB 1.7.4 or greater. To map-reduce against an older server use runCommand directly as described in http://www.mongodb.org/display/DOCS/MapReduce. +-- This implements the latest version of map-reduce that requires MongoDB 1.7.4 or greater. To map-reduce against an older server use 'runCommand' directly as described in http://www.mongodb.org/display/DOCS/MapReduce. data MapReduce = MapReduce { rColl :: Collection, rMap :: MapFun, rReduce :: ReduceFun, - rSelect :: Selector, -- ^ Operate on only those documents selected. Default is [] meaning all documents. - rSort :: Order, -- ^ Default is [] meaning no sort + rSelect :: Selector, -- ^ Operate on only those documents selected. Default is @[]@ meaning all documents. + rSort :: Order, -- ^ Default is @[]@ meaning no sort rLimit :: Limit, -- ^ Default is 0 meaning no limit rOut :: MROut, -- ^ Output to a collection with a certain merge policy. Default is no collection ('Inline'). Note, you don't want this default if your result set is large. rFinalize :: Maybe FinalizeFun, -- ^ Function to apply to all the results when finished. Default is Nothing. - rScope :: Document, -- ^ Variables (environment) that can be accessed from map/reduce/finalize. Default is []. + rScope :: Document, -- ^ Variables (environment) that can be accessed from map/reduce/finalize. Default is @[]@. rVerbose :: Bool -- ^ Provide statistics on job execution time. Default is False. } deriving (Show, Eq) diff --git a/Database/MongoDB/Transport.hs b/Database/MongoDB/Transport.hs index a7d5d98..e253cee 100644 --- a/Database/MongoDB/Transport.hs +++ b/Database/MongoDB/Transport.hs @@ -21,10 +21,8 @@ import qualified Data.ByteString as ByteString import System.IO -- | Abstract transport interface --- --- `read` should return `ByteString.null` on EOF data Transport = Transport { - read :: Int -> IO ByteString, + read :: Int -> IO ByteString, -- ^ should return `ByteString.null` on @EOF@ write :: ByteString -> IO (), flush :: IO (), close :: IO ()}