git.iko.soy/typeable/bloodhound
on master help sign in
WIP index aliases
ee94d8cMichael Xavier
src/Database/Bloodhound/Client.hs+29
@@ -27,6 +27,8 @@ module Database.Bloodhound.Client
27 , indexExists
27 , indexExists
28 , openIndex
28 , openIndex
29 , closeIndex
29 , closeIndex
30+ , updateIndexAliases
31+ , getIndexAliases
30 , putTemplate
32 , putTemplate
31 , templateExists
33 , templateExists
32 , deleteTemplate
34 , deleteTemplate
@@ -68,6 +70,7 @@ import Data.ByteString.Lazy.Builder
68import qualified Data.ByteString.Lazy.Char8 as L
70import qualified Data.ByteString.Lazy.Char8 as L
69import Data.Ix
71import Data.Ix
70import qualified Data.List as LS (filter)
72import qualified Data.List as LS (filter)
73+import qualified Data.List.NonEmpty as NE
71import Data.Maybe (fromMaybe, isJust)
74import Data.Maybe (fromMaybe, isJust)
72import Data.Monoid
75import Data.Monoid
73import Data.Text (Text)
76import Data.Text (Text)
@@ -279,6 +282,22 @@ existentialQuery url = do
279 reply <- head url
282 reply <- head url
280 return (reply, respIsTwoHunna reply)
283 return (reply, respIsTwoHunna reply)
281
284
285+parseEsResponse :: (MonadBH m, MonadThrow m, FromJSON a) => Reply
286+ -> m (Either EsError a)
287+parseEsResponse reply
288+ | respIsTwoHunna reply = case eitherDecode body of
289+ Right a -> return (Right a)
290+ Left e -> case eitherDecode body of
291+ Right e -> return (Left e)
292+ -- this case should not be possible
293+ Left _ -> explode
294+ | otherwise = explode
295+ where body = responseBody reply
296+ stat = responseStatus reply
297+ hdrs = responseHeaders reply
298+ cookies = responseCookieJar reply
299+ explode = throwM (StatusCodeException stat hdrs cookies)
300+
282-- | 'indexExists' enables you to check if an index exists. Returns 'Bool'
301-- | 'indexExists' enables you to check if an index exists. Returns 'Bool'
283-- in IO
302-- in IO
284--
303--
@@ -323,6 +342,16 @@ openIndex = openOrCloseIndexes OpenIndex
323closeIndex :: MonadBH m => IndexName -> m Reply
342closeIndex :: MonadBH m => IndexName -> m Reply
324closeIndex = openOrCloseIndexes CloseIndex
343closeIndex = openOrCloseIndexes CloseIndex
325
344
345+updateIndexAliases :: MonadBH m => NE.NonEmpty IndexAliasAction -> m Reply
346+updateIndexAliases actions = bindM2 post url (return body)
347+ where url = joinPath ["_aliases"]
348+ body = Just (encode bodyJSON)
349+ bodyJSON = object [ "actions" .= NE.toList actions]
350+
351+getIndexAliases :: (MonadBH m) => m (Either EsError IndexAliasesSummary)
352+getIndexAliases = liftIO . parseEsResponse =<< get =<< url
353+ where url = joinPath ["_aliases"]
354+
326-- | 'putTemplate' creates a template given an 'IndexTemplate' and a 'TemplateName'.
355-- | 'putTemplate' creates a template given an 'IndexTemplate' and a 'TemplateName'.
327-- Explained in further detail at
356-- Explained in further detail at
328-- <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html>
357-- <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html>
src/Database/Bloodhound/Types.hs+239−9
@@ -62,6 +62,16 @@ module Database.Bloodhound.Types
62 , EsResult(..)
62 , EsResult(..)
63 , EsResultFound(..)
63 , EsResultFound(..)
64 , EsError(..)
64 , EsError(..)
65+ , IndexAlias(..)
66+ , IndexAliasName(..)
67+ , IndexAliasAction(..)
68+ , IndexAliasCreate(..)
69+ , IndexAliasSummary(..)
70+ , IndexAliasesSummary(..)
71+ , AliasRouting(..)
72+ , SearchAliasRouting(..)
73+ , IndexAliasRouting(..)
74+ , RoutingValue(..)
65 , DocVersion
75 , DocVersion
66 , ExternalDocVersion(..)
76 , ExternalDocVersion(..)
67 , VersionControl(..)
77 , VersionControl(..)
@@ -237,9 +247,11 @@ import Control.Monad.Reader
237import Control.Monad.State
247import Control.Monad.State
238import Control.Monad.Writer
248import Control.Monad.Writer
239import Data.Aeson
249import Data.Aeson
240−import Data.Aeson.Types (Pair, emptyObject, parseMaybe)
250+import Data.Aeson.Types (Pair, Parser, emptyObject,
251+ parseMaybe)
241import qualified Data.ByteString.Lazy.Char8 as L
252import qualified Data.ByteString.Lazy.Char8 as L
253+import Data.Char
242−import qualified Data.HashMap.Strict as HM (union)
254+import qualified Data.HashMap.Strict as HM
243import Data.List (foldl', nub)
255import Data.List (foldl', nub)
244import Data.List.NonEmpty (NonEmpty (..), toList)
256import Data.List.NonEmpty (NonEmpty (..), toList)
245import qualified Data.Map.Strict as M
257import qualified Data.Map.Strict as M
@@ -247,6 +259,7 @@ import Data.Maybe
247import Data.Text (Text)
259import Data.Text (Text)
248import qualified Data.Text as T
260import qualified Data.Text as T
249import Data.Time.Clock (UTCTime)
261import Data.Time.Clock (UTCTime)
262+import qualified Data.Traversable as DT
250import qualified Data.Vector as V
263import qualified Data.Vector as V
251import GHC.Enum
264import GHC.Enum
252import GHC.Generics (Generic)
265import GHC.Generics (Generic)
@@ -430,6 +443,32 @@ data EsResultFound a = EsResultFound { _version :: DocVersion
430data EsError = EsError { errorStatus :: Int
443data EsError = EsError { errorStatus :: Int
431 , errorMessage :: Text } deriving (Eq, Show)
444 , errorMessage :: Text } deriving (Eq, Show)
432
445
446+data IndexAlias = IndexAlias { srcIndex :: IndexName
447+ , indexAlias :: IndexAliasName } deriving (Eq, Show)
448+
449+newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Show, ToJSON)
450+
451+data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
452+ | RemoveAlias IndexAlias deriving (Show, Eq)
453+
454+data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
455+ , aliasCreateFilter :: Maybe Filter}
456+ deriving (Show, Eq)
457+
458+data AliasRouting = AllAliasRouting RoutingValue
459+ | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
460+ deriving (Show, Eq)
461+
462+newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Show, Eq)
463+
464+newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Show, Eq, ToJSON, FromJSON)
465+
466+newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Show, Eq, ToJSON, FromJSON)
467+
468+newtype IndexAliasesSummary = IndexAliasesSummary [IndexAliasSummary]
469+
470+data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
471+ , indexAliasSummaryCreate :: IndexAliasCreate}
433
472
434{-| 'DocVersion' is an integer version number for a document between 1
473{-| 'DocVersion' is an integer version number for a document between 1
435and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
474and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
@@ -625,7 +664,7 @@ newtype QueryString = QueryString Text deriving (Eq, Generic, Show)
625{-| 'FieldName' is used all over the place wherever a specific field within
664{-| 'FieldName' is used all over the place wherever a specific field within
626 a document needs to be specified, usually in 'Query's or 'Filter's.
665 a document needs to be specified, usually in 'Query's or 'Filter's.
627-}
666-}
628−newtype FieldName = FieldName Text deriving (Eq, Show)
667+newtype FieldName = FieldName Text deriving (Eq, Show, FromJSON)
629
668
630
669
631{-| 'Script' is often used in place of 'FieldName' to specify more
670{-| 'Script' is often used in place of 'FieldName' to specify more
@@ -636,16 +675,16 @@ newtype Script = Script { scriptText :: Text } deriving (Eq, Show)
636{-| 'CacheName' is used in 'RegexpFilter' for describing the
675{-| 'CacheName' is used in 'RegexpFilter' for describing the
637 'CacheKey' keyed caching behavior.
676 'CacheKey' keyed caching behavior.
638-}
677-}
639−newtype CacheName = CacheName Text deriving (Eq, Show)
678+newtype CacheName = CacheName Text deriving (Eq, Show, FromJSON)
640
679
641{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
680{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
642-}
681-}
643newtype CacheKey =
682newtype CacheKey =
644− CacheKey Text deriving (Eq, Show)
683+ CacheKey Text deriving (Eq, Show, FromJSON)
645newtype Existence =
684newtype Existence =
646− Existence Bool deriving (Eq, Show)
685+ Existence Bool deriving (Eq, Show, FromJSON)
647newtype NullValue =
686newtype NullValue =
648− NullValue Bool deriving (Eq, Show)
687+ NullValue Bool deriving (Eq, Show, FromJSON)
649newtype CutoffFrequency =
688newtype CutoffFrequency =
650 CutoffFrequency Double deriving (Eq, Show, Generic)
689 CutoffFrequency Double deriving (Eq, Show, Generic)
651newtype Analyzer =
690newtype Analyzer =
@@ -1168,7 +1207,7 @@ data ZeroTermsQuery = ZeroTermsNone
1168data RangeExecution = RangeExecutionIndex
1207data RangeExecution = RangeExecutionIndex
1169 | RangeExecutionFielddata deriving (Eq, Show)
1208 | RangeExecutionFielddata deriving (Eq, Show)
1170
1209
1171−newtype Regexp = Regexp Text deriving (Eq, Show)
1210+newtype Regexp = Regexp Text deriving (Eq, Show, FromJSON)
1172
1211
1173data RegexpFlags = AllRegexpFlags
1212data RegexpFlags = AllRegexpFlags
1174 | NoRegexpFlags
1213 | NoRegexpFlags
@@ -1641,6 +1680,75 @@ instance ToJSON Filter where
1641 , "_cache" .= cache
1680 , "_cache" .= cache
1642 , "_cache_key" .= cacheKey]]
1681 , "_cache_key" .= cacheKey]]
1643
1682
1683+instance FromJSON Filter where
1684+ parseJSON = withObject "Filter" parse
1685+ where parse o = andFilter `taggedWith` "and"
1686+ <|> orFilter `taggedWith` "or"
1687+ <|> notFilter `taggedWith` "not"
1688+ <|> identityFilter `taggedWith` "match_all"
1689+ <|> boolFilter `taggedWith` "bool"
1690+ <|> existsFilter `taggedWith` "exists"
1691+ <|> geoBoundingBoxFilter `taggedWith` "geo_bounding_box"
1692+ <|> geoDistanceFilter `taggedWith` "geo_distance"
1693+ <|> geoDistanceRangeFilter `taggedWith` "geo_distance_range"
1694+ <|> geoPolygonFilter `taggedWith` "geo_polygon"
1695+ <|> idsFilter `taggedWith` "ids"
1696+ <|> limitFilter `taggedWith` "limit"
1697+ <|> missingFilter `taggedWith` "missing"
1698+ <|> prefixFilter `taggedWith` "prefix"
1699+ <|> queryFilter `taggedWith` "query"
1700+ <|> fqueryFilter `taggedWith` "fquery"
1701+ <|> rangeFilter `taggedWith` "range"
1702+ <|> regexpFilter `taggedWith` "regexp"
1703+ <|> termFilter `taggedWith` "term"
1704+ where taggedWith parser k = parser =<< o .: k
1705+ andFilter o = AndFilter <$> o .: "filters"
1706+ <*> o .:? "_cache" .!= defaultCache
1707+ orFilter o = OrFilter <$> o .: "filters"
1708+ <*> o .:? "_cache" .!= defaultCache
1709+ notFilter o = NotFilter <$> o .: "filters"
1710+ <*> o .: "_cache" .!= defaultCache
1711+ identityFilter () = pure IdentityFilter
1712+ boolFilter = pure . BoolFilter
1713+ existsFilter o = ExistsFilter <$> o .: "field"
1714+ geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
1715+ geoDistanceFilter o = flip fieldTagged o $ \fn o' -> do
1716+ gp <- GeoPoint fn <$> parseJSON (Object o')
1717+ GeoDistanceFilter gp <$> o .: "distance"
1718+ <*> o .: "distance_type"
1719+ <*> o .: "optimize_bbox"
1720+ <*> o .:? "_cache" .!= defaultCache
1721+ geoDistanceRangeFilter o = flip fieldTagged o $ \fn o' -> do
1722+ gp <- GeoPoint fn <$> parseJSON (Object o')
1723+ rng <- DistanceRange <$> o .: "from" <*> o .: "to"
1724+ return (GeoDistanceRangeFilter gp rng)
1725+ geoPolygonFilter = fieldTagged $ \fn o -> GeoPolygonFilter fn <$> o .: "points"
1726+ idsFilter o = IdsFilter <$> o .: "type"
1727+ <*> o .: "values"
1728+ limitFilter o = LimitFilter <$> o .: "value"
1729+ missingFilter o = MissingFilter <$> o .: "field"
1730+ <*> o .: "existence"
1731+ <*> o .: "null_value"
1732+ prefixFilter o = fieldTagged $ \fn o' -> PrefixFilter fn <$> parseJSON (Object o')
1733+ <*> o .:? "_cache" .!= defaultCache
1734+ queryFilter q = pure (QueryFilter q False)
1735+ fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
1736+ rangeFilter o = fieldTagged $ \fn o' -> RangeFilter fn <$> parseJSON (Object o')
1737+ <*> o .: "execution"
1738+ <*> o .:? "_cache" .!= defaultCache
1739+ regexpFilter = fieldTagged $ \fn o -> RegexpFilter fn <$> o .: "value"
1740+ <*> o .: "flags"
1741+ <*> o .: "_name"
1742+ <*> o .:? "_cache" .!= defaultCache
1743+ <*> o .: "_cache_key"
1744+ termFilter o = flip fieldTagged o $ \(FieldName fn) o' -> do
1745+ trm <- Term fn <$> parseJSON (Object o')
1746+ TermFilter trm <$> o .: "_cache" .!= defaultCache
1747+ --TODO: should this enforce there only being 1 key?
1748+ fieldTagged f o = case HM.toList o of
1749+ [(k, Object o')] -> f (FieldName k) o'
1750+ _ -> fail "Expected object with 1 field named key"
1751+
1644instance ToJSON GeoPoint where
1752instance ToJSON GeoPoint where
1645 toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
1753 toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
1646 object [ geoPointField .= geoPointLatLon ]
1754 object [ geoPointField .= geoPointLatLon ]
@@ -1827,6 +1935,9 @@ instance ToJSON RangeQuery where
1827 object [ fieldName .= conjoined ]
1935 object [ fieldName .= conjoined ]
1828 where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
1936 where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
1829
1937
1938+instance FromJSON RangeValue where
1939+ parseJSON = withObject "RangeValue" parse
1940+ where parse o = undefined
1830
1941
1831instance ToJSON PrefixQuery where
1942instance ToJSON PrefixQuery where
1832 toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
1943 toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
@@ -2135,7 +2246,6 @@ instance FromJSON MappingName where
2135instance FromJSON DocId where
2246instance FromJSON DocId where
2136 parseJSON = genericParseJSON defaultOptions
2247 parseJSON = genericParseJSON defaultOptions
2137
2248
2138−
2139instance FromJSON Status where
2249instance FromJSON Status where
2140 parseJSON (Object v) = Status <$>
2250 parseJSON (Object v) = Status <$>
2141 v .:? "ok" <*>
2251 v .:? "ok" <*>
@@ -2188,6 +2298,58 @@ instance FromJSON EsError where
2188 v .: "error"
2298 v .: "error"
2189 parseJSON _ = empty
2299 parseJSON _ = empty
2190
2300
2301+instance FromJSON IndexAliasesSummary where
2302+ parseJSON = withObject "IndexAliasesSummary" parse
2303+ where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)
2304+ go ixn = withObject "index aliases" $ \ia -> do
2305+ aliases <- ia .: "aliases"
2306+ forM (HM.toList aliases) $ \(aName, v) -> do
2307+ let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))
2308+ IndexAliasSummary indexAlias <$> parseJSON v
2309+
2310+
2311+instance ToJSON IndexAliasAction where
2312+ toJSON (AddAlias ia opts) = object ["add" .= (iaObj <> optsObj)]
2313+ where Object iaObj = toJSON ia
2314+ Object optsObj = toJSON opts
2315+ toJSON (RemoveAlias ia) = object ["remove" .= iaObj]
2316+ where Object iaObj = toJSON ia
2317+
2318+instance ToJSON IndexAlias where
2319+ toJSON IndexAlias {..} = object ["index" .= srcIndex
2320+ , "alias" .= indexAlias
2321+ ]
2322+
2323+instance ToJSON IndexAliasCreate where
2324+ toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)
2325+ where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter
2326+ Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting
2327+
2328+instance ToJSON AliasRouting where
2329+ toJSON (AllAliasRouting v) = object ["routing" .= v]
2330+ toJSON (GranularAliasRouting srch idx) = object (catMaybes prs)
2331+ where prs = [("search_routing" .=) <$> srch
2332+ ,("index_routing" .=) <$> idx]
2333+
2334+instance FromJSON AliasRouting where
2335+ parseJSON = withObject "AliasRouting" parse
2336+ where parse o = parseAll o <|> parseGranular o
2337+ parseAll o = AllAliasRouting <$> o .: "routing"
2338+ parseGranular o = GranularAliasRouting <$> o .:? "search_routing"
2339+ <*> o .:? "index_routing"
2340+
2341+instance FromJSON IndexAliasCreate where
2342+ parseJSON v = withObject "IndexAliasCreate" parse v
2343+ where parse o = IndexAliasCreate <$> parseJSON v
2344+ <*> o .:? "filter"
2345+
2346+instance ToJSON SearchAliasRouting where
2347+ toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
2348+
2349+instance FromJSON SearchAliasRouting where
2350+ parseJSON = withText "SearchAliasRouting" parse
2351+ where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
2352+
2191instance ToJSON Search where
2353instance ToJSON Search where
2192 toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
2354 toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
2193 omitNulls [ "query" .= query
2355 omitNulls [ "query" .= query
@@ -2290,6 +2452,9 @@ nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
2290 [ "fragment_size" .= npFragSize
2452 [ "fragment_size" .= npFragSize
2291 , "number_of_fragments" .= npNumOfFrags]
2453 , "number_of_fragments" .= npNumOfFrags]
2292
2454
2455+parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
2456+parseNEJSON [] = fail "Expected non-empty list"
2457+parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
2293
2458
2294
2459
2295instance ToJSON HighlightEncoder where
2460instance ToJSON HighlightEncoder where
@@ -2351,6 +2516,13 @@ instance ToJSON Distance where
2351 (String unitText) = toJSON dUnit
2516 (String unitText) = toJSON dUnit
2352 boltedTogether = mappend coefText unitText
2517 boltedTogether = mappend coefText unitText
2353
2518
2519+instance FromJSON Distance where
2520+ parseJSON = withText "Distance" parse
2521+ where parse t = Distance <$> parseCoeff nT
2522+ <*> parseJSON (String unitT)
2523+ where (nT, unitT) = T.span isNumber t
2524+ parseCoeff "" = fail "Empty string cannot be parsed as number"
2525+ parseCoeff s = return (read (T.unpack s))
2354
2526
2355instance ToJSON DistanceUnit where
2527instance ToJSON DistanceUnit where
2356 toJSON Miles = String "mi"
2528 toJSON Miles = String "mi"
@@ -2364,16 +2536,42 @@ instance ToJSON DistanceUnit where
2364 toJSON NauticalMiles = String "nmi"
2536 toJSON NauticalMiles = String "nmi"
2365
2537
2366
2538
2539+instance FromJSON DistanceUnit where
2540+ parseJSON = withText "DistanceUnit" parse
2541+ where parse "mi" = pure Miles
2542+ parse "yd" = pure Yards
2543+ parse "ft" = pure Feet
2544+ parse "in" = pure Inches
2545+ parse "km" = pure Kilometers
2546+ parse "m" = pure Meters
2547+ parse "cm" = pure Centimeters
2548+ parse "mm" = pure Millimeters
2549+ parse "nmi" = pure NauticalMiles
2550+ parse u = fail ("Unrecognized DistanceUnit: " <> show u)
2551+
2367instance ToJSON DistanceType where
2552instance ToJSON DistanceType where
2368 toJSON Arc = String "arc"
2553 toJSON Arc = String "arc"
2369 toJSON SloppyArc = String "sloppy_arc"
2554 toJSON SloppyArc = String "sloppy_arc"
2370 toJSON Plane = String "plane"
2555 toJSON Plane = String "plane"
2371
2556
2557+instance FromJSON DistanceType where
2558+ parseJSON = withText "DistanceType" parse
2559+ where parse "arc" = pure Arc
2560+ parse "sloppy_arc" = pure SloppyArc
2561+ parse "plane" = pure Plane
2562+ parse t = fail ("Unrecognized DistanceType: " <> show t)
2563+
2372
2564
2373instance ToJSON OptimizeBbox where
2565instance ToJSON OptimizeBbox where
2374 toJSON NoOptimizeBbox = String "none"
2566 toJSON NoOptimizeBbox = String "none"
2375 toJSON (OptimizeGeoFilterType gft) = toJSON gft
2567 toJSON (OptimizeGeoFilterType gft) = toJSON gft
2376
2568
2569+instance FromJSON OptimizeBbox where
2570+ parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
2571+ <|> parseOptimize v
2572+ where parseNoOptimize "none" = pure NoOptimizeBbox
2573+ parseNoOptimize _ = mzero
2574+ parseOptimize = fmap OptimizeGeoFilterType . parseJSON
2377
2575
2378instance ToJSON GeoBoundingBoxConstraint where
2576instance ToJSON GeoBoundingBoxConstraint where
2379 toJSON (GeoBoundingBoxConstraint
2577 toJSON (GeoBoundingBoxConstraint
@@ -2387,6 +2585,11 @@ instance ToJSON GeoFilterType where
2387 toJSON GeoFilterMemory = String "memory"
2585 toJSON GeoFilterMemory = String "memory"
2388 toJSON GeoFilterIndexed = String "indexed"
2586 toJSON GeoFilterIndexed = String "indexed"
2389
2587
2588+instance FromJSON GeoFilterType where
2589+ parseJSON = withText "GeoFilterType" parse
2590+ where parse "memory" = pure GeoFilterMemory
2591+ parse "indexed" = pure GeoFilterIndexed
2592+ parse t = fail ("Unrecognized GeoFilterType: " <> show t)
2390
2593
2391instance ToJSON GeoBoundingBox where
2594instance ToJSON GeoBoundingBox where
2392 toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
2595 toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
@@ -2399,6 +2602,10 @@ instance ToJSON LatLon where
2399 object ["lat" .= lLat
2602 object ["lat" .= lLat
2400 , "lon" .= lLon]
2603 , "lon" .= lLon]
2401
2604
2605+instance FromJSON LatLon where
2606+ parseJSON = withObject "LatLon" parse
2607+ where parse o = LatLon <$> o .: "lat"
2608+ <*> o .: "lon"
2402
2609
2403-- index for smaller ranges, fielddata for longer ranges
2610-- index for smaller ranges, fielddata for longer ranges
2404instance ToJSON RangeExecution where
2611instance ToJSON RangeExecution where
@@ -2406,6 +2613,12 @@ instance ToJSON RangeExecution where
2406 toJSON RangeExecutionFielddata = "fielddata"
2613 toJSON RangeExecutionFielddata = "fielddata"
2407
2614
2408
2615
2616+instance FromJSON RangeExecution where
2617+ parseJSON = withText "RangeExecution" parse
2618+ where parse "index" = pure RangeExecutionIndex
2619+ parse "fielddata" = pure RangeExecutionFielddata
2620+ parse t = error ("Unrecognized RangeExecution " <> show t)
2621+
2409instance ToJSON RegexpFlags where
2622instance ToJSON RegexpFlags where
2410 toJSON AllRegexpFlags = String "ALL"
2623 toJSON AllRegexpFlags = String "ALL"
2411 toJSON NoRegexpFlags = String "NONE"
2624 toJSON NoRegexpFlags = String "NONE"
@@ -2418,6 +2631,23 @@ instance ToJSON RegexpFlags where
2418 flagStr Intersection = "INTERSECTION"
2631 flagStr Intersection = "INTERSECTION"
2419 flagStr Interval = "INTERVAL"
2632 flagStr Interval = "INTERVAL"
2420
2633
2634+instance FromJSON RegexpFlags where
2635+ parseJSON = withText "RegexpFlags" parse
2636+ where parse "ALL" = pure AllRegexpFlags
2637+ parse "NONE" = pure NoRegexpFlags
2638+ parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
2639+
2640+instance FromJSON RegexpFlag where
2641+ parseJSON = withText "RegexpFlag" parse
2642+ where parse "ANYSTRING" = pure AnyString
2643+ parse "ANYSTRING" = pure AnyString
2644+ parse "AUTOMATON" = pure Automaton
2645+ parse "COMPLEMENT" = pure Complement
2646+ parse "EMPTY" = pure Empty
2647+ parse "INTERSECTION" = pure Intersection
2648+ parse "INTERVAL" = pure Interval
2649+ parse f = fail ("Unknown RegexpFlag: " <> show f)
2650+
2421instance ToJSON Term where
2651instance ToJSON Term where
2422 toJSON (Term field value) = object ["term" .= object
2652 toJSON (Term field value) = object ["term" .= object
2423 [field .= value]]
2653 [field .= value]]