@@ -251,6 +251,7 @@ import Data.Aeson.Types (Pair, Parser, emptyObject,
251 parseMaybe)
251 parseMaybe)
252import qualified Data.ByteString.Lazy.Char8 as L
252import qualified Data.ByteString.Lazy.Char8 as L
253import Data.Char
253import Data.Char
254+import Data.Hashable (Hashable)
254import qualified Data.HashMap.Strict as HM
255import qualified Data.HashMap.Strict as HM
255import Data.List (foldl', nub)
256import Data.List (foldl', nub)
256import Data.List.NonEmpty (NonEmpty (..), toList)
257import Data.List.NonEmpty (NonEmpty (..), toList)
@@ -266,6 +267,8 @@ import GHC.Generics (Generic)
266import Network.HTTP.Client
267import Network.HTTP.Client
267import qualified Network.HTTP.Types.Method as NHTM
268import qualified Network.HTTP.Types.Method as NHTM
269import Database.Bloodhound.Types.Class
272import Database.Bloodhound.Types.Class
@@ -711,8 +714,6 @@ newtype BoostTerms =
712newtype MinimumMatch =
715newtype MinimumMatch =
713 MinimumMatch Int deriving (Eq, Show, Generic, ToJSON, FromJSON)
716 MinimumMatch Int deriving (Eq, Show, Generic, ToJSON, FromJSON)
714−newtype MinimumMatchText =
715− MinimumMatchText Text deriving (Eq, Show, ToJSON, FromJSON)
716newtype DisableCoord =
717newtype DisableCoord =
717 DisableCoord Bool deriving (Eq, Show, Generic, ToJSON, FromJSON)
718 DisableCoord Bool deriving (Eq, Show, Generic, ToJSON, FromJSON)
718newtype IgnoreTermFrequency =
719newtype IgnoreTermFrequency =
@@ -1722,18 +1723,24 @@ instance FromJSON Filter where
1722 <*> o .:? "_cache" .!= defaultCache
1723 <*> o .:? "_cache" .!= defaultCache
1723 orFilter o = OrFilter <$> o .: "filters"
1724 orFilter o = OrFilter <$> o .: "filters"
1724 <*> o .:? "_cache" .!= defaultCache
1725 <*> o .:? "_cache" .!= defaultCache
1725− notFilter o = NotFilter <$> o .: "filters"
1726+ notFilter o = NotFilter <$> o .: "filter"
1726 <*> o .: "_cache" .!= defaultCache
1727 <*> o .: "_cache" .!= defaultCache
1728+ identityFilter :: Object -> Parser Filter
1727− identityFilter () = pure IdentityFilter
1730+ | HM.null m = pure IdentityFilter
1731+ | otherwise = fail ("Identityfilter expected empty object but got " <> show m)
1728 boolFilter = pure . BoolFilter
1732 boolFilter = pure . BoolFilter
1729 existsFilter o = ExistsFilter <$> o .: "field"
1733 existsFilter o = ExistsFilter <$> o .: "field"
1730 geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
1734 geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
1731− geoDistanceFilter o = flip fieldTagged o $ \fn o' -> do
1735+ geoDistanceFilter o = do
1736+ case HM.toList (deleteSeveral ["distance", "distance_type", "optimize_bbox", "_cache"] o) of
1732− gp <- GeoPoint fn <$> parseJSON (Object o')
1738+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
1733− GeoDistanceFilter gp <$> o .: "distance"
1739+ GeoDistanceFilter gp <$> o .: "distance"
1734− <*> o .: "distance_type"
1740+ <*> o .: "distance_type"
1735− <*> o .: "optimize_bbox"
1741+ <*> o .: "optimize_bbox"
1736− <*> o .:? "_cache" .!= defaultCache
1742+ <*> o .:? "_cache" .!= defaultCache
1743+ _ -> fail "Could not find GeoDistanceFilter field name"
1737 geoDistanceRangeFilter o = flip fieldTagged o $ \fn o' -> do
1744 geoDistanceRangeFilter o = flip fieldTagged o $ \fn o' -> do
1738 gp <- GeoPoint fn <$> parseJSON (Object o')
1745 gp <- GeoPoint fn <$> parseJSON (Object o')
1739 rng <- DistanceRange <$> o .: "from" <*> o .: "to"
1746 rng <- DistanceRange <$> o .: "from" <*> o .: "to"
@@ -1745,21 +1752,27 @@ instance FromJSON Filter where
1745 missingFilter o = MissingFilter <$> o .: "field"
1752 missingFilter o = MissingFilter <$> o .: "field"
1746 <*> o .: "existence"
1753 <*> o .: "existence"
1747 <*> o .: "null_value"
1754 <*> o .: "null_value"
1748− prefixFilter o = flip fieldTagged o $ \fn o' -> PrefixFilter fn <$> parseJSON (Object o')
1755+ prefixFilter o = case HM.toList (HM.delete "_cache" o) of
1749− <*> o .:? "_cache" .!= defaultCache
1756+ [(fn, String v)] -> PrefixFilter (FieldName fn) v <$> o .:? "_cache" .!= defaultCache
1757+ _ -> fail "Could not parse PrefixFilter"
1750 queryFilter q = pure (QueryFilter q False)
1759 queryFilter q = pure (QueryFilter q False)
1751 fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
1760 fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
1752− rangeFilter o = flip fieldTagged o $ \fn o' -> RangeFilter fn <$> parseJSON (Object o')
1761+ rangeFilter o = case HM.toList (deleteSeveral ["execution", "_cache"] o) of
1762+ [(fn, v)] -> RangeFilter (FieldName fn)
1753− <*> o .: "execution"
1764+ <*> o .: "execution"
1754− <*> o .:? "_cache" .!= defaultCache
1765+ <*> o .:? "_cache" .!= defaultCache
1766+ _ -> fail "Could not find field name for RangeFilter"
1755 regexpFilter = fieldTagged $ \fn o -> RegexpFilter fn <$> o .: "value"
1767 regexpFilter = fieldTagged $ \fn o -> RegexpFilter fn <$> o .: "value"
1756 <*> o .: "flags"
1768 <*> o .: "flags"
1757 <*> o .: "_name"
1769 <*> o .: "_name"
1758 <*> o .:? "_cache" .!= defaultCache
1770 <*> o .:? "_cache" .!= defaultCache
1759 <*> o .: "_cache_key"
1771 <*> o .: "_cache_key"
1760− termFilter o = flip fieldTagged o $ \(FieldName fn) o' -> do
1772+ termFilter o = case HM.toList (HM.delete "_cache" o) of
1761− trm <- Term fn <$> parseJSON (Object o')
1773+ [(termField, String termVal)] -> TermFilter (Term termField termVal)
1762− TermFilter trm <$> o .: "_cache" .!= defaultCache
1774+ <$> o .:? "_cache" .!= defaultCache
1775+ _ -> fail "Could not find term field for TermFilter"
1764fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
1777fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
1765fieldTagged f o = case HM.toList o of
1778fieldTagged f o = case HM.toList o of
@@ -1866,13 +1879,13 @@ instance ToJSON Query where
1866 object [ "simple_query_string" .= query ]
1879 object [ "simple_query_string" .= query ]
1868instance FromJSON Query where
1881instance FromJSON Query where
1869− parseJSON = withObject "Query" parse
1882+ parseJSON v = withObject "Query" parse v
1870 where parse o = termQuery `taggedWith` "term"
1883 where parse o = termQuery `taggedWith` "term"
1871 <|> termsQuery `taggedWith` "terms"
1884 <|> termsQuery `taggedWith` "terms"
1872 <|> idsQuery `taggedWith` "ids"
1885 <|> idsQuery `taggedWith` "ids"
1873 <|> queryQueryStringQuery `taggedWith` "query_string"
1886 <|> queryQueryStringQuery `taggedWith` "query_string"
1874 <|> queryMatchQuery `taggedWith` "match"
1887 <|> queryMatchQuery `taggedWith` "match"
1875− <|> queryMultiMatchQuery o --TODO: is this a precedence issue?
1888+ <|> queryMultiMatchQuery --TODO: is this a precedence issue?
1876 <|> queryBoolQuery `taggedWith` "bool"
1889 <|> queryBoolQuery `taggedWith` "bool"
1877 <|> queryBoostingQuery `taggedWith` "boosting"
1890 <|> queryBoostingQuery `taggedWith` "boosting"
1878 <|> queryCommonTermsQuery `taggedWith` "common"
1891 <|> queryCommonTermsQuery `taggedWith` "common"
@@ -1895,8 +1908,8 @@ instance FromJSON Query where
1895 <|> queryRegexpQuery `taggedWith` "regexp"
1908 <|> queryRegexpQuery `taggedWith` "regexp"
1896 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
1909 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
1897 where taggedWith parser k = parser =<< o .: k
1910 where taggedWith parser k = parser =<< o .: k
1898− termQuery o = TermQuery <$> parseJSON (Object o)
1911+ termQuery = fieldTagged $ \(FieldName fn) o ->
1899− <*> o .:? "boost"
1912+ TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
1900 termsQuery o = case HM.toList o of
1913 termsQuery o = case HM.toList o of
1901 [(fn, vs)] -> do vals <- parseJSON vs
1914 [(fn, vs)] -> do vals <- parseJSON vs
1902 case vals of
1915 case vals of
@@ -1907,7 +1920,7 @@ instance FromJSON Query where
1907 <*> o .: "values"
1920 <*> o .: "values"
1908 queryQueryStringQuery = pure . QueryQueryStringQuery
1921 queryQueryStringQuery = pure . QueryQueryStringQuery
1909 queryMatchQuery = pure . QueryMatchQuery
1922 queryMatchQuery = pure . QueryMatchQuery
1910− queryMultiMatchQuery = undefined
1923+ queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
1911 queryBoolQuery = pure . QueryBoolQuery
1924 queryBoolQuery = pure . QueryBoolQuery
1912 queryBoostingQuery = pure . QueryBoostingQuery
1925 queryBoostingQuery = pure . QueryBoostingQuery
1913 queryCommonTermsQuery = pure . QueryCommonTermsQuery
1926 queryCommonTermsQuery = pure . QueryCommonTermsQuery
@@ -2071,7 +2084,7 @@ instance FromJSON QueryStringQuery where
2072instance ToJSON RangeQuery where
2085instance ToJSON RangeQuery where
2073 toJSON (RangeQuery (FieldName fieldName) range boost) =
2086 toJSON (RangeQuery (FieldName fieldName) range boost) =
2074− object [ fieldName .= conjoined ]
2087+ object [ fieldName .= object conjoined ]
2075 where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2088 where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2077instance FromJSON RangeQuery where
2090instance FromJSON RangeQuery where
@@ -2312,7 +2325,7 @@ instance ToJSON FuzzyLikeThisQuery where
2312instance FromJSON FuzzyLikeThisQuery where
2325instance FromJSON FuzzyLikeThisQuery where
2313 parseJSON = withObject "FuzzyLikeThisQuery" parse
2326 parseJSON = withObject "FuzzyLikeThisQuery" parse
2314 where parse o = FuzzyLikeThisQuery
2327 where parse o = FuzzyLikeThisQuery
2315− <$> o .: "fields"
2328+ <$> o .:? "fields" .!= []
2316 <*> o .: "like_text"
2329 <*> o .: "like_text"
2317 <*> o .: "max_query_terms"
2330 <*> o .: "max_query_terms"
2318 <*> o .: "ignore_tf"
2331 <*> o .: "ignore_tf"
@@ -2342,7 +2355,7 @@ instance ToJSON DisMaxQuery where
2342instance FromJSON DisMaxQuery where
2355instance FromJSON DisMaxQuery where
2343 parseJSON = withObject "DisMaxQuery" parse
2356 parseJSON = withObject "DisMaxQuery" parse
2344 where parse o = DisMaxQuery
2357 where parse o = DisMaxQuery
2345− <$> o .: "queries"
2358+ <$> o .:? "queries" .!= []
2346 <*> o .: "tie_breaker"
2359 <*> o .: "tie_breaker"
2347 <*> o .:? "boost"
2360 <*> o .:? "boost"
@@ -2467,6 +2480,20 @@ instance ToJSON MultiMatchQuery where
2467 , "max_expansions" .= maxEx
2480 , "max_expansions" .= maxEx
2468 , "lenient" .= lenient ]
2481 , "lenient" .= lenient ]
2483+instance FromJSON MultiMatchQuery where
2484+ parseJSON = withObject "MultiMatchQuery" parse
2485+ where parse raw = do o <- raw .: "multi_match"
2487+ <$> o .:? "fields" .!= []
2489+ <*> o .: "operator"
2490+ <*> o .: "zero_terms_query"
2491+ <*> o .:? "tiebreaker"
2493+ <*> o .:? "cutoff_frequency"
2494+ <*> o .:? "analyzer"
2495+ <*> o .:? "max_expansions"
2496+ <*> o .:? "lenient"
2471instance ToJSON MultiMatchQueryType where
2498instance ToJSON MultiMatchQueryType where
2472 toJSON MultiMatchBestFields = "best_fields"
2499 toJSON MultiMatchBestFields = "best_fields"
@@ -2603,12 +2630,16 @@ instance FromJSON AliasRouting where
2603 parseJSON = withObject "AliasRouting" parse
2630 parseJSON = withObject "AliasRouting" parse
2604 where parse o = parseAll o <|> parseGranular o
2631 where parse o = parseAll o <|> parseGranular o
2605 parseAll o = AllAliasRouting <$> o .: "routing"
2632 parseAll o = AllAliasRouting <$> o .: "routing"
2633+ parseGranular o = do
2634+ sr <- o .:? "search_routing"
2635+ ir <- o .:? "index_routing"
2636+ if isNothing sr && isNothing ir
2637+ then fail "Both search_routing and index_routing can't be blank"
2606− parseGranular o = GranularAliasRouting <$> o .:? "search_routing"
2638+ else return (GranularAliasRouting sr ir)
2607− <*> o .:? "index_routing"
2609instance FromJSON IndexAliasCreate where
2640instance FromJSON IndexAliasCreate where
2610 parseJSON v = withObject "IndexAliasCreate" parse v
2641 parseJSON v = withObject "IndexAliasCreate" parse v
2611− where parse o = IndexAliasCreate <$> parseJSON v
2642+ where parse o = IndexAliasCreate <$> optional (parseJSON v)
2612 <*> o .:? "filter"
2643 <*> o .:? "filter"
2614instance ToJSON SearchAliasRouting where
2645instance ToJSON SearchAliasRouting where
@@ -2700,6 +2731,9 @@ fastVectorHighPairs (Just
2700 ++ commonHighlightPairs fvCom
2731 ++ commonHighlightPairs fvCom
2701 ++ nonPostingsToPairs fvNonPostSettings
2732 ++ nonPostingsToPairs fvNonPostSettings
2734+deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
2735+deleteSeveral ks hm = foldr HM.delete hm ks
2703commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
2737commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
2704commonHighlightPairs Nothing = []
2738commonHighlightPairs Nothing = []
2705commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
2739commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
@@ -2778,10 +2812,10 @@ instance ToJSON ScoreType where
2779instance FromJSON ScoreType where
2813instance FromJSON ScoreType where
2780 parseJSON = withText "ScoreType" parse
2814 parseJSON = withText "ScoreType" parse
2781− where parse "max" = pure ScoreTypeMax
2815+ where parse "max" = pure ScoreTypeMax
2782− parse "avg" = pure ScoreTypeAvg
2816+ parse "avg" = pure ScoreTypeAvg
2783− parse "sum" = pure ScoreTypeSum
2817+ parse "sum" = pure ScoreTypeSum
2784− parse "non" = pure ScoreTypeNone
2818+ parse "none" = pure ScoreTypeNone
2785 parse t = fail ("Unexpected ScoreType: " <> show t)
2819 parse t = fail ("Unexpected ScoreType: " <> show t)
2787instance ToJSON Distance where
2821instance ToJSON Distance where
@@ -2795,7 +2829,12 @@ instance FromJSON Distance where
2795 parseJSON = withText "Distance" parse
2829 parseJSON = withText "Distance" parse
2796 where parse t = Distance <$> parseCoeff nT
2830 where parse t = Distance <$> parseCoeff nT
2797 <*> parseJSON (String unitT)
2831 <*> parseJSON (String unitT)
2798− where (nT, unitT) = T.span isNumber t
2832+ where (nT, unitT) = T.span validForNumber t
2833+ -- may be a better way to do this
2834+ validForNumber '-' = True
2835+ validForNumber '.' = True
2836+ validForNumber 'e' = True
2837+ validForNumber c = isNumber c
2799 parseCoeff "" = fail "Empty string cannot be parsed as number"
2838 parseCoeff "" = fail "Empty string cannot be parsed as number"
2800 parseCoeff s = return (read (T.unpack s))
2839 parseCoeff s = return (read (T.unpack s))
@@ -2857,11 +2896,12 @@ instance ToJSON GeoBoundingBoxConstraint where
2858instance FromJSON GeoBoundingBoxConstraint where
2897instance FromJSON GeoBoundingBoxConstraint where
2859 parseJSON = withObject "GeoBoundingBoxConstraint" parse
2898 parseJSON = withObject "GeoBoundingBoxConstraint" parse
2860− where parse o = flip fieldTagged o $ \fn o' ->
2899+ where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of
2861− GeoBoundingBoxConstraint fn
2900+ [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)
2862− <$> parseJSON (Object o')
2901+ <$> parseJSON v
2863− <*> o .:? "cache" .!= defaultCache
2902+ <*> o .:? "_cache" .!= defaultCache
2864− <*> o .: "type"
2903+ <*> o .: "type"
2904+ _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
2866instance ToJSON GeoFilterType where
2906instance ToJSON GeoFilterType where
2867 toJSON GeoFilterMemory = String "memory"
2907 toJSON GeoFilterMemory = String "memory"