Skip to content

Commit 46643fd

Browse files
committed
Make runCommand compatible with MongoDB 6.0
1 parent 995087e commit 46643fd

File tree

2 files changed

+49
-14
lines changed

2 files changed

+49
-14
lines changed

Database/MongoDB/Internal/Protocol.hs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,10 @@ putOpMsg cmd requestId flagBit params = do
581581
putInt32 (bit $ bitOpMsg $ ExhaustAllowed)
582582
putInt8 0
583583
putDocument pre
584+
Message{..} -> do
585+
putInt32 biT
586+
putInt8 0
587+
putDocument $ merge [ "$db" =: mDatabase ] mParams
584588
Kc k -> case k of
585589
KillC{..} -> do
586590
let n = T.splitOn "." kFullCollection
@@ -656,7 +660,11 @@ data Request =
656660
} | GetMore {
657661
gFullCollection :: FullCollection,
658662
gBatchSize :: Int32,
659-
gCursorId :: CursorId}
663+
gCursorId :: CursorId
664+
} | Message {
665+
mDatabase :: Text,
666+
mParams :: Document
667+
}
660668
deriving (Show, Eq)
661669

662670
data QueryOption =
@@ -676,6 +684,7 @@ data QueryOption =
676684
qOpcode :: Request -> Opcode
677685
qOpcode Query{} = 2004
678686
qOpcode GetMore{} = 2005
687+
qOpcode Message{} = 2013
679688

680689
opMsgOpcode :: Opcode
681690
opMsgOpcode = 2013
@@ -696,6 +705,10 @@ putRequest request requestId = do
696705
putCString gFullCollection
697706
putInt32 gBatchSize
698707
putInt64 gCursorId
708+
Message{..} -> do
709+
putInt32 0
710+
putInt8 0
711+
putDocument $ merge [ "$db" =: mDatabase ] mParams
699712

700713
qBit :: QueryOption -> Int32
701714
qBit TailableCursor = bit 1

Database/MongoDB/Query.hs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,9 +1272,9 @@ find q@Query{selection, batchSize} = do
12721272
qr <- queryRequestOpMsg False q
12731273
let newQr =
12741274
case fst qr of
1275-
Req qry ->
1276-
let coll = last $ T.splitOn "." (qFullCollection qry)
1277-
in (Req $ qry {qSelector = merge (qSelector qry) [ "find" =: coll ]}, snd qr)
1275+
Req P.Query{..} ->
1276+
let coll = last $ T.splitOn "." qFullCollection
1277+
in (Req $ P.Query {qSelector = merge qSelector [ "find" =: coll ], ..}, snd qr)
12781278
-- queryRequestOpMsg only returns Cmd types constructed via Req
12791279
_ -> error "impossible"
12801280
dBatch <- liftIO $ requestOpMsg pipe newQr []
@@ -1312,6 +1312,9 @@ findCommand q@Query{..} = do
13121312
| predicate a = Just (f a)
13131313
| otherwise = Nothing
13141314

