git.iko.soy/typeable/bloodhound
on master help sign in
negative bounding box test
eb668ceChris Allen
Database/Bloodhound/Client.hs+28−28
@@ -62,7 +62,7 @@ data (FromJSON a, ToJSON a) => Status a =
62 , status :: Int
62 , status :: Int
63 , name :: Text
63 , name :: Text
64 , version :: a
64 , version :: a
65− , tagline :: Text } deriving (Show)
65+ , tagline :: Text } deriving (Eq, Show)
66
66
67instance ToJSON Version
67instance ToJSON Version
68instance FromJSON Version
68instance FromJSON Version
@@ -78,8 +78,8 @@ instance (FromJSON a, ToJSON a) => FromJSON (Status a) where
78
78
79main = simpleHttp "http://localhost:9200/events/event/_search?q=hostname:localhost&size=1" >>= L.putStrLn
79main = simpleHttp "http://localhost:9200/events/event/_search?q=hostname:localhost&size=1" >>= L.putStrLn
80
80
81−newtype ShardCount = ShardCount Int deriving (Show, Generic)
81+newtype ShardCount = ShardCount Int deriving (Eq, Show, Generic)
82−newtype ReplicaCount = ReplicaCount Int deriving (Show, Generic)
82+newtype ReplicaCount = ReplicaCount Int deriving (Eq, Show, Generic)
83
83
84mkShardCount :: Int -> Maybe ShardCount
84mkShardCount :: Int -> Maybe ShardCount
85mkShardCount n
85mkShardCount n
@@ -95,7 +95,7 @@ mkReplicaCount n
95
95
96data IndexSettings =
96data IndexSettings =
97 IndexSettings { indexShards :: ShardCount
97 IndexSettings { indexShards :: ShardCount
98− , indexReplicas :: ReplicaCount } deriving (Show)
98+ , indexReplicas :: ReplicaCount } deriving (Eq, Show)
99
99
100instance ToJSON IndexSettings where
100instance ToJSON IndexSettings where
101 toJSON (IndexSettings s r) = object ["settings" .= object ["shards" .= s, "replicas" .= r]]
101 toJSON (IndexSettings s r) = object ["settings" .= object ["shards" .= s, "replicas" .= r]]
@@ -105,9 +105,9 @@ instance ToJSON ShardCount
105
105
106defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
106defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
107
107
108−data Strategy = RoundRobinStrat | RandomStrat | HeadStrat deriving (Show)
108+data Strategy = RoundRobinStrat | RandomStrat | HeadStrat deriving (Eq, Show)
109
109
110−newtype Server = Server String deriving (Show)
110+newtype Server = Server String deriving (Eq, Show)
111
111
112type Reply = Network.HTTP.Conduit.Response L.ByteString
112type Reply = Network.HTTP.Conduit.Response L.ByteString
113type Method = NHTM.Method
113type Method = NHTM.Method
@@ -171,7 +171,7 @@ refreshIndex (Server server) indexName = dispatch url method body where
171 method = NHTM.methodPost
171 method = NHTM.methodPost
172 body = Nothing
172 body = Nothing
173
173
174−data OpenCloseIndex = OpenIndex | CloseIndex deriving (Show)
174+data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Show)
175
175
176stringifyOCIndex oci = case oci of
176stringifyOCIndex oci = case oci of
177 OpenIndex -> "_open"
177 OpenIndex -> "_open"
@@ -293,7 +293,7 @@ searchByType (Server server) indexName mappingName search = dispatchSearch url s
293 url = joinPath [server, indexName, mappingName, "_search"]
293 url = joinPath [server, indexName, mappingName, "_search"]
294
294
295data Search = Search { queryBody :: Maybe Query
295data Search = Search { queryBody :: Maybe Query
296− , filterBody :: Maybe Filter } deriving (Show)
296+ , filterBody :: Maybe Filter } deriving (Eq, Show)
297
297
298instance ToJSON Search where
298instance ToJSON Search where
299 toJSON (Search query filters) = object [--"query" .= fmap toJSON query,
299 toJSON (Search query filters) = object [--"query" .= fmap toJSON query,
@@ -306,12 +306,12 @@ type QueryString = Text
306-- field title has no value or doesn't exist, _missing_:title
306-- field title has no value or doesn't exist, _missing_:title
307-- field title has any non-null value, _exists:title
307-- field title has any non-null value, _exists:title
308
308
309−data BooleanOperator = AND | OR deriving (Show)
309+data BooleanOperator = AND | OR deriving (Eq, Show)
310
310
311type DisMax = Bool -- "use_dis_max"
311type DisMax = Bool -- "use_dis_max"
312−newtype TieBreaker = TieBreaker Int deriving (Show)
312+newtype TieBreaker = TieBreaker Int deriving (Eq, Show)
313data QueryField = DefaultField Text
313data QueryField = DefaultField Text
314− | Fields [Text] DisMax TieBreaker deriving (Show)
314+ | Fields [Text] DisMax TieBreaker deriving (Eq, Show)
315
315
316-- this is will go away later
316-- this is will go away later
317type Query = QueryStringQuery
317type Query = QueryStringQuery
@@ -350,7 +350,7 @@ data QueryStringQuery =
350 , lenient :: Maybe Bool
350 , lenient :: Maybe Bool
351 -- default ROOT, locale used for string conversions
351 -- default ROOT, locale used for string conversions
352 , locale :: Maybe Text
352 , locale :: Maybe Text
353− } deriving (Show)
353+ } deriving (Eq, Show)
354
354
355emptyQueryStringQuery = QueryStringQuery "" Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
355emptyQueryStringQuery = QueryStringQuery "" Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
356queryStringQuery query = emptyQueryStringQuery { query = query }
356queryStringQuery query = emptyQueryStringQuery { query = query }
@@ -367,7 +367,7 @@ data Filter = AndFilter [Filter] Cache
367 | ExistsFilter FieldName -- always cached
367 | ExistsFilter FieldName -- always cached
368 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
368 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
369 | GeoDistanceFilter GeoConstraint Distance
369 | GeoDistanceFilter GeoConstraint Distance
370− deriving (Show)
370+ deriving (Eq, Show)
371
371
372class Monoid a => Seminearring a where
372class Monoid a => Seminearring a where
373 -- 0, +, *
373 -- 0, +, *
@@ -423,7 +423,7 @@ instance ToJSON LatLon where
423 , "lon" .= lon]
423 , "lon" .= lon]
424
424
425data Term = Term { termField :: Text
425data Term = Term { termField :: Text
426− , termValue :: Text } deriving (Show)
426+ , termValue :: Text } deriving (Eq, Show)
427
427
428instance ToJSON Term where
428instance ToJSON Term where
429 toJSON (Term field value) = object ["term" .= object
429 toJSON (Term field value) = object ["term" .= object
@@ -431,7 +431,7 @@ instance ToJSON Term where
431
431
432data BoolMatch = MustMatch Term Cache
432data BoolMatch = MustMatch Term Cache
433 | MustNotMatch Term Cache
433 | MustNotMatch Term Cache
434− | ShouldMatch [Term] Cache deriving (Show)
434+ | ShouldMatch [Term] Cache deriving (Eq, Show)
435
435
436instance ToJSON BoolMatch where
436instance ToJSON BoolMatch where
437 toJSON (MustMatch term cache) = object ["must" .= toJSON term,
437 toJSON (MustMatch term cache) = object ["must" .= toJSON term,
@@ -442,25 +442,25 @@ instance ToJSON BoolMatch where
442 "_cache" .= cache]
442 "_cache" .= cache]
443
443
444-- "memory" or "indexed"
444-- "memory" or "indexed"
445−data GeoFilterType = GeoFilterMemory | GeoFilterIndexed deriving (Show)
445+data GeoFilterType = GeoFilterMemory | GeoFilterIndexed deriving (Eq, Show)
446
446
447
447
448data LatLon = LatLon { lat :: Double
448data LatLon = LatLon { lat :: Double
449− , lon :: Double } deriving (Show)
449+ , lon :: Double } deriving (Eq, Show)
450
450
451data GeoBoundingBox =
451data GeoBoundingBox =
452 GeoBoundingBox { topLeft :: LatLon
452 GeoBoundingBox { topLeft :: LatLon
453− , bottomRight :: LatLon } deriving (Show)
453+ , bottomRight :: LatLon } deriving (Eq, Show)
454
454
455data GeoBoundingBoxConstraint =
455data GeoBoundingBoxConstraint =
456 GeoBoundingBoxConstraint { geoBBField :: FieldName
456 GeoBoundingBoxConstraint { geoBBField :: FieldName
457 , constraintBox :: GeoBoundingBox
457 , constraintBox :: GeoBoundingBox
458 , cache :: Cache
458 , cache :: Cache
459− } deriving (Show)
459+ } deriving (Eq, Show)
460
460
461data GeoConstraint =
461data GeoConstraint =
462 GeoConstraint { geoField :: FieldName
462 GeoConstraint { geoField :: FieldName
463− , latLon :: LatLon } deriving (Show)
463+ , latLon :: LatLon } deriving (Eq, Show)
464
464
465data DistanceUnits = Miles
465data DistanceUnits = Miles
466 | Yards
466 | Yards
@@ -470,41 +470,41 @@ data DistanceUnits = Miles
470 | Meters
470 | Meters
471 | Centimeters
471 | Centimeters
472 | Millimeters
472 | Millimeters
473− | NauticalMiles deriving (Show)
473+ | NauticalMiles deriving (Eq, Show)
474
474
475−data DistanceType = Arc | SloppyArc | Plane deriving (Show)
475+data DistanceType = Arc | SloppyArc | Plane deriving (Eq, Show)
476
476
477-- geo_point?
477-- geo_point?
478−data OptimizeBbox = OptimizeGeoFilterType GeoFilterType | NoOptimizeBbox deriving (Show)
478+data OptimizeBbox = OptimizeGeoFilterType GeoFilterType | NoOptimizeBbox deriving (Eq, Show)
479
479
480data Distance =
480data Distance =
481 Distance { coefficient :: Double
481 Distance { coefficient :: Double
482− , unit :: DistanceUnits } deriving (Show)
482+ , unit :: DistanceUnits } deriving (Eq, Show)
483
483
484data FromJSON a => SearchResult a =
484data FromJSON a => SearchResult a =
485 SearchResult { took :: Int
485 SearchResult { took :: Int
486 , timedOut :: Bool
486 , timedOut :: Bool
487 , shards :: ShardResult
487 , shards :: ShardResult
488− , searchHits :: SearchHits a } deriving (Show)
488+ , searchHits :: SearchHits a } deriving (Eq, Show)
489
489
490type Score = Double
490type Score = Double
491
491
492data FromJSON a => SearchHits a =
492data FromJSON a => SearchHits a =
493 SearchHits { hitsTotal :: Int
493 SearchHits { hitsTotal :: Int
494 , maxScore :: Score
494 , maxScore :: Score
495− , hits :: [Hit a] } deriving (Show)
495+ , hits :: [Hit a] } deriving (Eq, Show)
496
496
497data FromJSON a => Hit a =
497data FromJSON a => Hit a =
498 Hit { hitIndex :: IndexName
498 Hit { hitIndex :: IndexName
499 , hitType :: MappingName
499 , hitType :: MappingName
500 , hitDocumentID :: DocumentID
500 , hitDocumentID :: DocumentID
501 , hitScore :: Score
501 , hitScore :: Score
502− , hitSource :: a } deriving (Show)
502+ , hitSource :: a } deriving (Eq, Show)
503
503
504data ShardResult =
504data ShardResult =
505 ShardResult { shardTotal :: Int
505 ShardResult { shardTotal :: Int
506 , shardsSuccessful :: Int
506 , shardsSuccessful :: Int
507− , shardsFailed :: Int } deriving (Show, Generic)
507+ , shardsFailed :: Int } deriving (Eq, Show, Generic)
508
508
509instance (FromJSON a, ToJSON a) => FromJSON (SearchResult a) where
509instance (FromJSON a, ToJSON a) => FromJSON (SearchResult a) where
510 parseJSON (Object v) = SearchResult <$>
510 parseJSON (Object v) = SearchResult <$>
tests/tests.hs+13−2
@@ -64,7 +64,7 @@ insertData = do
64
64
65searchTweet :: Search -> IO (Either String Tweet)
65searchTweet :: Search -> IO (Either String Tweet)
66searchTweet search = do
66searchTweet search = do
67− reply <- searchByIndex testServer "twitter" search
67+ reply <- searchByIndex testServer testIndex search
68 let result = eitherDecode (responseBody reply) :: Either String (SearchResult Tweet)
68 let result = eitherDecode (responseBody reply) :: Either String (SearchResult Tweet)
69 let myTweet = fmap (hitSource . head . hits . searchHits) result
69 let myTweet = fmap (hitSource . head . hits . searchHits) result
70 return myTweet
70 return myTweet
@@ -83,7 +83,7 @@ main = hspec $ do
83 describe "document API" $ do
83 describe "document API" $ do
84 it "indexes, gets, and then deletes the generated document" $ do
84 it "indexes, gets, and then deletes the generated document" $ do
85 _ <- insertData
85 _ <- insertData
86− docInserted <- getDocument (Server "http://localhost:9200") "twitter" "tweet" "1"
86+ docInserted <- getDocument testServer testIndex testMapping "1"
87 let newTweet = eitherDecode (responseBody docInserted) :: Either String (EsResult Tweet)
87 let newTweet = eitherDecode (responseBody docInserted) :: Either String (EsResult Tweet)
88 fmap _source newTweet `shouldBe` Right exampleTweet
88 fmap _source newTweet `shouldBe` Right exampleTweet
89
89
@@ -110,3 +110,14 @@ main = hspec $ do
110 let search = Search Nothing (Just geoFilter)
110 let search = Search Nothing (Just geoFilter)
111 myTweet <- searchTweet search
111 myTweet <- searchTweet search
112 myTweet `shouldBe` Right exampleTweet
112 myTweet `shouldBe` Right exampleTweet
113+
114+ it "doesn't return document for nonsensical boundingbox query" $ do
115+ _ <- insertData
116+ let box = GeoBoundingBox (LatLon 0.73 (-4.1)) (LatLon 0.10 (-1.12))
117+ let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
118+ let geoFilter = GeoBoundingBoxFilter bbConstraint GeoFilterMemory
119+ let search = Search Nothing (Just geoFilter)
120+ reply <- searchByIndex testServer testIndex search
121+ let result = eitherDecode (responseBody reply) :: Either String (SearchResult Tweet)
122+ let emptyHits = fmap (hits . searchHits) result
123+ emptyHits `shouldBe` Right []