@@ -108,12 +108,22 @@ import Database.Bloodhound.Types
108108--instance ToJSON BulkTest
109109-- :}
110110
111+-- | 'mkShardCount' is a straight-forward smart constructor for 'ShardCount'
112+-- which rejects 'Int' values below 1 and above 1000.
113+--
114+-- >>> mkShardCount 10
115+-- Just (ShardCount 10)
111116mkShardCount :: Int -> Maybe ShardCount
112117mkShardCount n
113118 | n < 1 = Nothing
114119 | n > 1000 = Nothing
115120 | otherwise = Just (ShardCount n)
116121
122+-- | 'mkReplicaCount' is a straight-forward smart constructor for 'ReplicaCount'
123+-- which rejects 'Int' values below 1 and above 1000.
124+--
125+-- >>> mkReplicaCount 10
126+-- Just (ReplicaCount 10)
117127mkReplicaCount :: Int -> Maybe ReplicaCount
118128mkReplicaCount n
119129 | n < 1 = Nothing
@@ -152,14 +162,17 @@ post = dispatch NHTM.methodPost
152162-- http://hackage.haskell.org/package/http-client-lens-0.1.0/docs/Network-HTTP-Client-Lens.html
153163-- https://github.com/supki/libjenkins/blob/master/src/Jenkins/Rest/Internal.hs
154164
165+-- | 'getStatus' fetches the 'Status' of a 'Server'
166+--
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"})
155169getStatus :: Server -> IO (Maybe Status)
156170getStatus (Server server) = do
157171 request <- parseUrl $ joinPath [server]
158172 response <- withManager defaultManagerSettings $ httpLbs request
159173 return $ decode (responseBody response)
160174
161−-- | createIndex will create an index given a 'Server',
162−-- 'IndexSettings', and an 'IndexName'
175+-- | 'createIndex' will create an index given a 'Server', 'IndexSettings', and an 'IndexName'.
163176--
164177-- >>> response <- createIndex testServer defaultIndexSettings (IndexName "didimakeanindex")
165178-- >>> respIsTwoHunna response
@@ -172,8 +185,7 @@ createIndex (Server server) indexSettings (IndexName indexName) =
172185 where url = joinPath [server, indexName]
173186 body = Just $ encode indexSettings
174187
175−-- | deleteIndex will delete an index given a 'Server',
176−-- and an 'IndexName'
188+-- | 'deleteIndex' will delete an index given a 'Server', and an 'IndexName'.
177189--
178190-- >>> response <- createIndex testServer defaultIndexSettings (IndexName "didimakeanindex")
179191-- >>> response <- deleteIndex testServer (IndexName "didimakeanindex")
@@ -196,6 +208,10 @@ existentialQuery url = do
196208 reply <- head url
197209 return (reply, respIsTwoHunna reply)
198210
211+-- | 'indexExists' enables you to check if an index exists. Returns 'Bool'
212+-- in IO
213+--
214+-- >>> exists <- indexExists testServer testIndex
199215indexExists :: Server -> IndexName -> IO Bool
200216indexExists (Server server) (IndexName indexName) = do
201217 (_, exists) <- existentialQuery url
@@ -223,9 +239,17 @@ openOrCloseIndexes oci (Server server) (IndexName indexName) =
223239 where ociString = stringifyOCIndex oci
224240 url = joinPath [server, indexName, ociString]
225241
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
244+--
245+-- >>> reply <- openIndex testServer testIndex
226246openIndex :: Server -> IndexName -> IO Reply
227247openIndex = openOrCloseIndexes OpenIndex
228248
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
251+--
252+-- >>> reply <- closeIndex testServer testIndex
229253closeIndex :: Server -> IndexName -> IO Reply
230254closeIndex = openOrCloseIndexes CloseIndex
231255
@@ -361,6 +385,10 @@ getDocument (Server server) (IndexName indexName)
361385 (MappingName mappingName) (DocId docId) =
362386 get $ joinPath [server, indexName, mappingName, docId]
363387
388+-- | 'documentExists' enables you to check if a document exists. Returns 'Bool'
389+-- in IO
390+--
391+-- >>> exists <- documentExists testServer testIndex testMapping (DocId "1")
364392documentExists :: Server -> IndexName -> MappingName
365393 -> DocId -> IO Bool
366394documentExists (Server server) (IndexName indexName)
@@ -372,27 +400,75 @@ documentExists (Server server) (IndexName indexName)
372400dispatchSearch :: String -> Search -> IO Reply
373401dispatchSearch url search = post url (Just (encode search))
374402
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.
405+--
406+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
407+-- >>> let search = mkSearch (Just query) Nothing
408+-- >>> reply <- searchAll testServer search
375409searchAll :: Server -> Search -> IO Reply
376410searchAll (Server server) = dispatchSearch url where
377411 url = joinPath [server, "_search"]
378412
413+-- | 'searchByIndex', given a 'Search' and an 'IndexName', will perform that search
414+-- against all mappings within an index on an Elasticsearch server.
415+--
416+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
417+-- >>> let search = mkSearch (Just query) Nothing
418+-- >>> reply <- searchByIndex testServer testIndex search
379419searchByIndex :: Server -> IndexName -> Search -> IO Reply
380420searchByIndex (Server server) (IndexName indexName) = dispatchSearch url where
381421 url = joinPath [server, indexName, "_search"]
382422
423+-- | 'searchByType', given a 'Search', 'IndexName', and 'MappingName', will perform that
424+-- search against a specific mapping within an index on an Elasticsearch server.
425+--
426+-- >>> let query = TermQuery (Term "user" "bitemyapp") Nothing
427+-- >>> let search = mkSearch (Just query) Nothing
428+-- >>> reply <- searchByType testServer testIndex testMapping search
383429searchByType :: Server -> IndexName -> MappingName -> Search -> IO Reply
384430searchByType (Server server) (IndexName indexName)
385431 (MappingName mappingName) = dispatchSearch url where
386432 url = joinPath [server, indexName, mappingName, "_search"]
387433
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.
438+--
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}
388442mkSearch :: Maybe Query -> Maybe Filter -> Search
389443mkSearch query filter = Search query filter Nothing Nothing Nothing False 0 10
390444
445+-- | 'mkAggregateSearch' is a helper function that defaults everything in a 'Search' except for
446+-- the 'Query' and the 'Aggregation'.
447+--
448+-- >>> let terms = TermsAgg $ (mkTermsAggregation "user") { termCollectMode = Just BreadthFirst }
449+-- >>> terms
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
391452mkAggregateSearch :: Maybe Query -> Aggregations -> Search
392453mkAggregateSearch query mkSearchAggs = Search query Nothing Nothing (Just mkSearchAggs) Nothing False 0 0
393454
455+-- | 'mkHighlightSearch' is a helper function that defaults everything in a 'Search' except for
456+-- the 'Query' and the 'Aggregation'.
457+--
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
394461mkHighlightSearch :: Maybe Query -> Highlights -> Search
395462mkHighlightSearch query searchHighlights = Search query Nothing Nothing Nothing (Just searchHighlights) False 0 10
396463
464+-- | 'pageSearch' is a helper function that takes a search and assigns the page from and to
465+-- fields for the search.
466+--
467+-- >>> let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
468+-- >>> let search = mkSearch (Just query) Nothing
469+-- >>> search
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}
397473pageSearch :: Int -> Int -> Search -> Search
398474pageSearch pageFrom pageSize search = search { from = pageFrom, size = pageSize }