git.iko.soy/typeable/bloodhound
on master help sign in
GeoPolygonFilter, positive and negative validation
a800719Chris Allen
Database/Bloodhound/Client.hs+6
@@ -374,6 +374,7 @@ data Filter = AndFilter [Filter] Cache
374 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
374 | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
375 | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
375 | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
376 | GeoDistanceRangeFilter GeoPoint DistanceRange
376 | GeoDistanceRangeFilter GeoPoint DistanceRange
377+ | GeoPolygonFilter FieldName [LatLon]
377 deriving (Eq, Show)
378 deriving (Eq, Show)
378
379
379class Monoid a => Seminearring a where
380class Monoid a => Seminearring a where
@@ -431,6 +432,11 @@ instance ToJSON Filter where
431 , "to" .= toJSON distanceTo
432 , "to" .= toJSON distanceTo
432 , geoField .= toJSON latLon]]
433 , geoField .= toJSON latLon]]
433
434
435+ toJSON (GeoPolygonFilter geoField latLons) =
436+ object ["geo_polygon" .=
437+ object [geoField .=
438+ object ["points" .= fmap toJSON latLons]]]
439+
434instance ToJSON GeoPoint where
440instance ToJSON GeoPoint where
435 toJSON (GeoPoint geoField latLon) =
441 toJSON (GeoPoint geoField latLon) =
436 object [geoField .= toJSON latLon]
442 object [geoField .= toJSON latLon]
tests/tests.hs+35−9
@@ -15,11 +15,14 @@ import Network.HTTP.Conduit
15import qualified Network.HTTP.Types.Status as NHTS
15import qualified Network.HTTP.Types.Status as NHTS
16import Test.Hspec
16import Test.Hspec
17
17
18−
19testServer = Server "http://localhost:9200"
18testServer = Server "http://localhost:9200"
20testIndex = "twitter"
19testIndex = "twitter"
21testMapping = "tweet"
20testMapping = "tweet"
21+
22+validateStatus resp expected =
22−validateStatus resp expected = (NHTS.statusCode $ responseStatus resp) `shouldBe` (expected :: Int)
23+ (NHTS.statusCode $ responseStatus resp)
24+ `shouldBe` (expected :: Int)
25+
23createExampleIndex = createIndex testServer defaultIndexSettings testIndex
26createExampleIndex = createIndex testServer defaultIndexSettings testIndex
24deleteExampleIndex = deleteIndex testServer testIndex
27deleteExampleIndex = deleteIndex testServer testIndex
25
28
@@ -78,6 +81,7 @@ searchExpectNoResults search = do
78
81
79main :: IO ()
82main :: IO ()
80main = hspec $ do
83main = hspec $ do
84+
81 describe "index create/delete API" $ do
85 describe "index create/delete API" $ do
82 it "creates and then deletes the requested index" $ do
86 it "creates and then deletes the requested index" $ do
83 -- priming state.
87 -- priming state.
@@ -91,7 +95,8 @@ main = hspec $ do
91 it "indexes, gets, and then deletes the generated document" $ do
95 it "indexes, gets, and then deletes the generated document" $ do
92 _ <- insertData
96 _ <- insertData
93 docInserted <- getDocument testServer testIndex testMapping "1"
97 docInserted <- getDocument testServer testIndex testMapping "1"
98+ let newTweet = eitherDecode
94− let newTweet = eitherDecode (responseBody docInserted) :: Either String (EsResult Tweet)
99+ (responseBody docInserted) :: Either String (EsResult Tweet)
95 fmap _source newTweet `shouldBe` Right exampleTweet
100 fmap _source newTweet `shouldBe` Right exampleTweet
96
101
97 describe "filtering API" $ do
102 describe "filtering API" $ do
@@ -103,13 +108,13 @@ main = hspec $ do
103 myTweet <- searchTweet search
108 myTweet <- searchTweet search
104 myTweet `shouldBe` Right exampleTweet
109 myTweet `shouldBe` Right exampleTweet
105
110
106− it "returns document for existential query" $ do
111+ it "returns document for existential filter" $ do
107 _ <- insertData
112 _ <- insertData
108 let search = Search Nothing (Just (ExistsFilter "user"))
113 let search = Search Nothing (Just (ExistsFilter "user"))
109 myTweet <- searchTweet search
114 myTweet <- searchTweet search
110 myTweet `shouldBe` Right exampleTweet
115 myTweet `shouldBe` Right exampleTweet
111
116
112− it "returns document for geo boundingbox query" $ do
117+ it "returns document for geo boundingbox filter" $ do
113 _ <- insertData
118 _ <- insertData
114 let box = GeoBoundingBox (LatLon 40.73 (-74.1)) (LatLon 40.10 (-71.12))
119 let box = GeoBoundingBox (LatLon 40.73 (-74.1)) (LatLon 40.10 (-71.12))
115 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
120 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
@@ -118,7 +123,7 @@ main = hspec $ do
118 myTweet <- searchTweet search
123 myTweet <- searchTweet search
119 myTweet `shouldBe` Right exampleTweet
124 myTweet `shouldBe` Right exampleTweet
120
125
121− it "doesn't return document for nonsensical boundingbox query" $ do
126+ it "doesn't return document for nonsensical boundingbox filter" $ do
122 _ <- insertData
127 _ <- insertData
123 let box = GeoBoundingBox (LatLon 0.73 (-4.1)) (LatLon 0.10 (-1.12))
128 let box = GeoBoundingBox (LatLon 0.73 (-4.1)) (LatLon 0.10 (-1.12))
124 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
129 let bbConstraint = GeoBoundingBoxConstraint "tweet.location" box False
@@ -126,7 +131,7 @@ main = hspec $ do
126 let search = Search Nothing (Just geoFilter)
131 let search = Search Nothing (Just geoFilter)
127 searchExpectNoResults search
132 searchExpectNoResults search
128
133
129− it "returns document for geo distance query" $ do
134+ it "returns document for geo distance filter" $ do
130 _ <- insertData
135 _ <- insertData
131 let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
136 let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
132 let distance = Distance 10.0 Miles
137 let distance = Distance 10.0 Miles
@@ -136,7 +141,7 @@ main = hspec $ do
136 myTweet <- searchTweet search
141 myTweet <- searchTweet search
137 myTweet `shouldBe` Right exampleTweet
142 myTweet `shouldBe` Right exampleTweet
138
143
139− it "returns document for geo distance range query" $ do
144+ it "returns document for geo distance range filter" $ do
140 _ <- insertData
145 _ <- insertData
141 let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
146 let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
142 let distanceRange = DistanceRange (Distance 0.0 Miles) (Distance 10.0 Miles)
147 let distanceRange = DistanceRange (Distance 0.0 Miles) (Distance 10.0 Miles)
@@ -145,10 +150,31 @@ main = hspec $ do
145 myTweet <- searchTweet search
150 myTweet <- searchTweet search
146 myTweet `shouldBe` Right exampleTweet
151 myTweet `shouldBe` Right exampleTweet
147
152
148− it "doesn't return document for wild geo distance range query" $ do
153+ it "doesn't return document for wild geo distance range filter" $ do
149 _ <- insertData
154 _ <- insertData
150 let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
155 let geoPoint = GeoPoint "tweet.location" (LatLon 40.12 (-71.34))
151 let distanceRange = DistanceRange (Distance 100.0 Miles) (Distance 1000.0 Miles)
156 let distanceRange = DistanceRange (Distance 100.0 Miles) (Distance 1000.0 Miles)
152 let geoFilter = GeoDistanceRangeFilter geoPoint distanceRange
157 let geoFilter = GeoDistanceRangeFilter geoPoint distanceRange
153 let search = Search Nothing (Just geoFilter)
158 let search = Search Nothing (Just geoFilter)
154 searchExpectNoResults search
159 searchExpectNoResults search
160+
161+ it "returns document for geo polygon filter" $ do
162+ _ <- insertData
163+ let points = [LatLon 40.0 (-70.00),
164+ LatLon 40.0 (-72.00),
165+ LatLon 41.0 (-70.00),
166+ LatLon 41.0 (-72.00)]
167+ let geoFilter = GeoPolygonFilter "tweet.location" points
168+ let search = Search Nothing (Just geoFilter)
169+ myTweet <- searchTweet search
170+ myTweet `shouldBe` Right exampleTweet
171+
172+ it "doesn't return document for bad geo polygon filter" $ do
173+ _ <- insertData
174+ let points = [LatLon 40.0 (-70.00),
175+ LatLon 40.0 (-71.00),
176+ LatLon 41.0 (-70.00),
177+ LatLon 41.0 (-71.00)]
178+ let geoFilter = GeoPolygonFilter "tweet.location" points
179+ let search = Search Nothing (Just geoFilter)
180+ searchExpectNoResults search