@@ -108,12 +108,22 @@ import Database.Bloodhound.Types
108--instance ToJSON BulkTest
108--instance ToJSON BulkTest
111+-- | 'mkShardCount' is a straight-forward smart constructor for 'ShardCount'
112+-- which rejects 'Int' values below 1 and above 1000.
114+-- >>> mkShardCount 10
115+-- Just (ShardCount 10)
111mkShardCount :: Int -> Maybe ShardCount
116mkShardCount :: Int -> Maybe ShardCount
112mkShardCount n
117mkShardCount n
113 | n < 1 = Nothing
118 | n < 1 = Nothing
114 | n > 1000 = Nothing
119 | n > 1000 = Nothing
115 | otherwise = Just (ShardCount n)
120 | otherwise = Just (ShardCount n)
122+-- | 'mkReplicaCount' is a straight-forward smart constructor for 'ReplicaCount'
123+-- which rejects 'Int' values below 1 and above 1000.
125+-- >>> mkReplicaCount 10
126+-- Just (ReplicaCount 10)
117mkReplicaCount :: Int -> Maybe ReplicaCount
127mkReplicaCount :: Int -> Maybe ReplicaCount
118mkReplicaCount n
128mkReplicaCount n
119 | n < 1 = Nothing
129 | n < 1 = Nothing
@@ -152,14 +162,17 @@ post = dispatch NHTM.methodPost
152-- http://hackage.haskell.org/package/http-client-lens-0.1.0/docs/Network-HTTP-Client-Lens.html
162-- http://hackage.haskell.org/package/http-client-lens-0.1.0/docs/Network-HTTP-Client-Lens.html
153-- https://github.com/supki/libjenkins/blob/master/src/Jenkins/Rest/Internal.hs
163-- https://github.com/supki/libjenkins/blob/master/src/Jenkins/Rest/Internal.hs
165+-- | 'getStatus' fetches the 'Status' of a 'Server'
167+-- >>> getStatus testServer
168+-- Just (Status {ok = Nothing, status = 200, name = "Arena", version = Version {number = "1.4.1", build_hash = "89d3241d670db65f994242c8e8383b169779e2d4", build_timestamp = 2014-11-26 15:49:29 UTC, build_snapshot = False, lucene_version = "4.10.2"}, tagline = "You Know, for Search"})
155getStatus :: Server -> IO (Maybe Status)
169getStatus :: Server -> IO (Maybe Status)
156getStatus (Server server) = do
170getStatus (Server server) = do
157 request <- parseUrl $ joinPath [server]
171 request <- parseUrl $ joinPath [server]
158 response <- withManager defaultManagerSettings $ httpLbs request
172 response <- withManager defaultManagerSettings $ httpLbs request
159 return $ decode (responseBody response)
173 return $ decode (responseBody response)
161−-- | createIndex will create an index given a 'Server',
175+-- | 'createIndex' will create an index given a 'Server', 'IndexSettings', and an 'IndexName'.
162−-- 'IndexSettings', and an 'IndexName'
164-- >>> response <- createIndex testServer defaultIndexSettings (IndexName "didimakeanindex")
177-- >>> response <- createIndex testServer defaultIndexSettings (IndexName "didimakeanindex")
165-- >>> respIsTwoHunna response
178-- >>> respIsTwoHunna response
@@ -172,8 +185,7 @@ createIndex (Server server) indexSettings (IndexName indexName) =
172 where url = joinPath [server, indexName]
185 where url = joinPath [server, indexName]
173 body = Just $ encode indexSettings
186 body = Just $ encode indexSettings
175−-- | deleteIndex will delete an index given a 'Server',
188+-- | 'deleteIndex' will delete an index given a 'Server', and an 'IndexName'.
176−-- and an 'IndexName'
178-- >>> response <- createIndex testServer defaultIndexSettings (IndexName "didimakeanindex")
190-- >>> response <- createIndex testServer defaultIndexSettings (IndexName "didimakeanindex")
179-- >>> response <- deleteIndex testServer (IndexName "didimakeanindex")
191-- >>> response <- deleteIndex testServer (IndexName "didimakeanindex")
@@ -196,6 +208,10 @@ existentialQuery url = do
196 reply <- head url
208 reply <- head url
197 return (reply, respIsTwoHunna reply)
209 return (reply, respIsTwoHunna reply)
211+-- | 'indexExists' enables you to check if an index exists. Returns 'Bool'
214+-- >>> exists <- indexExists testServer testIndex
199indexExists :: Server -> IndexName -> IO Bool
215indexExists :: Server -> IndexName -> IO Bool
200indexExists (Server server) (IndexName indexName) = do
216indexExists (Server server) (IndexName indexName) = do
201 (_, exists) <- existentialQuery url
217 (_, exists) <- existentialQuery url
@@ -223,9 +239,17 @@ openOrCloseIndexes oci (Server server) (IndexName indexName) =
223 where ociString = stringifyOCIndex oci
239 where ociString = stringifyOCIndex oci
224 url = joinPath [server, indexName, ociString]
240 url = joinPath [server, indexName, ociString]
242+-- | 'openIndex' opens an index given a 'Server' and an 'IndexName'. Explained in further detail at
243+-- http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html
245+-- >>> reply <- openIndex testServer testIndex
226openIndex :: Server -> IndexName -> IO Reply
246openIndex :: Server -> IndexName -> IO Reply
227openIndex = openOrCloseIndexes OpenIndex
247openIndex = openOrCloseIndexes OpenIndex
249+-- | 'closeIndex' closes an index given a 'Server' and an 'IndexName'. Explained in further detail at
250+-- http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html
252+-- >>> reply <- closeIndex testServer testIndex
229closeIndex :: Server -> IndexName -> IO Reply
253closeIndex :: Server -> IndexName -> IO Reply
230closeIndex = openOrCloseIndexes CloseIndex
254closeIndex = openOrCloseIndexes CloseIndex
@@ -361,6 +385,10 @@ getDocument (Server server) (IndexName indexName)
361 (MappingName mappingName) (DocId docId) =
385 (MappingName mappingName) (DocId docId) =
362 get $ joinPath [server, indexName, mappingName, docId]
386 get $ joinPath [server, indexName, mappingName, docId]
388+-- | 'documentExists' enables you to check if a document exists. Returns 'Bool'
391+-- >>> exists <- documentExists testServer testIndex testMapping (DocId "1")
364documentExists :: Server -> IndexName -> MappingName
392documentExists :: Server -> IndexName -> MappingName
365 -> DocId -> IO Bool
393 -> DocId -> IO Bool
366documentExists (Server server) (IndexName indexName)
394documentExists (Server server) (IndexName indexName)
@@ -372,27 +400,75 @@ documentExists (Server server) (IndexName indexName)
372dispatchSearch :: String -> Search -> IO Reply
400dispatchSearch :: String -> Search -> IO Reply
373dispatchSearch url search = post url (Just (encode search))
401dispatchSearch url search = post url (Just (encode search))
403+-- | 'searchAll', given a 'Search', will perform that search against all indexes
404+-- on an Elasticsearch server. Try to avoid doing this if it can be helped.
406+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
407+-- >>> let search = mkSearch (Just query) Nothing
408+-- >>> reply <- searchAll testServer search
375searchAll :: Server -> Search -> IO Reply
409searchAll :: Server -> Search -> IO Reply
376searchAll (Server server) = dispatchSearch url where
410searchAll (Server server) = dispatchSearch url where
377 url = joinPath [server, "_search"]
411 url = joinPath [server, "_search"]
413+-- | 'searchByIndex', given a 'Search' and an 'IndexName', will perform that search
414+-- against all mappings within an index on an Elasticsearch server.
416+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
417+-- >>> let search = mkSearch (Just query) Nothing
418+-- >>> reply <- searchByIndex testServer testIndex search
379searchByIndex :: Server -> IndexName -> Search -> IO Reply
419searchByIndex :: Server -> IndexName -> Search -> IO Reply
380searchByIndex (Server server) (IndexName indexName) = dispatchSearch url where
420searchByIndex (Server server) (IndexName indexName) = dispatchSearch url where
381 url = joinPath [server, indexName, "_search"]
421 url = joinPath [server, indexName, "_search"]
423+-- | 'searchByType', given a 'Search', 'IndexName', and 'MappingName', will perform that
424+-- search against a specific mapping within an index on an Elasticsearch server.
426+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
427+-- >>> let search = mkSearch (Just query) Nothing
428+-- >>> reply <- searchByType testServer testIndex testMapping search
383searchByType :: Server -> IndexName -> MappingName -> Search -> IO Reply
429searchByType :: Server -> IndexName -> MappingName -> Search -> IO Reply
384searchByType (Server server) (IndexName indexName)
430searchByType (Server server) (IndexName indexName)
385 (MappingName mappingName) = dispatchSearch url where
431 (MappingName mappingName) = dispatchSearch url where
386 url = joinPath [server, indexName, mappingName, "_search"]
432 url = joinPath [server, indexName, mappingName, "_search"]
434+-- | 'mkSearch' is a helper function for defaulting additional fields of a 'Search'
435+-- to Nothing in case you only care about your 'Query' and 'Filter'. Use record update
436+-- syntax if you want to add things like aggregations or highlights while still using
437+-- this helper function.
439+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
440+-- >>> mkSearch (Just query) Nothing
441+-- Search {queryBody = Just (TermQuery (Term {termField = "user", termValue = "bitemyapp"}) Nothing), filterBody = Nothing, sortBody = Nothing, aggBody = Nothing, highlight = Nothing, trackSortScores = False, from = 0, size = 10}
388mkSearch :: Maybe Query -> Maybe Filter -> Search
442mkSearch :: Maybe Query -> Maybe Filter -> Search
389mkSearch query filter = Search query filter Nothing Nothing Nothing False 0 10
443mkSearch query filter = Search query filter Nothing Nothing Nothing False 0 10
445+-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
446+-- the 'Query' and the 'Aggregation'.
448+-- >>> let terms = TermsAgg $ (mkTermsAggregation "user") { termCollectMode = Just BreadthFirst }
450+-- TermsAgg (TermsAggregation {term = Left "user", termInclude = Nothing, termExclude = Nothing, termOrder = Nothing, termMinDocCount = Nothing, termSize = Nothing, termShardSize = Nothing, termCollectMode = Just BreadthFirst, termExecutionHint = Nothing, termAggs = Nothing})
451+-- >>> let myAggregation = mkAggregateSearch Nothing $ mkAggregations "users" terms
391mkAggregateSearch :: Maybe Query -> Aggregations -> Search
452mkAggregateSearch :: Maybe Query -> Aggregations -> Search
392mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False 0 0
453mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False 0 0
455+-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
456+-- the 'Query' and the 'Aggregation'.
458+-- >>> let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
459+-- >>> let testHighlight = Highlights Nothing [FieldHighlight (FieldName "message") Nothing]
460+-- >>> let search = mkHighlightSearch (Just query) testHighlight
394mkHighlightSearch :: Maybe Query -> Highlights -> Search
461mkHighlightSearch :: Maybe Query -> Highlights -> Search
395mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False 0 10
462mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False 0 10
464+-- | 'pageSearch' is a helper function that takes a search and assigns the page from and to
465+-- fields for the search.
467+-- >>> let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
468+-- >>> let search = mkSearch (Just query) Nothing
470+-- 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 = 0, size = 10}
471+-- >>> pageSearch 10 100 search
472+-- 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 = 10, size = 100}
397pageSearch :: Int -> Int -> Search -> Search
473pageSearch :: Int -> Int -> Search -> Search
398pageSearch pageFrom pageSize search = search { from = pageFrom, size = pageSize }
474pageSearch pageFrom pageSize search = search { from = pageFrom, size = pageSize }