1module Database.Bloodhound.Client
20import qualified Data.ByteString.Lazy.Char8 as L
21import Data.ByteString.Builder
22import Data.List (foldl', intercalate, intersperse)
23import Data.Maybe (fromMaybe)
24import Data.Text (Text)
25import Network.HTTP.Conduit
26import qualified Network.HTTP.Types.Method as NHTM
27import qualified Network.HTTP.Types.Status as NHTS
28import Prelude hiding (head)
30import Database.Bloodhound.Types
31import Database.Bloodhound.Types.Class
32import Database.Bloodhound.Types.Instances
34-- find way to avoid destructuring Servers and Indexes?
35-- make get, post, put, delete helpers.
36-- make dispatch take URL last for better variance and
37-- utilization of partial application
39mkShardCount :: Int -> Maybe ShardCount
42 | n > 1000 = Nothing -- seriously, what the fuck?
43 | otherwise = Just (ShardCount n)
45mkReplicaCount :: Int -> Maybe ReplicaCount
48 | n > 1000 = Nothing -- ...
49 | otherwise = Just (ReplicaCount n)
51responseIsError :: Reply -> Bool
52responseIsError resp = NHTS.statusCode (responseStatus resp) > 299
56dispatch :: Method -> String -> Maybe L.ByteString
58dispatch method url body = do
59 initReq <- parseUrl url
60 let reqBody = RequestBodyLBS $ fromMaybe emptyBody body
61 let req = initReq { method = method
62 , requestBody = reqBody
63 , checkStatus = \_ _ _ -> Nothing}
64 withManager $ httpLbs req
66joinPath :: [String] -> String
67joinPath = intercalate "/"
69delete = flip (dispatch NHTM.methodDelete) $ Nothing
70get = flip (dispatch NHTM.methodGet) $ Nothing
71head = flip (dispatch NHTM.methodHead) $ Nothing
72put = dispatch NHTM.methodPost
73post = dispatch NHTM.methodPost
75-- indexDocument s ix name doc = put (root </> s </> ix </> name </> doc) (Just encode doc)
76-- http://hackage.haskell.org/package/http-client-lens-0.1.0/docs/Network-HTTP-Client-Lens.html
77-- https://github.com/supki/libjenkins/blob/master/src/Jenkins/Rest/Internal.hs
79getStatus :: Server -> IO (Maybe (Status Version))
80getStatus (Server server) = do
81 request <- parseUrl $ joinPath [server]
82 response <- withManager $ httpLbs request
83 return $ decode (responseBody response)
85createIndex :: Server -> IndexSettings -> IndexName -> IO Reply
86createIndex (Server server) indexSettings (IndexName indexName) =
88 where url = joinPath [server, indexName]
89 body = Just $ encode indexSettings
91deleteIndex :: Server -> IndexName -> IO Reply
92deleteIndex (Server server) (IndexName indexName) =
93 delete $ joinPath [server, indexName]
95respIsTwoHunna :: Reply -> Bool
96respIsTwoHunna resp = NHTS.statusCode (responseStatus resp) == 200
98existentialQuery url = do
100 return (reply, respIsTwoHunna reply)
102indexExists :: Server -> IndexName -> IO Bool
103indexExists (Server server) (IndexName indexName) = do
104 (reply, exists) <- existentialQuery url
106 where url = joinPath [server, indexName]
108refreshIndex :: Server -> IndexName -> IO Reply
109refreshIndex (Server server) (IndexName indexName) =
111 where url = joinPath [server, indexName, "_refresh"]
113stringifyOCIndex oci = case oci of
115 CloseIndex -> "_close"
117openOrCloseIndexes :: OpenCloseIndex -> Server -> IndexName -> IO Reply
118openOrCloseIndexes oci (Server server) (IndexName indexName) =
120 where ociString = stringifyOCIndex oci
121 url = joinPath [server, indexName, ociString]
123openIndex :: Server -> IndexName -> IO Reply
124openIndex = openOrCloseIndexes OpenIndex
126closeIndex :: Server -> IndexName -> IO Reply
127closeIndex = openOrCloseIndexes CloseIndex
129createMapping :: ToJSON a => Server -> IndexName
130 -> MappingName -> a -> IO Reply
131createMapping (Server server) (IndexName indexName) (MappingName mappingName) mapping =
133 where url = joinPath [server, indexName, mappingName, "_mapping"]
134 body = Just $ encode mapping
136deleteMapping :: Server -> IndexName -> MappingName -> IO Reply
137deleteMapping (Server server) (IndexName indexName) (MappingName mappingName) =
138 delete $ joinPath [server, indexName, mappingName, "_mapping"]
140indexDocument :: ToJSON doc => Server -> IndexName -> MappingName
141 -> doc -> DocId -> IO Reply
142indexDocument (Server server) (IndexName indexName)
143 (MappingName mappingName) document (DocId docId) =
145 where url = joinPath [server, indexName, mappingName, docId]
146 body = Just (encode document)
148deleteDocument :: Server -> IndexName -> MappingName
150deleteDocument (Server server) (IndexName indexName)
151 (MappingName mappingName) (DocId docId) =
152 delete $ joinPath [server, indexName, mappingName, docId]
154bulk :: Server -> [BulkOperation] -> IO Reply
155bulk (Server server) bulkOps = post url body where
156 url = joinPath [server, "_bulk"]
157 body = Just $ collapseStream bulkOps
159collapseStream :: [BulkOperation] -> L.ByteString
160collapseStream stream = collapsed where
161 blobs = intersperse "\n" $ concat $ fmap getStreamChunk stream
162 mashedTaters = mash (mempty :: Builder) blobs
163 collapsed = toLazyByteString $ mappend mashedTaters "\n"
165mash :: Builder -> [L.ByteString] -> Builder
166mash builder xs = foldl' (\b x -> mappend b (lazyByteString x)) builder xs
168mkMetadataValue :: Text -> String -> String -> String -> Value
169mkMetadataValue operation indexName mappingName docId =
171 object ["_index" .= indexName
172 , "_type" .= mappingName
175getStreamChunk :: BulkOperation -> [L.ByteString]
176getStreamChunk (BulkIndex (IndexName indexName)
177 (MappingName mappingName)
178 (DocId docId) value) = blob where
179 metadata = mkMetadataValue "index" indexName mappingName docId
180 blob = [encode metadata, encode value]
182getStreamChunk (BulkCreate (IndexName indexName)
183 (MappingName mappingName)
184 (DocId docId) value) = blob where
185 metadata = mkMetadataValue "create" indexName mappingName docId
186 blob = [encode metadata, encode value]
188getStreamChunk (BulkDelete (IndexName indexName)
189 (MappingName mappingName)
190 (DocId docId)) = blob where
191 metadata = mkMetadataValue "delete" indexName mappingName docId
192 blob = [encode metadata]
194getStreamChunk (BulkUpdate (IndexName indexName)
195 (MappingName mappingName)
196 (DocId docId) value) = blob where
197 metadata = mkMetadataValue "update" indexName mappingName docId
198 doc = object ["doc" .= value]
199 blob = [encode metadata, encode doc]
201getDocument :: Server -> IndexName -> MappingName
203getDocument (Server server) (IndexName indexName) (MappingName mappingName) (DocId docId) =
204 get $ joinPath [server, indexName, mappingName, docId]
206documentExists :: Server -> IndexName -> MappingName
208documentExists (Server server) (IndexName indexName)
209 (MappingName mappingName) (DocId docId) = do
210 (reply, exists) <- existentialQuery url
212 url = joinPath [server, indexName, mappingName, docId]
214dispatchSearch :: String -> Search -> IO Reply
215dispatchSearch url search = post url (Just (encode search))
217searchAll :: Server -> Search -> IO Reply
218searchAll (Server server) search = dispatchSearch url search where
219 url = joinPath [server, "_search"]
221searchByIndex :: Server -> IndexName -> Search -> IO Reply
222searchByIndex (Server server) (IndexName indexName) search = dispatchSearch url search where
223 url = joinPath [server, indexName, "_search"]
225searchByType :: Server -> IndexName -> MappingName -> Search -> IO Reply
226searchByType (Server server) (IndexName indexName)
227 (MappingName mappingName) search = dispatchSearch url search where
228 url = joinPath [server, indexName, mappingName, "_search"]
230mkSearch :: Maybe Query -> Maybe Filter -> Search
231mkSearch query filter = Search query filter Nothing False 0 10
233pageSearch :: Int -> Int -> Search -> Search
234pageSearch from size search = search { from = from, size = size }
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list