git.iko.soy/typeable/bloodhound
on master help sign in
geo distance range positive and negative validation
commit0c84e67e7f48d10ea3f825e4228d308b58780f69 authorChris Allen <cma@bitemyapp.com> dateThu 10 Apr 2014, 19:15 (13 years ago) parentd0e0763
2 files changed+49−16
Database/Bloodhound/Client.hs+22−10 tests/tests.hs+27−6
Database/Bloodhound/Client.hs+22−10
@@ -28,13 +28,14 @@ module Database.Bloodhound.Client
2828 , Seminearring(..)
2929 , BoolMatch(..)
3030 , Term(..)
31− , GeoConstraint(..)
31+ , GeoPoint(..)
3232 , GeoBoundingBoxConstraint(..)
3333 , GeoBoundingBox(..)
3434 , GeoFilterType(..)
3535 , Distance(..)
3636 , DistanceUnit(..)
3737 , DistanceType(..)
38+ , DistanceRange(..)
3839 , OptimizeBbox(..)
3940 , LatLon(..)
4041 )
@@ -371,7 +372,8 @@ data Filter = AndFilter [Filter] Cache
371372 | BoolFilter BoolMatch
372373 | ExistsFilter FieldName -- always cached
373374 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
374− | GeoDistanceFilter GeoConstraint Distance DistanceType OptimizeBbox Cache
375+ | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
376+ | GeoDistanceRangeFilter GeoPoint DistanceRange
375377 deriving (Eq, Show)
376378
377379class Monoid a => Seminearring a where
@@ -413,18 +415,24 @@ instance ToJSON Filter where
413415 object ["geo_bounding_box" .= toJSON bbConstraint
414416 , "type" .= toJSON filterType]
415417
416− toJSON (GeoDistanceFilter (GeoConstraint geoField latLon)
418+ toJSON (GeoDistanceFilter (GeoPoint geoField latLon)
417419 distance distanceType optimizeBbox cache) =
418420 object ["geo_distance" .=
419421 object ["distance" .= toJSON distance
420422 , "distance_type" .= toJSON distanceType
421423 , "optimize_bbox" .= optimizeBbox
422424 , geoField .= toJSON latLon
423− , "_cache" .= cache
424− ]]
425+ , "_cache" .= cache]]
425426
426−instance ToJSON GeoConstraint where
427− toJSON (GeoConstraint geoField latLon) =
427+ toJSON (GeoDistanceRangeFilter (GeoPoint geoField latLon)
428+ (DistanceRange distanceFrom distanceTo)) =
429+ object ["geo_distance_range" .=
430+ object ["from" .= toJSON distanceFrom
431+ , "to" .= toJSON distanceTo
432+ , geoField .= toJSON latLon]]
433+
434+instance ToJSON GeoPoint where
435+ toJSON (GeoPoint geoField latLon) =
428436 object [geoField .= toJSON latLon]
429437
430438showText :: Show a => a -> Text
@@ -513,9 +521,9 @@ data GeoBoundingBoxConstraint =
513521 , bbConstraintcache :: Cache
514522 } deriving (Eq, Show)
515523
516−data GeoConstraint =
517− GeoConstraint { geoField :: FieldName
518− , latLon :: LatLon} deriving (Eq, Show)
524+data GeoPoint =
525+ GeoPoint { geoField :: FieldName
526+ , latLon :: LatLon} deriving (Eq, Show)
519527
520528data DistanceUnit = Miles
521529 | Yards
@@ -538,6 +546,10 @@ data Distance =
538546 Distance { coefficient :: Double
539547 , unit :: DistanceUnit } deriving (Eq, Show)
540548
549+data DistanceRange =
550+ DistanceRange { distanceFrom :: Distance
551+ , distanceTo :: Distance } deriving (Eq, Show)
552+
541553data FromJSON a => SearchResult a =
542554 SearchResult { took :: Int
543555 , timedOut :: Bool
tests/tests.hs+27−6
@@ -69,6 +69,13 @@ searchTweet search = do
6969 let myTweet = fmap (hitSource . head . hits . searchHits) result
7070 return myTweet
7171
72+searchExpectNoResults :: Search -> IO ()
73+searchExpectNoResults search = do
74+ reply <- searchByIndex testServer testIndex search
75+ let result = eitherDecode (responseBody reply) :: Either String (SearchResult Tweet)
76+ let emptyHits = fmap (hits . searchHits) result
77+ emptyHits `shouldBe` Right []
78+
7279main :: IO ()
7380main = hspec $ do
7481 describe "index create/delete API" $ do
@@ -117,17 +124,31 @@ main = hspec $ do
117124 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
118125 let geoFilter = GeoBoundingBoxFilter bbConstraint GeoFilterMemory
119126 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 []
127+ searchExpectNoResults search
124128
125129 it "returns document for geo distance query" $ do
126130 _ <- insertData
127− let geoConstraint = GeoConstraint "tweet.location" (LatLon 40.12 (-71.34))
131+ let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
128132 let distance = Distance 10.0 Miles
129133 let optimizeBbox = OptimizeGeoFilterType GeoFilterMemory
130− let geoFilter = GeoDistanceFilter geoConstraint distance SloppyArc optimizeBbox False
134+ let geoFilter = GeoDistanceFilter geoPoint distance SloppyArc optimizeBbox False
131135 let search = Search Nothing (Just geoFilter)
132136 myTweet <- searchTweet search
133137 myTweet `shouldBe` Right exampleTweet
138+
139+ it "returns document for geo distance range query" $ do
140+ _ <- insertData
141+ let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
142+ let distanceRange = DistanceRange (Distance 0.0 Miles) (Distance 10.0 Miles)
143+ let geoFilter = GeoDistanceRangeFilter geoPoint distanceRange
144+ let search = Search Nothing (Just geoFilter)
145+ myTweet <- searchTweet search
146+ myTweet `shouldBe` Right exampleTweet
147+
148+ it "doesn't return document for wild geo distance range query" $ do
149+ _ <- insertData
150+ let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
151+ let distanceRange = DistanceRange (Distance 100.0 Miles) (Distance 1000.0 Miles)
152+ let geoFilter = GeoDistanceRangeFilter geoPoint distanceRange
153+ let search = Search Nothing (Just geoFilter)
154+ searchExpectNoResults search