diff --git a/Database/MongoDB/Internal/Protocol.hs b/Database/MongoDB/Internal/Protocol.hs index 26d190c..df4e367 100644 --- a/Database/MongoDB/Internal/Protocol.hs +++ b/Database/MongoDB/Internal/Protocol.hs @@ -494,6 +494,9 @@ data FlagBit = | ExhaustAllowed -- ^ The client is prepared for multiple replies to this request using the moreToCome bit. deriving (Show, Eq, Enum) +uOptDoc :: UpdateOption -> Document +uOptDoc Upsert = ["upsert" =: True] +uOptDoc MultiUpdate = ["multi" =: True] {- OP_MSG header == 16 byte @@ -528,7 +531,7 @@ putOpMsg cmd requestId flagBit params = do putCString "documents" -- identifier mapM_ putDocument iDocuments -- payload Update{..} -> do - let doc = ["q" =: uSelector, "u" =: uUpdater] + let doc = ["q" =: uSelector, "u" =: uUpdater] <> concatMap uOptDoc uOptions (sec0, sec1Size) = prepSectionInfo uFullCollection diff --git a/test/QuerySpec.hs b/test/QuerySpec.hs index 4d7435e..e7aa1fa 100644 --- a/test/QuerySpec.hs +++ b/test/QuerySpec.hs @@ -4,6 +4,7 @@ module QuerySpec (spec) where import Data.String (IsString(..)) import TestImport +import Control.Concurrent (threadDelay) import Control.Exception import Control.Monad (forM_, when) import System.Environment (getEnv) @@ -87,6 +88,21 @@ spec = around withCleanDatabase $ do db (count $ select ["name" =: "Yankees", "league" =: "American"] "team") `shouldReturn` 1 _id `shouldBe` () + describe "upsert" $ do + it "upserts a document twice with the same spec" $ do + let q = select ["name" =: "jack"] "users" + db $ upsert q ["color" =: "blue", "name" =: "jack"] + -- since there is no way to ask for a ack, we must wait for "a sufficient time" + -- for the write to be visible + threadDelay 10000 + db (rest =<< find (select [] "users")) >>= print + db (count $ select ["name" =: "jack"] "users") `shouldReturn` 1 + db $ upsert q ["color" =: "red", "name" =: "jack"] + threadDelay 10000 + db (count $ select ["name" =: "jack"] "users") `shouldReturn` 1 + Just doc <- db $ findOne (select ["name" =: "jack"] "users") + doc !? "color" `shouldBe` Just "red" + describe "insertMany" $ do it "inserts documents to the collection and returns their _ids" $ do (_id1:_id2:_) <- db $ insertMany "team" [ ["name" =: "Yankees", "league" =: "American"]