git.iko.soy/typeable/bloodhound
on master help sign in
Merge pull request #15 from latkins/master

Add support for lists of queries on must / should / must_not in BoolQuery

commit55783a27be6ad2ca71bcb024650968c37ec38c00 authorChris Allen <cma@bitemyapp.com> dateFri 10 Oct 2014, 12:21 (12 years ago) parenta7d8d4071de653
4 files changed+89−59
Database/Bloodhound/Types.hs+42−39 README.org+1−1 bloodhound.cabal+5−2 tests/tests.hs+41−17
Database/Bloodhound/Types.hs+42−39
@@ -1,4 +1,4 @@
1−{-# LANGUAGE DeriveGeneric #-}
1+{-# LANGUAGE DeriveGeneric #-}
22{-# LANGUAGE RecordWildCards #-}
33
44{-| Data types for describing actions and data structures performed to interact
@@ -22,6 +22,7 @@ module Database.Bloodhound.Types
2222 , mkBoolQuery
2323 , mkRangeQuery
2424 , mkQueryStringQuery
25+ , omitNulls
2526 , Version(..)
2627 , Status(..)
2728 , Existence(..)
@@ -144,20 +145,21 @@ module Database.Bloodhound.Types
144145 , ToJSON(..)
145146 ) where
146147
147−import Control.Applicative
148−import Data.Aeson
149−import qualified Data.ByteString.Lazy.Char8 as L
150−import Data.List (nub)
151−import Data.List.NonEmpty (NonEmpty(..))
152−import Data.Monoid
153−import Data.Text (Text)
154−import qualified Data.Text as T
155−import Data.Time.Clock (UTCTime)
156−import GHC.Generics (Generic)
157−import Network.HTTP.Client
158−import qualified Network.HTTP.Types.Method as NHTM
148+import Control.Applicative
149+import Data.Aeson
150+import qualified Data.ByteString.Lazy.Char8 as L
151+import Data.List (nub)
152+import Data.List.NonEmpty (NonEmpty (..))
153+import Data.Monoid
154+import Data.Text (Text)
155+import qualified Data.Text as T
156+import Data.Time.Clock (UTCTime)
157+import qualified Data.Vector as V
158+import GHC.Generics (Generic)
159+import Network.HTTP.Client
160+import qualified Network.HTTP.Types.Method as NHTM
159161
160−import Database.Bloodhound.Types.Class
162+import Database.Bloodhound.Types.Class
161163
162164
163165{-| 'Version' is embedded in 'Status' -}
@@ -215,8 +217,8 @@ data FieldDefinition =
215217 FieldDefinition { fieldType :: FieldType } deriving (Eq, Show)
216218
217219data MappingField =
218− MappingField { mappingFieldName :: FieldName
219− , fieldDefinition :: FieldDefinition } deriving (Eq, Show)
220+ MappingField { mappingFieldName :: FieldName
221+ , fieldDefinition :: FieldDefinition } deriving (Eq, Show)
220222
221223{-| Support for type reification of 'Mapping's is currently incomplete, for
222224 now the mapping API verbiage expects a 'ToJSON'able blob.
@@ -471,13 +473,13 @@ type TrackSortScores = Bool
471473type From = Int
472474type Size = Int
473475
474−data Search = Search { queryBody :: Maybe Query
475− , filterBody :: Maybe Filter
476− , sortBody :: Maybe Sort
476+data Search = Search { queryBody :: Maybe Query
477+ , filterBody :: Maybe Filter
478+ , sortBody :: Maybe Sort
477479 -- default False
478480 , trackSortScores :: TrackSortScores
479− , from :: From
480− , size :: Size } deriving (Eq, Show)
481+ , from :: From
482+ , size :: Size } deriving (Eq, Show)
481483
482484data Query =
483485 TermQuery Term (Maybe Boost)
@@ -510,10 +512,10 @@ data Query =
510512 deriving (Eq, Show)
511513
512514data RegexpQuery =
513− RegexpQuery { regexpQueryField :: FieldName
514− , regexpQuery :: Regexp
515− , regexpQueryFlags :: RegexpFlags
516− , regexpQueryBoost :: Maybe Boost
515+ RegexpQuery { regexpQueryField :: FieldName
516+ , regexpQuery :: Regexp
517+ , regexpQueryFlags :: RegexpFlags
518+ , regexpQueryBoost :: Maybe Boost
517519 } deriving (Eq, Show)
518520
519521data RangeQuery =
@@ -633,9 +635,9 @@ data MoreLikeThisQuery =
633635data IndicesQuery =
634636 IndicesQuery
635637 { indicesQueryIndices :: [IndexName]
636− , indicesQuery :: Query
638+ , indicesQuery :: Query
637639 -- default "all"
638− , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Show)
640+ , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Show)
639641
640642data HasParentQuery =
641643 HasParentQuery
@@ -752,15 +754,15 @@ data MultiMatchQueryType =
752754 | MultiMatchPhrasePrefix deriving (Eq, Show)
753755
754756data BoolQuery =
755− BoolQuery { boolQueryMustMatch :: Maybe Query
756− , boolQueryMustNotMatch :: Maybe Query
757− , boolQueryShouldMatch :: Maybe [Query]
757+ BoolQuery { boolQueryMustMatch :: [Query]
758+ , boolQueryMustNotMatch :: [Query]
759+ , boolQueryShouldMatch :: [Query]
758760 , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
759761 , boolQueryBoost :: Maybe Boost
760762 , boolQueryDisableCoord :: Maybe DisableCoord
761763 } deriving (Eq, Show)
762764
763−mkBoolQuery :: Maybe Query -> Maybe Query -> Maybe [Query] -> BoolQuery
765+mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
764766mkBoolQuery must mustNot should =
765767 BoolQuery must mustNot should Nothing Nothing Nothing
766768
@@ -787,7 +789,7 @@ data CommonMinimumMatch =
787789 deriving (Eq, Show)
788790
789791data MinimumMatchHighLow =
790− MinimumMatchHighLow { lowFreq :: MinimumMatch
792+ MinimumMatchHighLow { lowFreq :: MinimumMatch
791793 , highFreq :: MinimumMatch } deriving (Eq, Show)
792794
793795data Filter = AndFilter [Filter] Cache
@@ -926,11 +928,11 @@ data FromJSON a => SearchHits a =
926928 , hits :: [Hit a] } deriving (Eq, Show)
927929
928930data FromJSON a => Hit a =
929− Hit { hitIndex :: IndexName
930− , hitType :: MappingName
931− , hitDocId :: DocId
932− , hitScore :: Score
933− , hitSource :: a } deriving (Eq, Show)
931+ Hit { hitIndex :: IndexName
932+ , hitType :: MappingName
933+ , hitDocId :: DocId
934+ , hitScore :: Score
935+ , hitSource :: a } deriving (Eq, Show)
934936
935937data ShardResult =
936938 ShardResult { shardTotal :: Int
@@ -1152,8 +1154,9 @@ instance ToJSON Query where
11521154
11531155omitNulls :: [(Text, Value)] -> Value
11541156omitNulls = object . filter notNull where
1155− notNull (_, Null) = False
1156− notNull _ = True
1157+ notNull (_, Null) = False
1158+ notNull (_, (Array a)) = (not . V.null) a
1159+ notNull _ = True
11571160
11581161
11591162instance ToJSON SimpleQueryStringQuery where
README.org+1−1
@@ -386,7 +386,7 @@ let search = mkSearch (Just query) Nothing
386386let innerQuery = QueryMatchQuery $
387387 mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
388388let query = QueryBoolQuery $
389− mkBoolQuery (Just innerQuery) Nothing Nothing
389+ mkBoolQuery [innerQuery] [] []
390390let search = mkSearch (Just query) Nothing
391391
392392#+END_SRC
bloodhound.cabal+5−2
@@ -31,7 +31,8 @@ library
3131 semigroups >= 0.15,
3232 time >= 1.4,
3333 text >= 0.11,
34− http-types >= 0.8
34+ http-types >= 0.8,
35+ vector >= 0.10.11
3536 default-language: Haskell2010
3637
3738test-suite tests
@@ -49,5 +50,7 @@ test-suite tests
4950 time >= 1.4,
5051 aeson >= 0.7,
5152 semigroups >= 0.15,
52− QuickCheck
53+ QuickCheck,
54+ vector >= 0.10.11,
55+ unordered-containers >=0.2.5.0
5356 default-language: Haskell2010
tests/tests.hs+41−17
@@ -1,24 +1,26 @@
1−{-# LANGUAGE DeriveGeneric #-}
1+{-# LANGUAGE DeriveGeneric #-}
22{-# LANGUAGE ScopedTypeVariables #-}
33
44module Main where
55
6−import Control.Applicative
7−import Database.Bloodhound
8−import Data.Aeson
9−import Data.List (nub)
10−import Data.List.NonEmpty (NonEmpty(..))
11−import Data.Time.Calendar (Day(..))
12−import Data.Time.Clock (secondsToDiffTime, UTCTime(..))
13−import Data.Text (Text)
14−import qualified Data.Text as T
15−import GHC.Generics (Generic)
16−import Network.HTTP.Client
6+import Control.Applicative
7+import Data.Aeson
8+import Data.HashMap.Strict (fromList)
9+import Data.List (nub)
10+import Data.List.NonEmpty (NonEmpty (..))
11+import Data.Text (Text)
12+import qualified Data.Text as T
13+import Data.Time.Calendar (Day (..))
14+import Data.Time.Clock (UTCTime (..), secondsToDiffTime)
15+import qualified Data.Vector as V
16+import Database.Bloodhound
17+import GHC.Generics (Generic)
18+import Network.HTTP.Client
1719import qualified Network.HTTP.Types.Status as NHTS
18−import Prelude hiding (filter, putStrLn)
19−import Test.Hspec
20−import Test.Hspec.QuickCheck (prop)
21−import Test.QuickCheck
20+import Prelude hiding (filter, putStrLn)
21+import Test.Hspec
22+import Test.Hspec.QuickCheck (prop)
23+import Test.QuickCheck
2224
2325testServer :: Server
2426testServer = Server "http://localhost:9200"
@@ -203,7 +205,7 @@ main = hspec $ do
203205 let innerQuery = QueryMatchQuery $
204206 mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
205207 let query = QueryBoolQuery $
206− mkBoolQuery (Just innerQuery) Nothing Nothing
208+ mkBoolQuery [innerQuery] [] []
207209 let search = mkSearch (Just query) Nothing
208210 myTweet <- searchTweet search
209211 myTweet `shouldBe` Right exampleTweet
@@ -382,3 +384,25 @@ main = hspec $ do
382384 let String str = toJSON flags
383385 flagStrs = T.splitOn "|" str
384386 in noDuplicates flagStrs
387+
388+
389+ describe "omitNulls" $ do
390+ it "checks that omitNulls drops list elements when it should" $
391+ let dropped = omitNulls $ [ "test1" .= (toJSON ([] :: [Int]))
392+ , "test2" .= (toJSON ("some value" :: Text))]
393+ in dropped `shouldBe` Object (fromList [("test2", String "some value")])
394+
395+ it "checks that omitNulls doesn't drop list elements when it shouldn't" $
396+ let notDropped = omitNulls $ [ "test1" .= (toJSON ([1] :: [Int]))
397+ , "test2" .= (toJSON ("some value" :: Text))]
398+ in notDropped `shouldBe` Object (fromList [ ("test1", Array (V.fromList [Number 1.0]))
399+ , ("test2", String "some value")])
400+ it "checks that omitNulls drops non list elements when it should" $
401+ let dropped = omitNulls $ [ "test1" .= (toJSON Null)
402+ , "test2" .= (toJSON ("some value" :: Text))]
403+ in dropped `shouldBe` Object (fromList [("test2", String "some value")])
404+ it "checks that omitNulls doesn't drop non list elements when it shouldn't" $
405+ let notDropped = omitNulls $ [ "test1" .= (toJSON (1 :: Int))
406+ , "test2" .= (toJSON ("some value" :: Text))]
407+ in notDropped `shouldBe` Object (fromList [ ("test1", Number 1.0)
408+ , ("test2", String "some value")])