git.iko.soy/typeable/bloodhound
on master help sign in
merged
d9061cdChris Allen
src/Database/Bloodhound/Client.hs+24−22
@@ -173,16 +173,16 @@ joinPath ps = do
173 return $ joinPath' (s:ps)
173 return $ joinPath' (s:ps)
174
174
175appendSearchTypeParam :: Text -> SearchType -> Text
175appendSearchTypeParam :: Text -> SearchType -> Text
176−appendSearchTypeParam originalUrl st = addQuery [(keyEq, Just stParams)] originalUrl
176+appendSearchTypeParam originalUrl st = addQuery params originalUrl
177− where keyEq = "search_type="
177+ where stText = "search_type"
178− stParams
178+ params
179− | st == SearchTypeDfsQueryThenFetch = "dfs_query_then_fetch"
179+ | st == SearchTypeDfsQueryThenFetch = [(stText, Just "dfs_query_then_fetch")]
180− | st == SearchTypeCount = "count"
180+ | st == SearchTypeCount = [(stText, Just "count")]
181− | st == SearchTypeScan = "scan&scroll=1m"
181+ | st == SearchTypeScan = [(stText, Just "scan"), ("scroll", Just "1m")]
182− | st == SearchTypeQueryAndFetch = "query_and_fetch"
182+ | st == SearchTypeQueryAndFetch = [(stText, Just "query_and_fetch")]
183− | st == SearchTypeDfsQueryAndFetch = "dfs_query_and_fetch"
183+ | st == SearchTypeDfsQueryAndFetch = [(stText, Just "dfs_query_and_fetch")]
184 -- used to catch 'SearchTypeQueryThenFetch', which is also the default
184 -- used to catch 'SearchTypeQueryThenFetch', which is also the default
185− | otherwise = "query_then_fetch"
185+ | otherwise = [(stText, Just "query_then_fetch")]
186
186
187-- | Severely dumbed down query renderer. Assumes your data doesn't
187-- | Severely dumbed down query renderer. Assumes your data doesn't
188-- need any encoding
188-- need any encoding
@@ -543,13 +543,13 @@ searchByType (IndexName indexName)
543 (MappingName mappingName) = bindM2 dispatchSearch url . return
543 (MappingName mappingName) = bindM2 dispatchSearch url . return
544 where url = joinPath [indexName, mappingName, "_search"]
544 where url = joinPath [indexName, mappingName, "_search"]
545
545
546−scanSearch' :: MonadBH m => Search -> m (Maybe ScrollId)
546+scanSearch' :: MonadBH m => IndexName -> MappingName -> Search -> m (Maybe ScrollId)
547−scanSearch' search = do
547+scanSearch' (IndexName indexName) (MappingName mappingName) search = do
548− let url = joinPath ["_search"]
548+ let url = joinPath [indexName, mappingName, "_search"]
549 search' = search { searchType = SearchTypeScan }
549 search' = search { searchType = SearchTypeScan }
550 resp' <- bindM2 dispatchSearch url (return search')
550 resp' <- bindM2 dispatchSearch url (return search')
551 let msr = decode' $ responseBody resp' :: Maybe (SearchResult ())
551 let msr = decode' $ responseBody resp' :: Maybe (SearchResult ())
552− msid = maybe Nothing scrollId msr
552+ msid = maybe Nothing scrollId msr
553 return msid
553 return msid
554
554
555scroll' :: (FromJSON a, MonadBH m) => Maybe ScrollId -> m ([Hit a], Maybe ScrollId)
555scroll' :: (FromJSON a, MonadBH m) => Maybe ScrollId -> m ([Hit a], Maybe ScrollId)
@@ -570,9 +570,11 @@ simpleAccumilator oldHits (newHits, msid) = do
570 (newHits', msid') <- scroll' msid
570 (newHits', msid') <- scroll' msid
571 simpleAccumilator (oldHits ++ newHits) (newHits', msid')
571 simpleAccumilator (oldHits ++ newHits) (newHits', msid')
572
572
573+-- | 'scanSearch' uses the 'scan&scroll' API of elastic,
574+-- for a given 'IndexName' and 'MappingName',
573−scanSearch :: (FromJSON a, MonadBH m) => Search -> m [Hit a]
575+scanSearch :: (FromJSON a, MonadBH m) => IndexName -> MappingName -> Search -> m [Hit a]
574−scanSearch search = do
576+scanSearch indexName mappingName search = do
575− msid <- scanSearch' search
577+ msid <- scanSearch' indexName mappingName search
576 (hits, msid') <- scroll' msid
578 (hits, msid') <- scroll' msid
577 (totalHits, _) <- simpleAccumilator [] (hits, msid')
579 (totalHits, _) <- simpleAccumilator [] (hits, msid')
578 return totalHits
580 return totalHits
@@ -584,9 +586,9 @@ scanSearch search = do
584--
586--
585-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
587-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
586-- >>> mkSearch (Just query) Nothing
588-- >>> mkSearch (Just query) Nothing
587−-- Search {queryBody = Just (TermQuery (Term {termField = "user", termValue = "bitemyapp"}) Nothing), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 0, size = Size 10, searchType = SearchTypeQueryThenFetch, fields = Nothing}
589+-- Search {queryBody = Just (TermQuery (Term {termField = "user", termValue = "bitemyapp"}) Nothing), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 0, size = Size 10, searchType = SearchTypeQueryThenFetch, fields = Nothing, source = Nothing}
588mkSearch :: Maybe Query -> Maybe Filter -> Search
590mkSearch :: Maybe Query -> Maybe Filter -> Search
589−mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing
591+mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
590
592
591-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
593-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
592-- the 'Query' and the 'Aggregation'.
594-- the 'Query' and the 'Aggregation'.
@@ -596,7 +598,7 @@ mkSearch query filter = Search query filter Nothing Nothing Nothing False (From
596-- TermsAgg (TermsAggregation {term = Left "user", termInclude = Nothing, termExclude = Nothing, termOrder = Nothing, termMinDocCount = Nothing, termSize = Nothing, termShardSize = Nothing, termCollectMode = Just BreadthFirst, termExecutionHint = Nothing, termAggs = Nothing})
598-- TermsAgg (TermsAggregation {term = Left "user", termInclude = Nothing, termExclude = Nothing, termOrder = Nothing, termMinDocCount = Nothing, termSize = Nothing, termShardSize = Nothing, termCollectMode = Just BreadthFirst, termExecutionHint = Nothing, termAggs = Nothing})
597-- >>> let myAggregation = mkAggregateSearch Nothing $ mkAggregations "users" terms
599-- >>> let myAggregation = mkAggregateSearch Nothing $ mkAggregations "users" terms
598mkAggregateSearch :: Maybe Query -> Aggregations -> Search
600mkAggregateSearch :: Maybe Query -> Aggregations -> Search
599−mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False (From 0) (Size 0) SearchTypeQueryThenFetch Nothing
601+mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False (From 0) (Size 0) SearchTypeQueryThenFetch Nothing Nothing
600
602
601-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
603-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
602-- the 'Query' and the 'Aggregation'.
604-- the 'Query' and the 'Aggregation'.
@@ -605,7 +607,7 @@ mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSear
605-- >>> let testHighlight = Highlights Nothing [FieldHighlight (FieldName "message") Nothing]
607-- >>> let testHighlight = Highlights Nothing [FieldHighlight (FieldName "message") Nothing]
606-- >>> let search = mkHighlightSearch (Just query) testHighlight
608-- >>> let search = mkHighlightSearch (Just query) testHighlight
607mkHighlightSearch :: Maybe Query -> Highlights -> Search
609mkHighlightSearch :: Maybe Query -> Highlights -> Search
608−mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing
610+mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
609
611
610-- | 'pageSearch' is a helper function that takes a search and assigns the from
612-- | 'pageSearch' is a helper function that takes a search and assigns the from
611-- and size fields for the search. The from parameter defines the offset
613-- and size fields for the search. The from parameter defines the offset
@@ -615,9 +617,9 @@ mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing
615-- >>> let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
617-- >>> let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
616-- >>> let search = mkSearch (Just query) Nothing
618-- >>> let search = mkSearch (Just query) Nothing
617-- >>> search
619-- >>> search
618−-- Search {queryBody = Just (QueryMatchQuery (MatchQuery {matchQueryField = FieldName "_all", matchQueryQueryString = QueryString "haskell", matchQueryOperator = Or, matchQueryZeroTerms = ZeroTermsNone, matchQueryCutoffFrequency = Nothing, matchQueryMatchType = Nothing, matchQueryAnalyzer = Nothing, matchQueryMaxExpansions = Nothing, matchQueryLenient = Nothing})), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 0, size = Size 10, searchType = SearchTypeQueryThenFetch, fields = Nothing}
620+-- Search {queryBody = Just (QueryMatchQuery (MatchQuery {matchQueryField = FieldName "_all", matchQueryQueryString = QueryString "haskell", matchQueryOperator = Or, matchQueryZeroTerms = ZeroTermsNone, matchQueryCutoffFrequency = Nothing, matchQueryMatchType = Nothing, matchQueryAnalyzer = Nothing, matchQueryMaxExpansions = Nothing, matchQueryLenient = Nothing, matchQueryBoost = Nothing})), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 0, size = Size 10, searchType = SearchTypeQueryThenFetch, fields = Nothing, source = Nothing}
619-- >>> pageSearch (From 10) (Size 100) search
621-- >>> pageSearch (From 10) (Size 100) search
620−-- Search {queryBody = Just (QueryMatchQuery (MatchQuery {matchQueryField = FieldName "_all", matchQueryQueryString = QueryString "haskell", matchQueryOperator = Or, matchQueryZeroTerms = ZeroTermsNone, matchQueryCutoffFrequency = Nothing, matchQueryMatchType = Nothing, matchQueryAnalyzer = Nothing, matchQueryMaxExpansions = Nothing, matchQueryLenient = Nothing})), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 10, size = Size 100, searchType = SearchTypeQueryThenFetch, fields = Nothing}
622+-- Search {queryBody = Just (QueryMatchQuery (MatchQuery {matchQueryField = FieldName "_all", matchQueryQueryString = QueryString "haskell", matchQueryOperator = Or, matchQueryZeroTerms = ZeroTermsNone, matchQueryCutoffFrequency = Nothing, matchQueryMatchType = Nothing, matchQueryAnalyzer = Nothing, matchQueryMaxExpansions = Nothing, matchQueryLenient = Nothing, matchQueryBoost = Nothing})), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = From 10, size = Size 100, searchType = SearchTypeQueryThenFetch, fields = Nothing, source = Nothing}
621pageSearch :: From -- ^ The result offset
623pageSearch :: From -- ^ The result offset
622 -> Size -- ^ The number of results to return
624 -> Size -- ^ The number of results to return
623 -> Search -- ^ The current seach
625 -> Search -- ^ The current seach
src/Database/Bloodhound/Types.hs+66−20
@@ -47,7 +47,7 @@ module Database.Bloodhound.Types
47 , toTerms
47 , toTerms
48 , toDateHistogram
48 , toDateHistogram
49 , omitNulls
49 , omitNulls
50− , BH
50+ , BH(..)
51 , runBH
51 , runBH
52 , BHEnv(..)
52 , BHEnv(..)
53 , MonadBH(..)
53 , MonadBH(..)
@@ -75,6 +75,11 @@ module Database.Bloodhound.Types
75 , TrackSortScores
75 , TrackSortScores
76 , From(..)
76 , From(..)
77 , Size(..)
77 , Size(..)
78+ , Source(..)
79+ , PatternOrPatterns(..)
80+ , Include(..)
81+ , Exclude(..)
82+ , Pattern(..)
78 , ShardResult(..)
83 , ShardResult(..)
79 , Hit(..)
84 , Hit(..)
80 , Filter(..)
85 , Filter(..)
@@ -225,6 +230,7 @@ module Database.Bloodhound.Types
225 ) where
230 ) where
226
231
227import Control.Applicative
232import Control.Applicative
233+import Control.Monad.Catch
228import Control.Monad.Error
234import Control.Monad.Error
229import Control.Monad.Reader
235import Control.Monad.Reader
230import Control.Monad.State
236import Control.Monad.State
@@ -232,9 +238,9 @@ import Control.Monad.Writer
232import Data.Aeson
238import Data.Aeson
233import Data.Aeson.Types (Pair, emptyObject, parseMaybe)
239import Data.Aeson.Types (Pair, emptyObject, parseMaybe)
234import qualified Data.ByteString.Lazy.Char8 as L
240import qualified Data.ByteString.Lazy.Char8 as L
235−import Data.List (nub, foldl')
236−import Data.List.NonEmpty (NonEmpty (..), toList)
237import qualified Data.HashMap.Strict as HM (union)
241import qualified Data.HashMap.Strict as HM (union)
242+import Data.List (foldl', nub)
243+import Data.List.NonEmpty (NonEmpty (..), toList)
238import qualified Data.Map.Strict as M
244import qualified Data.Map.Strict as M
239import Data.Maybe
245import Data.Maybe
240import Data.Text (Text)
246import Data.Text (Text)
@@ -285,7 +291,10 @@ newtype BH m a = BH {
285 , MonadError e
291 , MonadError e
286 , Alternative
292 , Alternative
287 , MonadPlus
293 , MonadPlus
288− , MonadFix)
294+ , MonadFix
295+ , MonadThrow
296+ , MonadCatch
297+ , MonadMask)
289
298
290instance MonadTrans BH where
299instance MonadTrans BH where
291 lift = BH . lift
300 lift = BH . lift
@@ -368,7 +377,7 @@ data FieldDefinition =
368 https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
377 https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
369-}
378-}
370data IndexTemplate =
379data IndexTemplate =
371− IndexTemplate { templatePattern :: TemplatePattern
380+ IndexTemplate { templatePattern :: TemplatePattern
372 , templateSettings :: Maybe IndexSettings
381 , templateSettings :: Maybe IndexSettings
373 , templateMappings :: [Value]
382 , templateMappings :: [Value]
374 }
383 }
@@ -402,9 +411,9 @@ data BulkOperation =
402{-| 'EsResult' describes the standard wrapper JSON document that you see in
411{-| 'EsResult' describes the standard wrapper JSON document that you see in
403 successful Elasticsearch lookups or lookups that couldn't find the document.
412 successful Elasticsearch lookups or lookups that couldn't find the document.
404-}
413-}
405−data EsResult a = EsResult { _index :: Text
414+data EsResult a = EsResult { _index :: Text
406− , _type :: Text
415+ , _type :: Text
407− , _id :: Text
416+ , _id :: Text
408 , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Show)
417 , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Show)
409
418
410
419
@@ -412,7 +421,7 @@ data EsResult a = EsResult { _index :: Text
412 'EsResult' when the document was successfully found.
421 'EsResult' when the document was successfully found.
413-}
422-}
414data EsResultFound a = EsResultFound { _version :: DocVersion
423data EsResultFound a = EsResultFound { _version :: DocVersion
415− , _source :: a } deriving (Eq, Show)
424+ , _source :: a } deriving (Eq, Show)
416
425
417
426
418
427
@@ -733,11 +742,12 @@ data Search = Search { queryBody :: Maybe Query
733 -- default False
742 -- default False
734 , trackSortScores :: TrackSortScores
743 , trackSortScores :: TrackSortScores
735 , from :: From
744 , from :: From
736− , size :: Size
745+ , size :: Size
737 , searchType :: SearchType
746 , searchType :: SearchType
738− , fields :: Maybe [FieldName] } deriving (Eq, Show)
747+ , fields :: Maybe [FieldName]
748+ , source :: Maybe Source } deriving (Eq, Show)
739
749
740−data SearchType = SearchTypeQueryThenFetch
750+data SearchType = SearchTypeQueryThenFetch
741 | SearchTypeDfsQueryThenFetch
751 | SearchTypeDfsQueryThenFetch
742 | SearchTypeCount
752 | SearchTypeCount
743 | SearchTypeScan
753 | SearchTypeScan
@@ -745,6 +755,20 @@ data SearchType = SearchTypeQueryThenFetch
745 | SearchTypeDfsQueryAndFetch
755 | SearchTypeDfsQueryAndFetch
746 deriving (Eq, Show)
756 deriving (Eq, Show)
747
757
758+data Source =
759+ NoSource
760+ | SourcePatterns PatternOrPatterns
761+ | SourceIncludeExclude Include Exclude
762+ deriving (Show, Eq)
763+
764+data PatternOrPatterns = PopPattern Pattern
765+ | PopPatterns [Pattern] deriving (Eq, Show)
766+
767+data Include = Include [Pattern] deriving (Eq, Show)
768+data Exclude = Exclude [Pattern] deriving (Eq, Show)
769+
770+newtype Pattern = Pattern Text deriving (Eq, Show)
771+
748data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
772data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
749 , highlightFields :: [FieldHighlight]
773 , highlightFields :: [FieldHighlight]
750 } deriving (Show, Eq)
774 } deriving (Show, Eq)
@@ -1031,13 +1055,14 @@ data MatchQuery =
1031 , matchQueryMatchType :: Maybe MatchQueryType
1055 , matchQueryMatchType :: Maybe MatchQueryType
1032 , matchQueryAnalyzer :: Maybe Analyzer
1056 , matchQueryAnalyzer :: Maybe Analyzer
1033 , matchQueryMaxExpansions :: Maybe MaxExpansions
1057 , matchQueryMaxExpansions :: Maybe MaxExpansions
1034− , matchQueryLenient :: Maybe Lenient } deriving (Eq, Show)
1058+ , matchQueryLenient :: Maybe Lenient
1059+ , matchQueryBoost :: Maybe Boost } deriving (Eq, Show)
1035
1060
1036{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
1061{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
1037 enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
1062 enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
1038-}
1063-}
1039mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1064mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1040−mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing
1065+mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1041
1066
1042data MatchQueryType =
1067data MatchQueryType =
1043 MatchPhrase
1068 MatchPhrase
@@ -1256,7 +1281,7 @@ data SearchResult a =
1256 , timedOut :: Bool
1281 , timedOut :: Bool
1257 , shards :: ShardResult
1282 , shards :: ShardResult
1258 , searchHits :: SearchHits a
1283 , searchHits :: SearchHits a
1259− , aggregations :: Maybe AggregationResults
1284+ , aggregations :: Maybe AggregationResults
1260 , scrollId :: Maybe ScrollId } deriving (Eq, Show)
1285 , scrollId :: Maybe ScrollId } deriving (Eq, Show)
1261
1286
1262type ScrollId = Text -- Fixme: Newtype
1287type ScrollId = Text -- Fixme: Newtype
@@ -1367,7 +1392,7 @@ data ValueCountAggregation = FieldValueCount FieldName
1367
1392
1368-- | Single-bucket filter aggregations. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html#search-aggregations-bucket-filter-aggregation> for more information.
1393-- | Single-bucket filter aggregations. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html#search-aggregations-bucket-filter-aggregation> for more information.
1369data FilterAggregation = FilterAggregation { faFilter :: Filter
1394data FilterAggregation = FilterAggregation { faFilter :: Filter
1370− , faAggs :: Maybe Aggregations} deriving (Eq, Show)
1395+ , faAggs :: Maybe Aggregations} deriving (Eq, Show)
1371
1396
1372mkTermsAggregation :: Text -> TermsAggregation
1397mkTermsAggregation :: Text -> TermsAggregation
1373mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1398mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
@@ -1967,7 +1992,7 @@ instance ToJSON MatchQuery where
1967 toJSON (MatchQuery (FieldName fieldName)
1992 toJSON (MatchQuery (FieldName fieldName)
1968 (QueryString mqQueryString) booleanOperator
1993 (QueryString mqQueryString) booleanOperator
1969 zeroTermsQuery cutoffFrequency matchQueryType
1994 zeroTermsQuery cutoffFrequency matchQueryType
1970− analyzer maxExpansions lenient) =
1995+ analyzer maxExpansions lenient boost) =
1971 object [ fieldName .= omitNulls base ]
1996 object [ fieldName .= omitNulls base ]
1972 where base = [ "query" .= mqQueryString
1997 where base = [ "query" .= mqQueryString
1973 , "operator" .= booleanOperator
1998 , "operator" .= booleanOperator
@@ -1976,7 +2001,8 @@ instance ToJSON MatchQuery where
1976 , "type" .= matchQueryType
2001 , "type" .= matchQueryType
1977 , "analyzer" .= analyzer
2002 , "analyzer" .= analyzer
1978 , "max_expansions" .= maxExpansions
2003 , "max_expansions" .= maxExpansions
1979− , "lenient" .= lenient ]
2004+ , "lenient" .= lenient
2005+ , "boost" .= boost ]
1980
2006
1981
2007
1982instance ToJSON MultiMatchQuery where
2008instance ToJSON MultiMatchQuery where
@@ -2108,7 +2134,7 @@ instance (FromJSON a) => FromJSON (EsResultFound a) where
2108 parseJSON _ = empty
2134 parseJSON _ = empty
2109
2135
2110instance ToJSON Search where
2136instance ToJSON Search where
2111− toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields) =
2137+ toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
2112 omitNulls [ "query" .= query
2138 omitNulls [ "query" .= query
2113 , "filter" .= sFilter
2139 , "filter" .= sFilter
2114 , "sort" .= sort
2140 , "sort" .= sort
@@ -2117,7 +2143,27 @@ instance ToJSON Search where
2117 , "from" .= sFrom
2143 , "from" .= sFrom
2118 , "size" .= sSize
2144 , "size" .= sSize
2119 , "track_scores" .= sTrackSortScores
2145 , "track_scores" .= sTrackSortScores
2120− , "fields" .= sFields]
2146+ , "fields" .= sFields
2147+ , "_source" .= sSource]
2148+
2149+
2150+instance ToJSON Source where
2151+ toJSON NoSource = toJSON False
2152+ toJSON (SourcePatterns patterns) = toJSON patterns
2153+ toJSON (SourceIncludeExclude incl excl) = object [ "include" .= incl, "exclude" .= excl ]
2154+
2155+instance ToJSON PatternOrPatterns where
2156+ toJSON (PopPattern pattern) = toJSON pattern
2157+ toJSON (PopPatterns patterns) = toJSON patterns
2158+
2159+instance ToJSON Include where
2160+ toJSON (Include patterns) = toJSON patterns
2161+
2162+instance ToJSON Exclude where
2163+ toJSON (Exclude patterns) = toJSON patterns
2164+
2165+instance ToJSON Pattern where
2166+ toJSON (Pattern pattern) = toJSON pattern
2121
2167
2122
2168
2123instance ToJSON FieldHighlight where
2169instance ToJSON FieldHighlight where
tests/tests.hs+50−1
@@ -220,6 +220,17 @@ searchTweetHighlight search = do
220 let myHighlight = fmap (hitHighlight . head . hits . searchHits) result
220 let myHighlight = fmap (hitHighlight . head . hits . searchHits) result
221 return myHighlight
221 return myHighlight
222
222
223+searchExpectSource :: Source -> Either String Value -> BH IO ()
224+searchExpectSource src expected = do
225+ _ <- insertData
226+ let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
227+ let search = (mkSearch (Just query) Nothing) { source = Just src }
228+ reply <- searchAll search
229+ let result = eitherDecode (responseBody reply) :: Either String (SearchResult Value)
230+ let value = fmap (hitSource . head . hits . searchHits) result
231+ liftIO $
232+ value `shouldBe` expected
233+
223data BulkTest = BulkTest { name :: Text } deriving (Eq, Generic, Show)
234data BulkTest = BulkTest { name :: Text } deriving (Eq, Generic, Show)
224instance FromJSON BulkTest
235instance FromJSON BulkTest
225instance ToJSON BulkTest
236instance ToJSON BulkTest
@@ -435,7 +446,7 @@ main = hspec $ do
435 let sortSpec = DefaultSortSpec $ mkSort (FieldName "age") Ascending
446 let sortSpec = DefaultSortSpec $ mkSort (FieldName "age") Ascending
436 let search = Search Nothing
447 let search = Search Nothing
437 (Just IdentityFilter) (Just [sortSpec]) Nothing Nothing
448 (Just IdentityFilter) (Just [sortSpec]) Nothing Nothing
438− False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing
449+ False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
439 result <- searchTweets search
450 result <- searchTweets search
440 let myTweet = fmap (hitSource . head . hits . searchHits) result
451 let myTweet = fmap (hitSource . head . hits . searchHits) result
441 liftIO $
452 liftIO $
@@ -698,7 +709,32 @@ main = hspec $ do
698 liftIO $
709 liftIO $
699 myHighlight `shouldBe` Right Nothing
710 myHighlight `shouldBe` Right Nothing
700
711
712+ describe "Source filtering" $ do
713+
714+ it "doesn't include source when sources are disabled" $ withTestEnv $ do
715+ searchExpectSource
716+ NoSource
717+ (Left "key \"_source\" not present")
718+
719+ it "includes a source" $ withTestEnv $ do
720+ searchExpectSource
721+ (SourcePatterns (PopPattern (Pattern "message")))
722+ (Right (Object (HM.fromList [("message", String "Use haskell!")])))
723+
724+ it "includes sources" $ withTestEnv $ do
725+ searchExpectSource
726+ (SourcePatterns (PopPatterns [Pattern "user", Pattern "message"]))
727+ (Right (Object (HM.fromList [("user",String "bitemyapp"),("message", String "Use haskell!")])))
701
728
729+ it "includes source patterns" $ withTestEnv $ do
730+ searchExpectSource
731+ (SourcePatterns (PopPattern (Pattern "*ge")))
732+ (Right (Object (HM.fromList [("age", Number 10000),("message", String "Use haskell!")])))
733+
734+ it "excludes source patterns" $ withTestEnv $ do
735+ searchExpectSource
736+ (SourceIncludeExclude (Include []) (Exclude [Pattern "l*", Pattern "*ge", Pattern "postDate"]))
737+ (Right (Object (HM.fromList [("user",String "bitemyapp")])))
702
738
703 describe "ToJSON RegexpFlags" $ do
739 describe "ToJSON RegexpFlags" $ do
704 it "generates the correct JSON for AllRegexpFlags" $
740 it "generates the correct JSON for AllRegexpFlags" $
@@ -762,3 +798,16 @@ main = hspec $ do
762 enumFrom (pred maxBound :: DocVersion) `shouldBe` [pred maxBound, maxBound]
798 enumFrom (pred maxBound :: DocVersion) `shouldBe` [pred maxBound, maxBound]
763 enumFrom (pred maxBound :: DocVersion) `shouldBe` [pred maxBound, maxBound]
799 enumFrom (pred maxBound :: DocVersion) `shouldBe` [pred maxBound, maxBound]
764 enumFromThen minBound (pred maxBound :: DocVersion) `shouldBe` [minBound, pred maxBound]
800 enumFromThen minBound (pred maxBound :: DocVersion) `shouldBe` [minBound, pred maxBound]
801+
802+ describe "scan&scroll API" $ do
803+ it "returns documents using the scan&scroll API" $ withTestEnv $ do
804+ _ <- insertData
805+ _ <- insertOther
806+ let search = (mkSearch (Just $ MatchAllQuery Nothing) Nothing) { size = (Size 1) }
807+ regular_search <- searchTweet search
808+ scan_search' <- scanSearch testIndex testMapping search :: BH IO [Hit Tweet]
809+ let scan_search = map hitSource scan_search'
810+ liftIO $
811+ regular_search `shouldBe` Right exampleTweet -- Check that the size restrtiction is being honored
812+ liftIO $
813+ scan_search `shouldMatchList` [exampleTweet, otherTweet]