diff --git a/src/Database/Bloodhound/Client.hs b/src/Database/Bloodhound/Client.hs index 6f263881..c755b22c 100644 --- a/src/Database/Bloodhound/Client.hs +++ b/src/Database/Bloodhound/Client.hs @@ -57,6 +57,7 @@ module Database.Bloodhound.Client -- ** Searching , searchAll , searchByIndex + , countByIndex , searchByIndices , searchByIndexTemplate , searchByIndicesTemplate @@ -66,6 +67,7 @@ module Database.Bloodhound.Client , advanceScroll , refreshIndex , mkSearch + , mkCount , mkAggregateSearch , mkHighlightSearch , mkSearchTemplate @@ -1050,6 +1052,11 @@ dispatchSearch :: MonadBH m => Text -> Search -> m Reply dispatchSearch url search = post url' (Just (encode search)) where url' = appendSearchTypeParam url (searchType search) +appendCountTypeParam = appendSearchTypeParam +dispatchCount :: MonadBH m => Text -> Count -> m Reply +dispatchCount url count = post url' (Just (encode count)) + where url' = appendCountTypeParam url (countSearchType count) + -- | 'searchAll', given a 'Search', will perform that search against all indexes -- on an Elasticsearch server. Try to avoid doing this if it can be helped. -- @@ -1070,6 +1077,16 @@ searchByIndex :: MonadBH m => IndexName -> Search -> m Reply searchByIndex (IndexName indexName) = bindM2 dispatchSearch url . return where url = joinPath [indexName, "_search"] +-- | 'countByIndex', given a 'Search' and an 'IndexName', will perform that search +-- within an index on an Elasticsearch server. +-- +-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing +-- >>> let search = mkSearch (Just query) Nothing +-- >>> reply <- runBH' $ countByIndex testIndex search +countByIndex :: MonadBH m => IndexName -> Count -> m Reply +countByIndex (IndexName indexName) = bindM2 dispatchCount url . return + where url = joinPath [indexName, "_count"] + -- | 'searchByIndices' is a variant of 'searchByIndex' that executes a -- 'Search' over many indices. This is much faster than using -- 'mapM' to 'searchByIndex' over a collection since it only @@ -1227,6 +1244,17 @@ scanSearch indexName search = do mkSearch :: Maybe Query -> Maybe Filter -> Search mkSearch query filter = Search query filter Nothing Nothing Nothing False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing Nothing Nothing Nothing + +-- | 'mkCount' is a helper function for defaulting additional field of a 'Count' +-- and resemble the similar function for Search endpoint +-- +-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing +-- >>> mkCount (Just query) +-- Count {countQueryBody = Just (TermQuery (Term {termField = "user", termValue = "bitemyapp"}) Nothing), countSearchType = SearchTypeQueryThenFetch} +mkCount :: Maybe Query -> Count +mkCount query = Count query SearchTypeQueryThenFetch + + -- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for -- the 'Query' and the 'Aggregation'. -- diff --git a/src/Database/Bloodhound/Types.hs b/src/Database/Bloodhound/Types.hs index 98c6fc2b..36d16e53 100644 --- a/src/Database/Bloodhound/Types.hs +++ b/src/Database/Bloodhound/Types.hs @@ -105,9 +105,11 @@ module Database.Bloodhound.Types , JoinRelation(..) , IndexDocumentSettings(..) , Query(..) + , Count(..) , Search(..) , SearchType(..) , SearchResult(..) + , CountResult(..) , ScrollId(..) , HitsTotalRelation(..) , HitsTotal(..) @@ -459,7 +461,15 @@ data Search = Search { queryBody :: Maybe Query , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported. } deriving (Eq, Show) +data Count = Count { countQueryBody :: Maybe Query + , countSearchType :: SearchType + } deriving (Eq, Show) + +instance ToJSON Count where + toJSON (Count mquery _) = + omitNulls [ "query" .= mquery] + instance ToJSON Search where toJSON (Search mquery sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sAfter sFields @@ -530,6 +540,18 @@ newtype Pattern = Pattern Text deriving (Eq, Read, Show) instance ToJSON Pattern where toJSON (Pattern pattern) = toJSON pattern +data CountResult a = + CountResult { crCount :: Int + , crShards :: ShardResult + } + deriving (Eq, Show) + +instance (FromJSON a) => FromJSON (CountResult a) where + parseJSON (Object v) = CountResult <$> + v .: "count" <*> + v .: "_shards" + parseJSON _ = empty + data SearchResult a = SearchResult { took :: Int , timedOut :: Bool @@ -657,4 +679,4 @@ instance FromJSON GetTemplateScript where v .: "found" ) script - parseJSON _ = empty \ No newline at end of file + parseJSON _ = empty