1315+
isHandshake :: Document -> Bool
1316+
isHandshake = (== ["isMaster" =: (1 :: Int32)])
1317+
13151318
findOne :: (MonadIO m) => Query -> Action m (Maybe Document)
13161319
-- ^ Fetch first document satisfying query or @Nothing@ if none satisfy it
13171320
findOne q = do
@@ -1321,8 +1324,7 @@ findOne q = do
13211324
rq <- liftIO $ request pipe [] qr
13221325
Batch _ _ docs <- liftDB $ fulfill rq
13231326
return (listToMaybe docs)
1324-
isHandshake = (== ["isMaster" =: (1 :: Int32)]) $ selector $ selection q :: Bool
1325-
if isHandshake
1327+
if isHandshake (selector $ selection q)
13261328
then legacyQuery
13271329
else do
13281330
let sd = P.serverData pipe
@@ -1332,14 +1334,14 @@ findOne q = do
13321334
qr <- queryRequestOpMsg False q {limit = 1}
13331335
let newQr =
13341336
case fst qr of
1335-
Req qry ->
1336-
let coll = last $ T.splitOn "." (qFullCollection qry)
1337+
Req P.Query{..} ->
1338+
let coll = last $ T.splitOn "." qFullCollection
13371339
-- We have to understand whether findOne is called as
13381340
-- command directly. This is necessary since findOne is used via
13391341
-- runCommand as a vehicle to execute any type of commands and notices.
1340-
labels = catMaybes $ map (\f -> look f $ qSelector qry) (noticeCommands ++ adminCommands) :: [Value]
1342+
labels = catMaybes $ map (\f -> look f qSelector) (noticeCommands ++ adminCommands) :: [Value]
13411343
in if null labels
1342-
then (Req $ qry {qSelector = merge (qSelector qry) [ "find" =: coll ]}, snd qr)
1344+
then (Req P.Query {qSelector = merge qSelector [ "find" =: coll ], ..}, snd qr)
13431345
else qr
13441346
_ -> error "impossible"
13451347
rq <- liftIO $ requestOpMsg pipe newQr []
@@ -1526,7 +1528,7 @@ requestOpMsg pipe (Req r, remainingLimit) params = do
15261528
promise <- liftIOE ConnectionFailure $ P.callOpMsg pipe r Nothing params
15271529
let protectedPromise = liftIOE ConnectionFailure promise
15281530
return $ fromReply remainingLimit =<< protectedPromise
1529-
requestOpMsg _ (Nc _, _) _ = error "requestOpMsg: Only messages of type Query are supported"
1531+
requestOpMsg _ _ _ = error "requestOpMsg: Only messages of type Query are supported"
15301532

15311533
fromReply :: Maybe Limit -> Reply -> DelayedBatch
15321534
-- ^ Convert Reply to Batch or Failure
@@ -1844,9 +1846,29 @@ type Command = Document
18441846
-- ^ A command is a special query or action against the database. See <http://www.mongodb.org/display/DOCS/Commands> for details.
18451847

18461848
runCommand :: (MonadIO m) => Command -> Action m Document
1847-
-- ^ Run command against the database and return its result
1848-
runCommand c = fromMaybe err <$> findOne (query c "$cmd") where
1849-
err = error $ "Nothing returned for command: " ++ show c
1849+
runCommand params = do
1850+
pipe <- asks mongoPipe
1851+
if isHandshake params || maxWireVersion (P.serverData pipe) < 17
1852+
then runCommandLegacy pipe params
1853+
else runCommand' pipe params
1854+
1855+
runCommandLegacy :: MonadIO m => Pipe -> Selector -> ReaderT MongoContext m Document
1856+
runCommandLegacy pipe params = do
1857+
qr <- queryRequest False (query params "$cmd") {limit = 1}
1858+
rq <- liftIO $ request pipe [] qr
1859+
Batch _ _ docs <- liftDB $ fulfill rq
1860+
case docs of
1861+
[doc] -> pure doc
1862+
_ -> error $ "Nothing returned for command: " <> show params
1863+
1864+
runCommand' :: MonadIO m => Pipe -> Selector -> ReaderT MongoContext m Document
1865+
runCommand' pipe params = do
1866+
ctx <- ask
1867+
rq <- liftIO $ requestOpMsg pipe ( Req (P.Message (mongoDatabase ctx) params), Just 1) []
1868+
Batch _ _ docs <- liftDB $ fulfill rq
1869+
case docs of
1870+
[doc] -> pure doc
1871+
_ -> error $ "Nothing returned for command: " <> show params
18501872

18511873
runCommand1 :: (MonadIO m) => Text -> Action m Document
18521874
-- ^ @runCommand1 foo = runCommand [foo =: 1]@

0 commit comments

Comments
 (0)