git.iko.soy/typeable/bloodhound
on master help sign in
geo distance range positive and negative validation
0c84e67Chris Allen
Database/Bloodhound/Client.hs+22−10
@@ -28,13 +28,14 @@ module Database.Bloodhound.Client
28 , Seminearring(..)
28 , Seminearring(..)
29 , BoolMatch(..)
29 , BoolMatch(..)
30 , Term(..)
30 , Term(..)
31− , GeoConstraint(..)
31+ , GeoPoint(..)
32 , GeoBoundingBoxConstraint(..)
32 , GeoBoundingBoxConstraint(..)
33 , GeoBoundingBox(..)
33 , GeoBoundingBox(..)
34 , GeoFilterType(..)
34 , GeoFilterType(..)
35 , Distance(..)
35 , Distance(..)
36 , DistanceUnit(..)
36 , DistanceUnit(..)
37 , DistanceType(..)
37 , DistanceType(..)
38+ , DistanceRange(..)
38 , OptimizeBbox(..)
39 , OptimizeBbox(..)
39 , LatLon(..)
40 , LatLon(..)
40 )
41 )
@@ -371,7 +372,8 @@ data Filter = AndFilter [Filter] Cache
371 | BoolFilter BoolMatch
372 | BoolFilter BoolMatch
372 | ExistsFilter FieldName -- always cached
373 | ExistsFilter FieldName -- always cached
373 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
374 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
374− | GeoDistanceFilter GeoConstraint Distance DistanceType OptimizeBbox Cache
375+ | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
376+ | GeoDistanceRangeFilter GeoPoint DistanceRange
375 deriving (Eq, Show)
377 deriving (Eq, Show)
376
378
377class Monoid a => Seminearring a where
379class Monoid a => Seminearring a where
@@ -413,18 +415,24 @@ instance ToJSON Filter where
413 object ["geo_bounding_box" .= toJSON bbConstraint
415 object ["geo_bounding_box" .= toJSON bbConstraint
414 , "type" .= toJSON filterType]
416 , "type" .= toJSON filterType]
415
417
416− toJSON (GeoDistanceFilter (GeoConstraint geoField latLon)
418+ toJSON (GeoDistanceFilter (GeoPoint geoField latLon)
417 distance distanceType optimizeBbox cache) =
419 distance distanceType optimizeBbox cache) =
418 object ["geo_distance" .=
420 object ["geo_distance" .=
419 object ["distance" .= toJSON distance
421 object ["distance" .= toJSON distance
420 , "distance_type" .= toJSON distanceType
422 , "distance_type" .= toJSON distanceType
421 , "optimize_bbox" .= optimizeBbox
423 , "optimize_bbox" .= optimizeBbox
422 , geoField .= toJSON latLon
424 , geoField .= toJSON latLon
423− , "_cache" .= cache
425+ , "_cache" .= cache]]
424− ]]
425
426
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+
426−instance ToJSON GeoConstraint where
434+instance ToJSON GeoPoint where
427− toJSON (GeoConstraint geoField latLon) =
435+ toJSON (GeoPoint geoField latLon) =
428 object [geoField .= toJSON latLon]
436 object [geoField .= toJSON latLon]
429
437
430showText :: Show a => a -> Text
438showText :: Show a => a -> Text
@@ -513,9 +521,9 @@ data GeoBoundingBoxConstraint =
513 , bbConstraintcache :: Cache
521 , bbConstraintcache :: Cache
514 } deriving (Eq, Show)
522 } deriving (Eq, Show)
515
523
516−data GeoConstraint =
524+data GeoPoint =
517− GeoConstraint { geoField :: FieldName
525+ GeoPoint { geoField :: FieldName
518− , latLon :: LatLon} deriving (Eq, Show)
526+ , latLon :: LatLon} deriving (Eq, Show)
519
527
520data DistanceUnit = Miles
528data DistanceUnit = Miles
521 | Yards
529 | Yards
@@ -538,6 +546,10 @@ data Distance =
538 Distance { coefficient :: Double
546 Distance { coefficient :: Double
539 , unit :: DistanceUnit } deriving (Eq, Show)
547 , unit :: DistanceUnit } deriving (Eq, Show)
540
548
549+data DistanceRange =
550+ DistanceRange { distanceFrom :: Distance
551+ , distanceTo :: Distance } deriving (Eq, Show)
552+
541data FromJSON a => SearchResult a =
553data FromJSON a => SearchResult a =
542 SearchResult { took :: Int
554 SearchResult { took :: Int
543 , timedOut :: Bool
555 , timedOut :: Bool
tests/tests.hs+27−6
@@ -69,6 +69,13 @@ searchTweet search = do
69 let myTweet = fmap (hitSource . head . hits . searchHits) result
69 let myTweet = fmap (hitSource . head . hits . searchHits) result
70 return myTweet
70 return myTweet
71
71
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+
72main :: IO ()
79main :: IO ()
73main = hspec $ do
80main = hspec $ do
74 describe "index create/delete API" $ do
81 describe "index create/delete API" $ do
@@ -117,17 +124,31 @@ main = hspec $ do
117 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
124 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
118 let geoFilter = GeoBoundingBoxFilter bbConstraint GeoFilterMemory
125 let geoFilter = GeoBoundingBoxFilter bbConstraint GeoFilterMemory
119 let search = Search Nothing (Just geoFilter)
126 let search = Search Nothing (Just geoFilter)
120− reply <- searchByIndex testServer testIndex search
127+ searchExpectNoResults search
121− let result = eitherDecode (responseBody reply) :: Either String (SearchResult Tweet)
122− let emptyHits = fmap (hits . searchHits) result
123− emptyHits `shouldBe` Right []
124
128
125 it "returns document for geo distance query" $ do
129 it "returns document for geo distance query" $ do
126 _ <- insertData
130 _ <- insertData
127− let geoConstraint = GeoConstraint "tweet.location" (LatLon 40.12 (-71.34))
131+ let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
128 let distance = Distance 10.0 Miles
132 let distance = Distance 10.0 Miles
129 let optimizeBbox = OptimizeGeoFilterType GeoFilterMemory
133 let optimizeBbox = OptimizeGeoFilterType GeoFilterMemory
130− let geoFilter = GeoDistanceFilter geoConstraint distance SloppyArc optimizeBbox False
134+ let geoFilter = GeoDistanceFilter geoPoint distance SloppyArc optimizeBbox False
131 let search = Search Nothing (Just geoFilter)
135 let search = Search Nothing (Just geoFilter)
132 myTweet <- searchTweet search
136 myTweet <- searchTweet search
133 myTweet `shouldBe` Right exampleTweet
137 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