git.iko.soy/typeable/bloodhound
on master help sign in
Merge pull request #58 from Soostone/57-esresult-partiality
85bbc62Chris Allen
README.md+13−14
@@ -276,23 +276,22 @@ let eitherResult = eitherDecode body :: Either String (EsResult Tweet)
276Right (EsResult {_index = "twitter"
276Right (EsResult {_index = "twitter"
277 , _type = "tweet"
277 , _type = "tweet"
278 , _id = "1"
278 , _id = "1"
279− , _version = 2
279+ , foundResult = Just (EsResultFound { _version = 2
280− , found = Just True
281− , _source = Tweet {user = "bitemyapp"
280+ , _source = Tweet {user = "bitemyapp"
282− , postDate = 2009-06-18 00:00:10 UTC
281+ , postDate = 2009-06-18 00:00:10 UTC
283− , message = "Use haskell!"
282+ , message = "Use haskell!"
284− , age = 10000
283+ , age = 10000
285− , location = Location {lat = 40.12, lon = -71.34}}})
284+ , location = Location {lat = 40.12, lon = -71.34}}})})
286
285
287−-- _source in EsResult is parametric, we dispatch the type by passing in what we expect (Tweet) as a parameter to EsResult.
286+-- _source in EsResultFound is parametric, we dispatch the type by passing in what we expect (Tweet) as a parameter to EsResult.
288
287
289-- use the _source record accessor to get at your document
288-- use the _source record accessor to get at your document
290−fmap _source eitherResult
289+fmap (fmap _source . foundResult) eitherResult
291−Right (Tweet {user = "bitemyapp"
290+Right (Just (Tweet {user = "bitemyapp"
292− , postDate = 2009-06-18 00:00:10 UTC
291+ , postDate = 2009-06-18 00:00:10 UTC
293− , message = "Use haskell!"
292+ , message = "Use haskell!"
294− , age = 10000
293+ , age = 10000
295− , location = Location {lat = 40.12, lon = -71.34}})
294+ , location = Location {lat = 40.12, lon = -71.34}}))
296
295
297```
296```
298
297
src/Database/Bloodhound/Types.hs+26−11
@@ -60,6 +60,7 @@ module Database.Bloodhound.Types
60 , Server(..)
60 , Server(..)
61 , Reply
61 , Reply
62 , EsResult(..)
62 , EsResult(..)
63+ , EsResultFound(..)
63 , DocVersion
64 , DocVersion
64 , ExternalDocVersion(..)
65 , ExternalDocVersion(..)
65 , VersionControl(..)
66 , VersionControl(..)
@@ -394,14 +395,21 @@ data BulkOperation =
394 | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Show)
395 | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Show)
395
396
396{-| 'EsResult' describes the standard wrapper JSON document that you see in
397{-| 'EsResult' describes the standard wrapper JSON document that you see in
397− successful Elasticsearch responses.
398+ successful Elasticsearch lookups or lookups that couldn't find the document.
398-}
399-}
399data EsResult a = EsResult { _index :: Text
400data EsResult a = EsResult { _index :: Text
400 , _type :: Text
401 , _type :: Text
401 , _id :: Text
402 , _id :: Text
403+ , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Show)
404+
405+
406+{-| 'EsResultFound' contains the document and its metadata inside of an
407+ 'EsResult' when the document was successfully found.
408+-}
402− , _version :: DocVersion
409+data EsResultFound a = EsResultFound { _version :: DocVersion
403− , found :: Maybe Bool
404− , _source :: a } deriving (Eq, Show)
410+ , _source :: a } deriving (Eq, Show)
411+
412+
405
413
406{-| 'DocVersion' is an integer version number for a document between 1
414{-| 'DocVersion' is an integer version number for a document between 1
407and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
415and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
@@ -2039,15 +2047,22 @@ instance ToJSON IndexTemplate where
2039 merge _ _ = undefined
2047 merge _ _ = undefined
2040
2048
2041instance (FromJSON a) => FromJSON (EsResult a) where
2049instance (FromJSON a) => FromJSON (EsResult a) where
2042− parseJSON (Object v) = EsResult <$>
2050+ parseJSON jsonVal@(Object v) = do
2051+ found <- v .:? "found" .!= False
2052+ fr <- if found
2053+ then parseJSON jsonVal
2054+ else return Nothing
2043− v .: "_index" <*>
2055+ EsResult <$> v .: "_index" <*>
2044− v .: "_type" <*>
2056+ v .: "_type" <*>
2045− v .: "_id" <*>
2057+ v .: "_id" <*>
2046− v .: "_version" <*>
2058+ pure fr
2047− v .:? "found" <*>
2048− v .: "_source"
2049 parseJSON _ = empty
2059 parseJSON _ = empty
2050
2060
2061+instance (FromJSON a) => FromJSON (EsResultFound a) where
2062+ parseJSON (Object v) = EsResultFound <$>
2063+ v .: "_version" <*>
2064+ v .: "_source"
2065+ parseJSON _ = empty
2051
2066
2052instance ToJSON Search where
2067instance ToJSON Search where
2053 toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize sFields) =
2068 toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize sFields) =
tests/tests.hs+14−5
@@ -278,6 +278,9 @@ instance Arbitrary a => Arbitrary (SearchHits a) where
278 hs <- arbitrary
278 hs <- arbitrary
279 return $ SearchHits tot score hs
279 return $ SearchHits tot score hs
280
280
281+getSource :: EsResult a -> Maybe a
282+getSource = fmap _source . foundResult
283+
281main :: IO ()
284main :: IO ()
282main = hspec $ do
285main = hspec $ do
283
286
@@ -298,7 +301,13 @@ main = hspec $ do
298 docInserted <- getDocument testIndex testMapping (DocId "1")
301 docInserted <- getDocument testIndex testMapping (DocId "1")
299 let newTweet = eitherDecode
302 let newTweet = eitherDecode
300 (responseBody docInserted) :: Either String (EsResult Tweet)
303 (responseBody docInserted) :: Either String (EsResult Tweet)
301− liftIO $ (fmap _source newTweet `shouldBe` Right exampleTweet)
304+ liftIO $ (fmap getSource newTweet `shouldBe` Right (Just exampleTweet))
305+
306+ it "produces a parseable result when looking up a bogus document" $ withTestEnv $ do
307+ doc <- getDocument testIndex testMapping (DocId "bogus")
308+ let noTweet = eitherDecode
309+ (responseBody doc) :: Either String (EsResult Tweet)
310+ liftIO $ fmap foundResult noTweet `shouldBe` Right Nothing
302
311
303 it "can use optimistic concurrency control" $ withTestEnv $ do
312 it "can use optimistic concurrency control" $ withTestEnv $ do
304 let ev = ExternalDocVersion minBound
313 let ev = ExternalDocVersion minBound
@@ -344,8 +353,8 @@ main = hspec $ do
344 let maybeFirst = eitherDecode $ responseBody fDoc :: Either String (EsResult BulkTest)
353 let maybeFirst = eitherDecode $ responseBody fDoc :: Either String (EsResult BulkTest)
345 let maybeSecond = eitherDecode $ responseBody sDoc :: Either String (EsResult BulkTest)
354 let maybeSecond = eitherDecode $ responseBody sDoc :: Either String (EsResult BulkTest)
346 liftIO $ do
355 liftIO $ do
347− fmap _source maybeFirst `shouldBe` Right firstTest
356+ fmap getSource maybeFirst `shouldBe` Right (Just firstTest)
348− fmap _source maybeSecond `shouldBe` Right secondTest
357+ fmap getSource maybeSecond `shouldBe` Right (Just secondTest)
349
358
350
359
351 describe "query API" $ do
360 describe "query API" $ do
@@ -377,8 +386,8 @@ main = hspec $ do
377
386
378 it "returns document for multi-match query" $ withTestEnv $ do
387 it "returns document for multi-match query" $ withTestEnv $ do
379 _ <- insertData
388 _ <- insertData
380− let fields = [FieldName "user", FieldName "message"]
389+ let flds = [FieldName "user", FieldName "message"]
381− let query = QueryMultiMatchQuery $ mkMultiMatchQuery fields (QueryString "bitemyapp")
390+ let query = QueryMultiMatchQuery $ mkMultiMatchQuery flds (QueryString "bitemyapp")
382 let search = mkSearch (Just query) Nothing
391 let search = mkSearch (Just query) Nothing
383 myTweet <- searchTweet search
392 myTweet <- searchTweet search
384 liftIO $
393 liftIO $