bloodhound-1.0.0.0: tests/Test/QuerySpec.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.QuerySpec where
import Data.Aeson.KeyMap qualified as X
import TestsUtils.Common
import TestsUtils.Import
spec :: Spec
spec =
describe "query API" $ do
it "returns document for term query and identity filter" $
withTestEnv $ do
_ <- insertData
let query = TermQuery (Term "user" "bitemyapp") Nothing
let filter' = Filter $ MatchAllQuery Nothing
let search = mkSearch (Just query) (Just filter')
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "handles constant score queries" $
withTestEnv $ do
_ <- insertData
let query = TermsQuery "user" ("bitemyapp" :| [])
let cfQuery = ConstantScoreQuery query (Boost 1.0)
let filter' = Filter $ MatchAllQuery Nothing
let search = mkSearch (Just cfQuery) (Just filter')
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for terms query and identity filter" $
withTestEnv $ do
_ <- insertData
let query = TermsQuery "user" ("bitemyapp" :| [])
let filter' = Filter $ MatchAllQuery Nothing
let search = mkSearch (Just query) (Just filter')
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for match query" $
withTestEnv $ do
_ <- insertData
let query = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for match query with fuzziness" $
withTestEnv $ do
_ <- insertData
let match = mkMatchQuery (FieldName "user") (QueryString "bidemyapp")
let query = QueryMatchQuery $ match {matchQueryFuzziness = Just FuzzinessAuto}
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for multi-match query" $
withTestEnv $ do
_ <- insertData
let flds = [FieldName "user", FieldName "message"]
let query = QueryMultiMatchQuery $ mkMultiMatchQuery flds (QueryString "bitemyapp")
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for multi-match query with a custom tiebreaker" $
withTestEnv $ do
_ <- insertData
let tiebreaker = Just $ Tiebreaker 0.3
flds = [FieldName "user", FieldName "message"]
multiQuery' = mkMultiMatchQuery flds (QueryString "bitemyapp")
query = QueryMultiMatchQuery $ multiQuery' {multiMatchQueryTiebreaker = tiebreaker}
search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for bool query" $
withTestEnv $ do
_ <- insertData
let innerQuery =
QueryMatchQuery $
mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
let query =
QueryBoolQuery $
mkBoolQuery [innerQuery] [] [] []
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for boosting query" $
withTestEnv $ do
_ <- insertData
let posQuery = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
let negQuery = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "notmyapp")
let query = QueryBoostingQuery $ BoostingQuery posQuery negQuery (Boost 0.2)
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
-- The @common@ terms query was deprecated in ES 6.1 and removed in
-- ES 8.0 (OpenSearch, which forked from ES 7.10, still supports it).
-- Gate the live round-trip to backends whose major version is below 8.
esCommonIt <- runIO (withMajorVersionIT (< 8))
esCommonIt "returns document for common terms query" $
withTestEnv $ do
_ <- insertData
let query =
QueryCommonTermsQuery $
CommonTermsQuery
(FieldName "user")
(QueryString "bitemyapp")
(Just (CutoffFrequency 0.0001))
(Just Or)
(Just Or)
Nothing
Nothing
Nothing
Nothing
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet
it "returns document for template query" $
withTestEnv $ do
_ <- insertData
let query = SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"
templateParams =
TemplateQueryKeyValuePairs $
X.fromList
[ ("my_field", "user"),
("my_value", "bitemyapp")
]
search = mkSearchTemplate (Right query) templateParams
response <- performBHRequest $ searchByIndexTemplate testIndex search
let myTweet = grabFirst response
liftIO $ myTweet `shouldBe` Right exampleTweet
it "can save, use, read and delete template queries" $
withTestEnv $ do
_ <- insertData
let query = SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"
templateParams =
TemplateQueryKeyValuePairs $
X.fromList
[ ("my_field", "user"),
("my_value", "bitemyapp")
]
tid = SearchTemplateId "myTemplate"
search = mkSearchTemplate (Left tid) templateParams
_ <- performBHRequest $ storeSearchTemplate tid query
t1 <- performBHRequest $ getSearchTemplate tid
liftIO $ t1 `shouldBe` GetTemplateScript {getTemplateScriptLang = Just "mustache", getTemplateScriptSource = Just (SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"), getTemplateScriptOptions = Nothing, getTemplateScriptId = "myTemplate", getTemplateScriptFound = True}
response <- performBHRequest $ searchByIndexTemplate testIndex search
_ <- performBHRequest $ deleteSearchTemplate tid
t2 <- performBHRequest $ getSearchTemplate tid
let myTweet = grabFirst response
liftIO $ do
t2 `shouldBe` GetTemplateScript {getTemplateScriptLang = Nothing, getTemplateScriptSource = Nothing, getTemplateScriptOptions = Nothing, getTemplateScriptId = "myTemplate", getTemplateScriptFound = False}
myTweet `shouldBe` Right exampleTweet
it "renderTemplate renders an inline template's mustache substitutions without executing it" $
withTestEnv $ do
-- renderTemplate renders the body server-side without executing
-- a search, so no document needs to be indexed for this test.
let query = SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"
templateParams =
TemplateQueryKeyValuePairs $
X.fromList
[ ("my_field", "user"),
("my_value", "bitemyapp")
]
search = mkSearchTemplate (Right query) templateParams
rendered <- performBHRequest $ renderTemplate search
liftIO $ case rendered of
Left err ->
expectationFailure ("renderTemplate failed: " <> show err)
Right body -> do
-- The response wraps the resolved query under
-- @template_output@. Both the key (@{{my_field}}@) and the
-- value (@{{my_value}}@) must be substituted by mustache.
let expectedOutput =
object
[ "query"
.= object ["match" .= object ["user" .= String "bitemyapp"]]
]
case body of
Object top -> X.lookup "template_output" top `shouldBe` Just expectedOutput
_ -> expectationFailure "expected a JSON object body"
it "renderTemplate renders a stored template by id without executing it" $
withTestEnv $ do
-- renderTemplate renders the body server-side without executing
-- a search, so no document needs to be indexed for this test.
let query = SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"
tid = SearchTemplateId "bh-render-template-spec"
templateParams =
TemplateQueryKeyValuePairs $
X.fromList
[ ("my_field", "user"),
("my_value", "bitemyapp")
]
search = mkSearchTemplate (Left tid) templateParams
_ <- performBHRequest $ storeSearchTemplate tid query
rendered <- performBHRequest $ renderTemplate search
_ <- performBHRequest $ deleteSearchTemplate tid
liftIO $ case rendered of
Left err ->
expectationFailure ("renderTemplate by id failed: " <> show err)
Right body -> do
let expectedOutput =
object
[ "query"
.= object ["match" .= object ["user" .= String "bitemyapp"]]
]
case body of
Object top -> X.lookup "template_output" top `shouldBe` Just expectedOutput
_ -> expectationFailure "expected a JSON object body"
it "returns document for wildcard query" $
withTestEnv $ do
_ <- insertData
let query = QueryWildcardQuery $ WildcardQuery (FieldName "user") (Just "bitemy*") Nothing Nothing Nothing Nothing
let search = mkSearch (Just query) Nothing
myTweet <- searchTweet search
liftIO $
myTweet `shouldBe` Right exampleTweet