packages feed

bloodhound-1.0.0.0: tests/Test/MultiGetSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Test.MultiGetSpec where

import Data.List (isInfixOf)
import TestsUtils.Common
import TestsUtils.Import

spec :: Spec
spec =
  describe "multi-get API" $ do
    it "fetches multiple documents by ID" $
      withTestEnv $ do
        _ <- insertData
        _ <- insertOther
        result <- tryPerformBHRequest $ getDocuments @Tweet testIndex [DocId "1", DocId "2"]
        case result of
          Left _ -> liftIO $ expectationFailure "Multi-get failed"
          Right resp -> do
            let docs = multiGetResponseDocs resp
            liftIO $ length docs `shouldBe` 2

    it "returns found status for existing documents" $
      withTestEnv $ do
        _ <- insertData
        result <- tryPerformBHRequest $ getDocuments @Tweet testIndex [DocId "1"]
        case result of
          Left _ -> liftIO $ expectationFailure "Multi-get failed"
          Right resp -> do
            let docs = multiGetResponseDocs resp
            liftIO $ length docs `shouldBe` 1
            let firstDoc = head docs
            liftIO $ foundResult firstDoc `shouldSatisfy` isJust

    it "returns not found for missing documents" $
      withTestEnv $ do
        _ <- insertData
        result <- tryPerformBHRequest $ getDocuments @Tweet testIndex [DocId "nonexistent"]
        case result of
          Left _ -> liftIO $ expectationFailure "Multi-get failed"
          Right resp -> do
            let docs = multiGetResponseDocs resp
            liftIO $ length docs `shouldBe` 1
            let firstDoc = head docs
            liftIO $ foundResult firstDoc `shouldBe` Nothing

    it "handles mixed found and not found documents" $
      withTestEnv $ do
        _ <- insertData
        result <- tryPerformBHRequest $ getDocuments @Tweet testIndex [DocId "1", DocId "nonexistent"]
        case result of
          Left _ -> liftIO $ expectationFailure "Multi-get failed"
          Right resp -> do
            let docs = multiGetResponseDocs resp
            liftIO $ length docs `shouldBe` 2
            let [firstDoc, secondDoc] = docs
            liftIO $ foundResult firstDoc `shouldSatisfy` isJust
            liftIO $ foundResult secondDoc `shouldBe` Nothing

    describe "per-document source filtering (MultiGetDoc body)" $ do
      it "multiGetDocSource=NoSource omits the source for that document only" $
        withTestEnv $ do
          _ <- insertData
          _ <- insertOther
          -- POST /_mget requires _index per-doc since no index is in the URL.
          let doc1 =
                (mkMultiGetDoc (DocId "1"))
                  { multiGetDocSource = Just NoSource,
                    multiGetDocIndex = Just testIndex
                  }
              doc2 = (mkMultiGetDoc (DocId "2")) {multiGetDocIndex = Just testIndex}
              body = MultiGet [doc1, doc2]
          result <- tryPerformBHRequest $ getDocumentsMulti @Tweet body
          case result of
            Left _ -> liftIO $ expectationFailure "Multi-get failed"
            Right resp -> do
              let [firstDoc, secondDoc] = multiGetResponseDocs resp
              -- First doc: _source=false per-doc → source absent → foundResult Nothing
              -- Second doc: normal → source present
              liftIO $ getSource firstDoc `shouldBe` Nothing
              liftIO $ getSource secondDoc `shouldBe` Just otherTweet

      it "getDocumentsMultiWith applies MultiGetOptions at URI level" $
        withTestEnv $ do
          _ <- insertData
          _ <- insertOther
          let opts = defaultMultiGetOptions {mgoSource = Just False}
              doc i = (mkMultiGetDoc (DocId i)) {multiGetDocIndex = Just testIndex}
              body = MultiGet (map doc ["1", "2"])
          result <- tryPerformBHRequest $ getDocumentsMultiWith @Tweet opts body
          case result of
            Left _ -> liftIO $ expectationFailure "Multi-get failed"
            Right resp -> do
              let docs = multiGetResponseDocs resp
              liftIO $ length docs `shouldBe` 2
              -- With _source=false at the URI level, no document should
              -- carry a source.
              liftIO $ all (isNothing . getSource) docs `shouldBe` True

      it "getDocumentsWith applies MultiGetOptions at URI level" $
        withTestEnv $ do
          _ <- insertData
          _ <- insertOther
          let opts = defaultMultiGetOptions {mgoSourceIncludes = Just "user"}
          -- Parse as Value so we can inspect the partial source without
          -- requiring every Tweet field to be present.
          result <- tryPerformBHRequest $ getDocumentsWith @Value opts testIndex [DocId "1", DocId "2"]
          case result of
            Left _ -> liftIO $ expectationFailure "Multi-get failed"
            Right resp -> do
              let docs = multiGetResponseDocs resp
              liftIO $ length docs `shouldBe` 2
              let firstAsValue = getSource (head docs)
              liftIO $ firstAsValue `shouldSatisfy` isJust
              -- With _source_includes=user, the re-encoded source should
              -- contain exactly the "user" field and nothing else.
              case firstAsValue of
                Just v -> do
                  let s = show v
                  liftIO $ s `shouldSatisfy` isInfixOf "\"user\""
                  liftIO $ s `shouldSatisfy` not . isInfixOf "\"age\""
                Nothing ->
                  liftIO $ expectationFailure "expected a source"