bloodhound-0.21.0.0: src/Database/Bloodhound/Internal/Query.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Database.Bloodhound.Internal.Query
( module X,
module Database.Bloodhound.Internal.Query,
)
where
import Bloodhound.Import
import qualified Data.Aeson.KeyMap as X
import qualified Data.HashMap.Strict as HM
import qualified Data.Text as T
import Database.Bloodhound.Common.Script as X
import Database.Bloodhound.Internal.Newtypes
import GHC.Generics
data Query
= TermQuery Term (Maybe Boost)
| TermsQuery Key (NonEmpty Text)
| QueryMatchQuery MatchQuery
| QueryMultiMatchQuery MultiMatchQuery
| QueryBoolQuery BoolQuery
| QueryBoostingQuery BoostingQuery
| QueryCommonTermsQuery CommonTermsQuery
| ConstantScoreQuery Query Boost
| QueryFunctionScoreQuery FunctionScoreQuery
| QueryDisMaxQuery DisMaxQuery
| QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
| QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
| QueryFuzzyQuery FuzzyQuery
| QueryHasChildQuery HasChildQuery
| QueryHasParentQuery HasParentQuery
| IdsQuery [DocId]
| QueryIndicesQuery IndicesQuery
| MatchAllQuery (Maybe Boost)
| QueryMoreLikeThisQuery MoreLikeThisQuery
| QueryMoreLikeThisFieldQuery MoreLikeThisFieldQuery
| QueryNestedQuery NestedQuery
| QueryPrefixQuery PrefixQuery
| QueryQueryStringQuery QueryStringQuery
| QuerySimpleQueryStringQuery SimpleQueryStringQuery
| QueryRangeQuery RangeQuery
| QueryRegexpQuery RegexpQuery
| QueryExistsQuery FieldName
| QueryMatchNoneQuery
| QueryWildcardQuery WildcardQuery
deriving (Eq, Show, Generic)
instance ToJSON Query where
toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
object
[ "term"
.= object [termQueryField .= object merged]
]
where
base = ["value" .= termQueryValue]
boosted = maybe [] (return . ("boost" .=)) boost
merged = mappend base boosted
toJSON (TermsQuery fieldName terms) =
object ["terms" .= object conjoined]
where
conjoined = [fieldName .= terms]
toJSON (IdsQuery docIds) =
object ["ids" .= object conjoined]
where
conjoined = ["values" .= fmap toJSON docIds]
toJSON (QueryQueryStringQuery qQueryStringQuery) =
object ["query_string" .= qQueryStringQuery]
toJSON (QueryMatchQuery matchQuery) =
object ["match" .= matchQuery]
toJSON (QueryMultiMatchQuery multiMatchQuery) =
toJSON multiMatchQuery
toJSON (QueryBoolQuery boolQuery) =
object ["bool" .= boolQuery]
toJSON (QueryBoostingQuery boostingQuery) =
object ["boosting" .= boostingQuery]
toJSON (QueryCommonTermsQuery commonTermsQuery) =
object ["common" .= commonTermsQuery]
toJSON (ConstantScoreQuery query boost) =
object
[ "constant_score"
.= object
[ "filter" .= query,
"boost" .= boost
]
]
toJSON (QueryFunctionScoreQuery functionScoreQuery) =
object ["function_score" .= functionScoreQuery]
toJSON (QueryDisMaxQuery disMaxQuery) =
object ["dis_max" .= disMaxQuery]
toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
object ["fuzzy_like_this" .= fuzzyQuery]
toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
object ["fuzzy_like_this_field" .= fuzzyFieldQuery]
toJSON (QueryFuzzyQuery fuzzyQuery) =
object ["fuzzy" .= fuzzyQuery]
toJSON (QueryHasChildQuery childQuery) =
object ["has_child" .= childQuery]
toJSON (QueryHasParentQuery parentQuery) =
object ["has_parent" .= parentQuery]
toJSON (QueryIndicesQuery qIndicesQuery) =
object ["indices" .= qIndicesQuery]
toJSON (MatchAllQuery boost) =
object ["match_all" .= omitNulls ["boost" .= boost]]
toJSON (QueryMoreLikeThisQuery query) =
object ["more_like_this" .= query]
toJSON (QueryMoreLikeThisFieldQuery query) =
object ["more_like_this_field" .= query]
toJSON (QueryNestedQuery query) =
object ["nested" .= query]
toJSON (QueryPrefixQuery query) =
object ["prefix" .= query]
toJSON (QueryRangeQuery query) =
object ["range" .= query]
toJSON (QueryRegexpQuery query) =
object ["regexp" .= query]
toJSON (QuerySimpleQueryStringQuery query) =
object ["simple_query_string" .= query]
toJSON (QueryExistsQuery (FieldName fieldName)) =
object
[ "exists"
.= object
["field" .= fieldName]
]
toJSON QueryMatchNoneQuery =
object ["match_none" .= object []]
toJSON (QueryWildcardQuery query) =
object ["wildcard" .= query]
instance FromJSON Query where
parseJSON v = withObject "Query" parse v
where
parse o =
termQuery
`taggedWith` "term"
<|> termsQuery
`taggedWith` "terms"
<|> idsQuery
`taggedWith` "ids"
<|> queryQueryStringQuery
`taggedWith` "query_string"
<|> queryMatchQuery
`taggedWith` "match"
<|> queryMultiMatchQuery
<|> queryBoolQuery
`taggedWith` "bool"
<|> queryBoostingQuery
`taggedWith` "boosting"
<|> queryCommonTermsQuery
`taggedWith` "common"
<|> constantScoreQuery
`taggedWith` "constant_score"
<|> queryFunctionScoreQuery
`taggedWith` "function_score"
<|> queryDisMaxQuery
`taggedWith` "dis_max"
<|> queryFuzzyLikeThisQuery
`taggedWith` "fuzzy_like_this"
<|> queryFuzzyLikeFieldQuery
`taggedWith` "fuzzy_like_this_field"
<|> queryFuzzyQuery
`taggedWith` "fuzzy"
<|> queryHasChildQuery
`taggedWith` "has_child"
<|> queryHasParentQuery
`taggedWith` "has_parent"
<|> queryIndicesQuery
`taggedWith` "indices"
<|> matchAllQuery
`taggedWith` "match_all"
<|> queryMoreLikeThisQuery
`taggedWith` "more_like_this"
<|> queryMoreLikeThisFieldQuery
`taggedWith` "more_like_this_field"
<|> queryNestedQuery
`taggedWith` "nested"
<|> queryPrefixQuery
`taggedWith` "prefix"
<|> queryRangeQuery
`taggedWith` "range"
<|> queryRegexpQuery
`taggedWith` "regexp"
<|> querySimpleQueryStringQuery
`taggedWith` "simple_query_string"
<|> queryWildcardQuery
`taggedWith` "wildcard"
where
taggedWith parser k = parser =<< o .: k
termQuery = fieldTagged $ \(FieldName fn) o ->
TermQuery <$> (Term (fromText fn) <$> o .: "value") <*> o .:? "boost"
termsQuery o = case HM.toList o of
[(fn, vs)] -> do
vals <- parseJSON vs
case vals of
x : xs -> return (TermsQuery fn (x :| xs))
_ -> fail "Expected non empty list of values"
_ -> fail "Expected object with 1 field-named key"
idsQuery o = IdsQuery <$> o .: "values"
queryQueryStringQuery = pure . QueryQueryStringQuery
queryMatchQuery = pure . QueryMatchQuery
queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
queryBoolQuery = pure . QueryBoolQuery
queryBoostingQuery = pure . QueryBoostingQuery
queryCommonTermsQuery = pure . QueryCommonTermsQuery
constantScoreQuery o = case X.lookup "filter" o of
Just x ->
ConstantScoreQuery
<$> parseJSON x
<*> o .: "boost"
_ -> fail "Does not appear to be a ConstantScoreQuery"
queryFunctionScoreQuery = pure . QueryFunctionScoreQuery
queryDisMaxQuery = pure . QueryDisMaxQuery
queryFuzzyLikeThisQuery = pure . QueryFuzzyLikeThisQuery
queryFuzzyLikeFieldQuery = pure . QueryFuzzyLikeFieldQuery
queryFuzzyQuery = pure . QueryFuzzyQuery
queryHasChildQuery = pure . QueryHasChildQuery
queryHasParentQuery = pure . QueryHasParentQuery
queryIndicesQuery = pure . QueryIndicesQuery
matchAllQuery o = MatchAllQuery <$> o .:? "boost"
queryMoreLikeThisQuery = pure . QueryMoreLikeThisQuery
queryMoreLikeThisFieldQuery = pure . QueryMoreLikeThisFieldQuery
queryNestedQuery = pure . QueryNestedQuery
queryPrefixQuery = pure . QueryPrefixQuery
queryRangeQuery = pure . QueryRangeQuery
queryRegexpQuery = pure . QueryRegexpQuery
querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
-- queryExistsQuery o = QueryExistsQuery <$> o .: "field"
queryWildcardQuery = pure . QueryWildcardQuery
-- | As of Elastic 2.0, 'Filters' are just 'Queries' housed in a
-- Bool Query, and flagged in a different context.
newtype Filter = Filter {unFilter :: Query}
deriving (Eq, Show)
instance ToJSON Filter where
toJSON = toJSON . unFilter
instance FromJSON Filter where
parseJSON v = Filter <$> parseJSON v
data RegexpQuery = RegexpQuery
{ regexpQueryField :: FieldName,
regexpQuery :: Regexp,
regexpQueryFlags :: RegexpFlags,
regexpQueryBoost :: Maybe Boost
}
deriving (Eq, Show, Generic)
instance ToJSON RegexpQuery where
toJSON
( RegexpQuery
(FieldName rqQueryField)
(Regexp regexpQueryQuery)
rqQueryFlags
rqQueryBoost
) =
object [fromText rqQueryField .= omitNulls base]
where
base =
[ "value" .= regexpQueryQuery,
"flags" .= rqQueryFlags,
"boost" .= rqQueryBoost
]
instance FromJSON RegexpQuery where
parseJSON = withObject "RegexpQuery" parse
where
parse = fieldTagged $ \fn o ->
RegexpQuery fn
<$> o .: "value"
<*> o .: "flags"
<*> o .:? "boost"
data WildcardQuery = WildcardQuery
{ wildcardQueryField :: FieldName,
wildcardQuery :: Key,
wildcardQueryBoost :: Maybe Boost
}
deriving (Eq, Show, Generic)
instance ToJSON WildcardQuery where
toJSON
( WildcardQuery
(FieldName wcQueryField)
(wcQueryQuery)
wcQueryBoost
) =
object [fromText wcQueryField .= omitNulls base]
where
base =
[ "value" .= wcQueryQuery,
"boost" .= wcQueryBoost
]
instance FromJSON WildcardQuery where
parseJSON = withObject "WildcardQuery" parse
where
parse = fieldTagged $ \fn o ->
WildcardQuery fn
<$> o .: "value"
<*> o .:? "boost"
data RangeQuery = RangeQuery
{ rangeQueryField :: FieldName,
rangeQueryRange :: RangeValue,
rangeQueryBoost :: Boost
}
deriving (Eq, Show, Generic)
instance ToJSON RangeQuery where
toJSON (RangeQuery (FieldName fieldName) range boost) =
object [fromText fieldName .= object conjoined]
where
conjoined = ("boost" .= boost) : rangeValueToPair range
instance FromJSON RangeQuery where
parseJSON = withObject "RangeQuery" parse
where
parse = fieldTagged $ \fn o ->
RangeQuery fn
<$> parseJSON (Object o)
<*> o .: "boost"
mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
mkRangeQuery f r = RangeQuery f r (Boost 1.0)
data SimpleQueryStringQuery = SimpleQueryStringQuery
{ simpleQueryStringQuery :: QueryString,
simpleQueryStringField :: Maybe FieldOrFields,
simpleQueryStringOperator :: Maybe BooleanOperator,
simpleQueryStringAnalyzer :: Maybe Analyzer,
simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag),
simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded,
simpleQueryStringLocale :: Maybe Locale
}
deriving (Eq, Show, Generic)
instance ToJSON SimpleQueryStringQuery where
toJSON SimpleQueryStringQuery {..} =
omitNulls (base ++ maybeAdd)
where
base = ["query" .= simpleQueryStringQuery]
maybeAdd =
[ "fields" .= simpleQueryStringField,
"default_operator" .= simpleQueryStringOperator,
"analyzer" .= simpleQueryStringAnalyzer,
"flags" .= simpleQueryStringFlags,
"lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded,
"locale" .= simpleQueryStringLocale
]
instance FromJSON SimpleQueryStringQuery where
parseJSON = withObject "SimpleQueryStringQuery" parse
where
parse o =
SimpleQueryStringQuery
<$> o .: "query"
<*> o .:? "fields"
<*> o .:? "default_operator"
<*> o .:? "analyzer"
<*> (parseFlags <$> o .:? "flags")
<*> o .:? "lowercase_expanded_terms"
<*> o .:? "locale"
parseFlags (Just (x : xs)) = Just (x :| xs)
parseFlags _ = Nothing
data SimpleQueryFlag
= SimpleQueryAll
| SimpleQueryNone
| SimpleQueryAnd
| SimpleQueryOr
| SimpleQueryPrefix
| SimpleQueryPhrase
| SimpleQueryPrecedence
| SimpleQueryEscape
| SimpleQueryWhitespace
| SimpleQueryFuzzy
| SimpleQueryNear
| SimpleQuerySlop
deriving (Eq, Show, Generic)
instance ToJSON SimpleQueryFlag where
toJSON SimpleQueryAll = "ALL"
toJSON SimpleQueryNone = "NONE"
toJSON SimpleQueryAnd = "AND"
toJSON SimpleQueryOr = "OR"
toJSON SimpleQueryPrefix = "PREFIX"
toJSON SimpleQueryPhrase = "PHRASE"
toJSON SimpleQueryPrecedence = "PRECEDENCE"
toJSON SimpleQueryEscape = "ESCAPE"
toJSON SimpleQueryWhitespace = "WHITESPACE"
toJSON SimpleQueryFuzzy = "FUZZY"
toJSON SimpleQueryNear = "NEAR"
toJSON SimpleQuerySlop = "SLOP"
instance FromJSON SimpleQueryFlag where
parseJSON = withText "SimpleQueryFlag" parse
where
parse "ALL" = pure SimpleQueryAll
parse "NONE" = pure SimpleQueryNone
parse "AND" = pure SimpleQueryAnd
parse "OR" = pure SimpleQueryOr
parse "PREFIX" = pure SimpleQueryPrefix
parse "PHRASE" = pure SimpleQueryPhrase
parse "PRECEDENCE" = pure SimpleQueryPrecedence
parse "ESCAPE" = pure SimpleQueryEscape
parse "WHITESPACE" = pure SimpleQueryWhitespace
parse "FUZZY" = pure SimpleQueryFuzzy
parse "NEAR" = pure SimpleQueryNear
parse "SLOP" = pure SimpleQuerySlop
parse f = fail ("Unexpected SimpleQueryFlag: " <> show f)
-- use_dis_max and tie_breaker when fields are plural?
data QueryStringQuery = QueryStringQuery
{ queryStringQuery :: QueryString,
queryStringDefaultField :: Maybe FieldName,
queryStringOperator :: Maybe BooleanOperator,
queryStringAnalyzer :: Maybe Analyzer,
queryStringAllowLeadingWildcard :: Maybe AllowLeadingWildcard,
queryStringLowercaseExpanded :: Maybe LowercaseExpanded,
queryStringEnablePositionIncrements :: Maybe EnablePositionIncrements,
queryStringFuzzyMaxExpansions :: Maybe MaxExpansions,
queryStringFuzziness :: Maybe Fuzziness,
queryStringFuzzyPrefixLength :: Maybe PrefixLength,
queryStringPhraseSlop :: Maybe PhraseSlop,
queryStringBoost :: Maybe Boost,
queryStringAnalyzeWildcard :: Maybe AnalyzeWildcard,
queryStringGeneratePhraseQueries :: Maybe GeneratePhraseQueries,
queryStringMinimumShouldMatch :: Maybe MinimumMatch,
queryStringLenient :: Maybe Lenient,
queryStringLocale :: Maybe Locale
}
deriving (Eq, Show, Generic)
instance ToJSON QueryStringQuery where
toJSON
( QueryStringQuery
qsQueryString
qsDefaultField
qsOperator
qsAnalyzer
qsAllowWildcard
qsLowercaseExpanded
qsEnablePositionIncrements
qsFuzzyMaxExpansions
qsFuzziness
qsFuzzyPrefixLength
qsPhraseSlop
qsBoost
qsAnalyzeWildcard
qsGeneratePhraseQueries
qsMinimumShouldMatch
qsLenient
qsLocale
) =
omitNulls base
where
base =
[ "query" .= qsQueryString,
"default_field" .= qsDefaultField,
"default_operator" .= qsOperator,
"analyzer" .= qsAnalyzer,
"allow_leading_wildcard" .= qsAllowWildcard,
"lowercase_expanded_terms" .= qsLowercaseExpanded,
"enable_position_increments" .= qsEnablePositionIncrements,
"fuzzy_max_expansions" .= qsFuzzyMaxExpansions,
"fuzziness" .= qsFuzziness,
"fuzzy_prefix_length" .= qsFuzzyPrefixLength,
"phrase_slop" .= qsPhraseSlop,
"boost" .= qsBoost,
"analyze_wildcard" .= qsAnalyzeWildcard,
"auto_generate_phrase_queries" .= qsGeneratePhraseQueries,
"minimum_should_match" .= qsMinimumShouldMatch,
"lenient" .= qsLenient,
"locale" .= qsLocale
]
instance FromJSON QueryStringQuery where
parseJSON = withObject "QueryStringQuery" parse
where
parse o =
QueryStringQuery
<$> o .: "query"
<*> o .:? "default_field"
<*> o .:? "default_operator"
<*> o .:? "analyzer"
<*> o .:? "allow_leading_wildcard"
<*> o .:? "lowercase_expanded_terms"
<*> o .:? "enable_position_increments"
<*> o .:? "fuzzy_max_expansions"
<*> o .:? "fuzziness"
<*> o .:? "fuzzy_prefix_length"
<*> o .:? "phrase_slop"
<*> o .:? "boost"
<*> o .:? "analyze_wildcard"
<*> o .:? "auto_generate_phrase_queries"
<*> o .:? "minimum_should_match"
<*> o .:? "lenient"
<*> o .:? "locale"
mkQueryStringQuery :: QueryString -> QueryStringQuery
mkQueryStringQuery qs =
QueryStringQuery
qs
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
data FieldOrFields
= FofField FieldName
| FofFields (NonEmpty FieldName)
deriving (Eq, Show, Generic)
instance ToJSON FieldOrFields where
toJSON (FofField fieldName) =
toJSON fieldName
toJSON (FofFields fieldNames) =
toJSON fieldNames
instance FromJSON FieldOrFields where
parseJSON v =
FofField <$> parseJSON v
<|> FofFields <$> (parseNEJSON =<< parseJSON v)
data PrefixQuery = PrefixQuery
{ prefixQueryField :: FieldName,
prefixQueryPrefixValue :: Text,
prefixQueryBoost :: Maybe Boost
}
deriving (Eq, Show, Generic)
instance ToJSON PrefixQuery where
toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
object [fromText fieldName .= omitNulls base]
where
base =
[ "value" .= queryValue,
"boost" .= boost
]
instance FromJSON PrefixQuery where
parseJSON = withObject "PrefixQuery" parse
where
parse = fieldTagged $ \fn o ->
PrefixQuery fn
<$> o .: "value"
<*> o .:? "boost"
data NestedQuery = NestedQuery
{ nestedQueryPath :: QueryPath,
nestedQueryScoreType :: ScoreType,
nestedQuery :: Query,
nestedQueryInnerHits :: Maybe InnerHits
}
deriving (Eq, Show, Generic)
instance ToJSON NestedQuery where
toJSON (NestedQuery nqPath nqScoreType nqQuery nqInnerHits) =
omitNulls
[ "path" .= nqPath,
"score_mode" .= nqScoreType,
"query" .= nqQuery,
"inner_hits" .= nqInnerHits
]
instance FromJSON NestedQuery where
parseJSON = withObject "NestedQuery" parse
where
parse o =
NestedQuery
<$> o .: "path"
<*> o .: "score_mode"
<*> o .: "query"
<*> o .:? "inner_hits"
data MoreLikeThisFieldQuery = MoreLikeThisFieldQuery
{ moreLikeThisFieldText :: Text,
moreLikeThisFieldFields :: FieldName,
-- default 0.3 (30%)
moreLikeThisFieldPercentMatch :: Maybe PercentMatch,
moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency,
moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms,
moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord),
moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency,
moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency,
moreLikeThisFieldMinWordLength :: Maybe MinWordLength,
moreLikeThisFieldMaxWordLength :: Maybe MaxWordLength,
moreLikeThisFieldBoostTerms :: Maybe BoostTerms,
moreLikeThisFieldBoost :: Maybe Boost,
moreLikeThisFieldAnalyzer :: Maybe Analyzer
}
deriving (Eq, Show, Generic)
instance ToJSON MoreLikeThisFieldQuery where
toJSON
( MoreLikeThisFieldQuery
text
(FieldName fieldName)
percent
mtf
mqt
stopwords
mindf
maxdf
minwl
maxwl
boostTerms
boost
analyzer
) =
object [fromText fieldName .= omitNulls base]
where
base =
[ "like_text" .= text,
"percent_terms_to_match" .= percent,
"min_term_freq" .= mtf,
"max_query_terms" .= mqt,
"stop_words" .= stopwords,
"min_doc_freq" .= mindf,
"max_doc_freq" .= maxdf,
"min_word_length" .= minwl,
"max_word_length" .= maxwl,
"boost_terms" .= boostTerms,
"boost" .= boost,
"analyzer" .= analyzer
]
instance FromJSON MoreLikeThisFieldQuery where
parseJSON = withObject "MoreLikeThisFieldQuery" parse
where
parse = fieldTagged $ \fn o ->
MoreLikeThisFieldQuery
<$> o .: "like_text"
<*> pure fn
<*> o .:? "percent_terms_to_match"
<*> o .:? "min_term_freq"
<*> o .:? "max_query_terms"
-- <*> (optionalNE =<< o .:? "stop_words")
<*> o .:? "stop_words"
<*> o .:? "min_doc_freq"
<*> o .:? "max_doc_freq"
<*> o .:? "min_word_length"
<*> o .:? "max_word_length"
<*> o .:? "boost_terms"
<*> o .:? "boost"
<*> o .:? "analyzer"
-- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
data MoreLikeThisQuery = MoreLikeThisQuery
{ moreLikeThisText :: Text,
moreLikeThisFields :: Maybe (NonEmpty FieldName),
-- default 0.3 (30%)
moreLikeThisPercentMatch :: Maybe PercentMatch,
moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency,
moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms,
moreLikeThisStopWords :: Maybe (NonEmpty StopWord),
moreLikeThisMinDocFrequency :: Maybe MinDocFrequency,
moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency,
moreLikeThisMinWordLength :: Maybe MinWordLength,
moreLikeThisMaxWordLength :: Maybe MaxWordLength,
moreLikeThisBoostTerms :: Maybe BoostTerms,
moreLikeThisBoost :: Maybe Boost,
moreLikeThisAnalyzer :: Maybe Analyzer
}
deriving (Eq, Show, Generic)
instance ToJSON MoreLikeThisQuery where
toJSON
( MoreLikeThisQuery
text
fields
percent
mtf
mqt
stopwords
mindf
maxdf
minwl
maxwl
boostTerms
boost
analyzer
) =
omitNulls base
where
base =
[ "like_text" .= text,
"fields" .= fields,
"percent_terms_to_match" .= percent,
"min_term_freq" .= mtf,
"max_query_terms" .= mqt,
"stop_words" .= stopwords,
"min_doc_freq" .= mindf,
"max_doc_freq" .= maxdf,
"min_word_length" .= minwl,
"max_word_length" .= maxwl,
"boost_terms" .= boostTerms,
"boost" .= boost,
"analyzer" .= analyzer
]
instance FromJSON MoreLikeThisQuery where
parseJSON = withObject "MoreLikeThisQuery" parse
where
parse o =
MoreLikeThisQuery
<$> o .: "like_text"
-- <*> (optionalNE =<< o .:? "fields")
<*> o .:? "fields"
<*> o .:? "percent_terms_to_match"
<*> o .:? "min_term_freq"
<*> o .:? "max_query_terms"
-- <*> (optionalNE =<< o .:? "stop_words")
<*> o .:? "stop_words"
<*> o .:? "min_doc_freq"
<*> o .:? "max_doc_freq"
<*> o .:? "min_word_length"
<*> o .:? "max_word_length"
<*> o .:? "boost_terms"
<*> o .:? "boost"
<*> o .:? "analyzer"
-- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
data IndicesQuery = IndicesQuery
{ indicesQueryIndices :: [IndexName],
indicesQuery :: Query,
-- default "all"
indicesQueryNoMatch :: Maybe Query
}
deriving (Eq, Show, Generic)
instance ToJSON IndicesQuery where
toJSON (IndicesQuery indices query noMatch) =
omitNulls
[ "indices" .= indices,
"no_match_query" .= noMatch,
"query" .= query
]
instance FromJSON IndicesQuery where
parseJSON = withObject "IndicesQuery" parse
where
parse o =
IndicesQuery
<$> o .:? "indices" .!= []
<*> o .: "query"
<*> o .:? "no_match_query"
data HasParentQuery = HasParentQuery
{ hasParentQueryType :: RelationName,
hasParentQuery :: Query,
hasParentQueryScore :: Maybe AggregateParentScore,
hasParentIgnoreUnmapped :: Maybe IgnoreUnmapped
}
deriving (Eq, Show, Generic)
instance ToJSON HasParentQuery where
toJSON (HasParentQuery queryType query scoreType ignoreUnmapped) =
omitNulls
[ "parent_type" .= queryType,
"score" .= scoreType,
"query" .= query,
"ignore_unmapped" .= ignoreUnmapped
]
instance FromJSON HasParentQuery where
parseJSON = withObject "HasParentQuery" parse
where
parse o =
HasParentQuery
<$> o .: "parent_type"
<*> o .: "query"
<*> o .:? "score"
<*> o .:? "ignore_unmapped"
data HasChildQuery = HasChildQuery
{ hasChildQueryType :: RelationName,
hasChildQuery :: Query,
hasChildQueryScoreType :: Maybe ScoreType,
hasChildIgnoreUnmappped :: Maybe IgnoreUnmapped,
hasChildMinChildren :: Maybe MinChildren,
hasChildMaxChildren :: Maybe MaxChildren
}
deriving (Eq, Show, Generic)
instance ToJSON HasChildQuery where
toJSON (HasChildQuery queryType query scoreType ignoreUnmapped minChildren maxChildren) =
omitNulls
[ "query" .= query,
"score_mode" .= scoreType,
"type" .= queryType,
"min_children" .= minChildren,
"max_children" .= maxChildren,
"ignore_unmapped" .= ignoreUnmapped
]
instance FromJSON HasChildQuery where
parseJSON = withObject "HasChildQuery" parse
where
parse o =
HasChildQuery
<$> o .: "type"
<*> o .: "query"
<*> o .:? "score_mode"
<*> o .:? "ignore_unmapped"
<*> o .:? "min_children"
<*> o .:? "max_children"
data ScoreType
= ScoreTypeMax
| ScoreTypeSum
| ScoreTypeAvg
| ScoreTypeNone
deriving (Eq, Show, Generic)
instance ToJSON ScoreType where
toJSON ScoreTypeMax = "max"
toJSON ScoreTypeAvg = "avg"
toJSON ScoreTypeSum = "sum"
toJSON ScoreTypeNone = "none"
instance FromJSON ScoreType where
parseJSON = withText "ScoreType" parse
where
parse "max" = pure ScoreTypeMax
parse "avg" = pure ScoreTypeAvg
parse "sum" = pure ScoreTypeSum
parse "none" = pure ScoreTypeNone
parse t = fail ("Unexpected ScoreType: " <> show t)
data FuzzyQuery = FuzzyQuery
{ fuzzyQueryField :: FieldName,
fuzzyQueryValue :: Text,
fuzzyQueryPrefixLength :: PrefixLength,
fuzzyQueryMaxExpansions :: MaxExpansions,
fuzzyQueryFuzziness :: Fuzziness,
fuzzyQueryBoost :: Maybe Boost
}
deriving (Eq, Show, Generic)
instance ToJSON FuzzyQuery where
toJSON
( FuzzyQuery
(FieldName fieldName)
queryText
prefixLength
maxEx
fuzziness
boost
) =
object [fromText fieldName .= omitNulls base]
where
base =
[ "value" .= queryText,
"fuzziness" .= fuzziness,
"prefix_length" .= prefixLength,
"boost" .= boost,
"max_expansions" .= maxEx
]
instance FromJSON FuzzyQuery where
parseJSON = withObject "FuzzyQuery" parse
where
parse = fieldTagged $ \fn o ->
FuzzyQuery fn
<$> o .: "value"
<*> o .: "prefix_length"
<*> o .: "max_expansions"
<*> o .: "fuzziness"
<*> o .:? "boost"
data FuzzyLikeFieldQuery = FuzzyLikeFieldQuery
{ fuzzyLikeField :: FieldName,
-- anaphora is good for the soul.
fuzzyLikeFieldText :: Text,
fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms,
fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency,
fuzzyLikeFieldFuzziness :: Fuzziness,
fuzzyLikeFieldPrefixLength :: PrefixLength,
fuzzyLikeFieldBoost :: Boost,
fuzzyLikeFieldAnalyzer :: Maybe Analyzer
}
deriving (Eq, Show, Generic)
instance ToJSON FuzzyLikeFieldQuery where
toJSON
( FuzzyLikeFieldQuery
(FieldName fieldName)
fieldText
maxTerms
ignoreFreq
fuzziness
prefixLength
boost
analyzer
) =
object
[ fromText fieldName
.= omitNulls
[ "like_text" .= fieldText,
"max_query_terms" .= maxTerms,
"ignore_tf" .= ignoreFreq,
"fuzziness" .= fuzziness,
"prefix_length" .= prefixLength,
"analyzer" .= analyzer,
"boost" .= boost
]
]
instance FromJSON FuzzyLikeFieldQuery where
parseJSON = withObject "FuzzyLikeFieldQuery" parse
where
parse = fieldTagged $ \fn o ->
FuzzyLikeFieldQuery fn
<$> o .: "like_text"
<*> o .: "max_query_terms"
<*> o .: "ignore_tf"
<*> o .: "fuzziness"
<*> o .: "prefix_length"
<*> o .: "boost"
<*> o .:? "analyzer"
data FuzzyLikeThisQuery = FuzzyLikeThisQuery
{ fuzzyLikeFields :: [FieldName],
fuzzyLikeText :: Text,
fuzzyLikeMaxQueryTerms :: MaxQueryTerms,
fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency,
fuzzyLikeFuzziness :: Fuzziness,
fuzzyLikePrefixLength :: PrefixLength,
fuzzyLikeBoost :: Boost,
fuzzyLikeAnalyzer :: Maybe Analyzer
}
deriving (Eq, Show, Generic)
instance ToJSON FuzzyLikeThisQuery where
toJSON
( FuzzyLikeThisQuery
fields
text
maxTerms
ignoreFreq
fuzziness
prefixLength
boost
analyzer
) =
omitNulls base
where
base =
[ "fields" .= fields,
"like_text" .= text,
"max_query_terms" .= maxTerms,
"ignore_tf" .= ignoreFreq,
"fuzziness" .= fuzziness,
"prefix_length" .= prefixLength,
"analyzer" .= analyzer,
"boost" .= boost
]
instance FromJSON FuzzyLikeThisQuery where
parseJSON = withObject "FuzzyLikeThisQuery" parse
where
parse o =
FuzzyLikeThisQuery
<$> o .:? "fields" .!= []
<*> o .: "like_text"
<*> o .: "max_query_terms"
<*> o .: "ignore_tf"
<*> o .: "fuzziness"
<*> o .: "prefix_length"
<*> o .: "boost"
<*> o .:? "analyzer"
data DisMaxQuery = DisMaxQuery
{ disMaxQueries :: [Query],
-- default 0.0
disMaxTiebreaker :: Tiebreaker,
disMaxBoost :: Maybe Boost
}
deriving (Eq, Show, Generic)
instance ToJSON DisMaxQuery where
toJSON (DisMaxQuery queries tiebreaker boost) =
omitNulls base
where
base =
[ "queries" .= queries,
"boost" .= boost,
"tie_breaker" .= tiebreaker
]
instance FromJSON DisMaxQuery where
parseJSON = withObject "DisMaxQuery" parse
where
parse o =
DisMaxQuery
<$> o .:? "queries" .!= []
<*> o .: "tie_breaker"
<*> o .:? "boost"
data MatchQuery = MatchQuery
{ matchQueryField :: FieldName,
matchQueryQueryString :: QueryString,
matchQueryOperator :: BooleanOperator,
matchQueryZeroTerms :: ZeroTermsQuery,
matchQueryCutoffFrequency :: Maybe CutoffFrequency,
matchQueryMatchType :: Maybe MatchQueryType,
matchQueryAnalyzer :: Maybe Analyzer,
matchQueryMaxExpansions :: Maybe MaxExpansions,
matchQueryLenient :: Maybe Lenient,
matchQueryBoost :: Maybe Boost,
matchQueryMinimumShouldMatch :: Maybe Text,
matchQueryFuzziness :: Maybe Fuzziness
}
deriving (Eq, Show, Generic)
instance ToJSON MatchQuery where
toJSON
( MatchQuery
(FieldName fieldName)
(QueryString mqQueryString)
booleanOperator
zeroTermsQuery
cutoffFrequency
matchQueryType
analyzer
maxExpansions
lenient
boost
minShouldMatch
mqFuzziness
) =
object [fromText fieldName .= omitNulls base]
where
base =
[ "query" .= mqQueryString,
"operator" .= booleanOperator,
"zero_terms_query" .= zeroTermsQuery,
"cutoff_frequency" .= cutoffFrequency,
"type" .= matchQueryType,
"analyzer" .= analyzer,
"max_expansions" .= maxExpansions,
"lenient" .= lenient,
"boost" .= boost,
"minimum_should_match" .= minShouldMatch,
"fuzziness" .= mqFuzziness
]
instance FromJSON MatchQuery where
parseJSON = withObject "MatchQuery" parse
where
parse = fieldTagged $ \fn o ->
MatchQuery fn
<$> o .: "query"
<*> o .: "operator"
<*> o .: "zero_terms_query"
<*> o .:? "cutoff_frequency"
<*> o .:? "type"
<*> o .:? "analyzer"
<*> o .:? "max_expansions"
<*> o .:? "lenient"
<*> o .:? "boost"
<*> o .:? "minimum_should_match"
<*> o .:? "fuzziness"
-- | 'mkMatchQuery' is a convenience function that defaults the less common parameters,
-- enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
mkMatchQuery :: FieldName -> QueryString -> MatchQuery
mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
data MatchQueryType
= MatchPhrase
| MatchPhrasePrefix
deriving (Eq, Show, Generic)
instance ToJSON MatchQueryType where
toJSON MatchPhrase = "phrase"
toJSON MatchPhrasePrefix = "phrase_prefix"
instance FromJSON MatchQueryType where
parseJSON = withText "MatchQueryType" parse
where
parse "phrase" = pure MatchPhrase
parse "phrase_prefix" = pure MatchPhrasePrefix
parse t = fail ("Unexpected MatchQueryType: " <> show t)
data MultiMatchQuery = MultiMatchQuery
{ multiMatchQueryFields :: [FieldName],
multiMatchQueryString :: QueryString,
multiMatchQueryOperator :: BooleanOperator,
multiMatchQueryZeroTerms :: ZeroTermsQuery,
multiMatchQueryTiebreaker :: Maybe Tiebreaker,
multiMatchQueryType :: Maybe MultiMatchQueryType,
multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency,
multiMatchQueryAnalyzer :: Maybe Analyzer,
multiMatchQueryMaxExpansions :: Maybe MaxExpansions,
multiMatchQueryLenient :: Maybe Lenient
}
deriving (Eq, Show, Generic)
instance ToJSON MultiMatchQuery where
toJSON
( MultiMatchQuery
fields
(QueryString query)
boolOp
ztQ
tb
mmqt
cf
analyzer
maxEx
lenient
) =
object ["multi_match" .= omitNulls base]
where
base =
[ "fields" .= fmap toJSON fields,
"query" .= query,
"operator" .= boolOp,
"zero_terms_query" .= ztQ,
"tie_breaker" .= tb,
"type" .= mmqt,
"cutoff_frequency" .= cf,
"analyzer" .= analyzer,
"max_expansions" .= maxEx,
"lenient" .= lenient
]
instance FromJSON MultiMatchQuery where
parseJSON = withObject "MultiMatchQuery" parse
where
parse raw = do
o <- raw .: "multi_match"
MultiMatchQuery
<$> o .:? "fields" .!= []
<*> o .: "query"
<*> o .: "operator"
<*> o .: "zero_terms_query"
<*> o .:? "tie_breaker"
<*> o .:? "type"
<*> o .:? "cutoff_frequency"
<*> o .:? "analyzer"
<*> o .:? "max_expansions"
<*> o .:? "lenient"
-- | 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
-- enabling you to provide only the list of 'FieldName's and 'QueryString' to
-- make a 'MultiMatchQuery'.
mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
mkMultiMatchQuery matchFields query =
MultiMatchQuery
matchFields
query
Or
ZeroTermsNone
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
data MultiMatchQueryType
= MultiMatchBestFields
| MultiMatchMostFields
| MultiMatchCrossFields
| MultiMatchPhrase
| MultiMatchPhrasePrefix
deriving (Eq, Show, Generic)
instance ToJSON MultiMatchQueryType where
toJSON MultiMatchBestFields = "best_fields"
toJSON MultiMatchMostFields = "most_fields"
toJSON MultiMatchCrossFields = "cross_fields"
toJSON MultiMatchPhrase = "phrase"
toJSON MultiMatchPhrasePrefix = "phrase_prefix"
instance FromJSON MultiMatchQueryType where
parseJSON = withText "MultiMatchPhrasePrefix" parse
where
parse "best_fields" = pure MultiMatchBestFields
parse "most_fields" = pure MultiMatchMostFields
parse "cross_fields" = pure MultiMatchCrossFields
parse "phrase" = pure MultiMatchPhrase
parse "phrase_prefix" = pure MultiMatchPhrasePrefix
parse t = fail ("Unexpected MultiMatchPhrasePrefix: " <> show t)
data BoolQuery = BoolQuery
{ boolQueryMustMatch :: [Query],
boolQueryFilter :: [Filter],
boolQueryMustNotMatch :: [Query],
boolQueryShouldMatch :: [Query],
boolQueryMinimumShouldMatch :: Maybe MinimumMatch,
boolQueryBoost :: Maybe Boost,
boolQueryDisableCoord :: Maybe DisableCoord
}
deriving (Eq, Show, Generic)
instance ToJSON BoolQuery where
toJSON (BoolQuery mustM filterM' notM shouldM bqMin boost disableCoord) =
omitNulls base
where
base =
[ "must" .= mustM,
"filter" .= filterM',
"must_not" .= notM,
"should" .= shouldM,
"minimum_should_match" .= bqMin,
"boost" .= boost,
"disable_coord" .= disableCoord
]
instance FromJSON BoolQuery where
parseJSON = withObject "BoolQuery" parse
where
parse o =
BoolQuery
<$> o .:? "must" .!= []
<*> o .:? "filter" .!= []
<*> o .:? "must_not" .!= []
<*> o .:? "should" .!= []
<*> o .:? "minimum_should_match"
<*> o .:? "boost"
<*> o .:? "disable_coord"
mkBoolQuery :: [Query] -> [Filter] -> [Query] -> [Query] -> BoolQuery
mkBoolQuery must filt mustNot should =
BoolQuery must filt mustNot should Nothing Nothing Nothing
data BoostingQuery = BoostingQuery
{ positiveQuery :: Query,
negativeQuery :: Query,
negativeBoost :: Boost
}
deriving (Eq, Show, Generic)
instance ToJSON BoostingQuery where
toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
object
[ "positive" .= bqPositiveQuery,
"negative" .= bqNegativeQuery,
"negative_boost" .= bqNegativeBoost
]
instance FromJSON BoostingQuery where
parseJSON = withObject "BoostingQuery" parse
where
parse o =
BoostingQuery
<$> o .: "positive"
<*> o .: "negative"
<*> o .: "negative_boost"
data CommonTermsQuery = CommonTermsQuery
{ commonField :: FieldName,
commonQuery :: QueryString,
commonCutoffFrequency :: CutoffFrequency,
commonLowFreqOperator :: BooleanOperator,
commonHighFreqOperator :: BooleanOperator,
commonMinimumShouldMatch :: Maybe CommonMinimumMatch,
commonBoost :: Maybe Boost,
commonAnalyzer :: Maybe Analyzer,
commonDisableCoord :: Maybe DisableCoord
}
deriving (Eq, Show, Generic)
instance ToJSON CommonTermsQuery where
toJSON
( CommonTermsQuery
(FieldName fieldName)
(QueryString query)
cf
lfo
hfo
msm
boost
analyzer
disableCoord
) =
object [fromText fieldName .= omitNulls base]
where
base =
[ "query" .= query,
"cutoff_frequency" .= cf,
"low_freq_operator" .= lfo,
"minimum_should_match" .= msm,
"boost" .= boost,
"analyzer" .= analyzer,
"disable_coord" .= disableCoord,
"high_freq_operator" .= hfo
]
instance FromJSON CommonTermsQuery where
parseJSON = withObject "CommonTermsQuery" parse
where
parse = fieldTagged $ \fn o ->
CommonTermsQuery fn
<$> o .: "query"
<*> o .: "cutoff_frequency"
<*> o .: "low_freq_operator"
<*> o .: "high_freq_operator"
<*> o .:? "minimum_should_match"
<*> o .:? "boost"
<*> o .:? "analyzer"
<*> o .:? "disable_coord"
data CommonMinimumMatch
= CommonMinimumMatchHighLow MinimumMatchHighLow
| CommonMinimumMatch MinimumMatch
deriving (Eq, Show, Generic)
instance ToJSON CommonMinimumMatch where
toJSON (CommonMinimumMatch mm) = toJSON mm
toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
object
[ "low_freq" .= lowF,
"high_freq" .= highF
]
instance FromJSON CommonMinimumMatch where
parseJSON v =
parseMinimum v
<|> parseMinimumHighLow v
where
parseMinimum = fmap CommonMinimumMatch . parseJSON
parseMinimumHighLow =
fmap CommonMinimumMatchHighLow
. withObject
"CommonMinimumMatchHighLow"
( \o ->
MinimumMatchHighLow
<$> o .: "low_freq"
<*> o .: "high_freq"
)
data MinimumMatchHighLow = MinimumMatchHighLow
{ lowFreq :: MinimumMatch,
highFreq :: MinimumMatch
}
deriving (Eq, Show, Generic)
data ZeroTermsQuery
= ZeroTermsNone
| ZeroTermsAll
deriving (Eq, Show, Generic)
instance ToJSON ZeroTermsQuery where
toJSON ZeroTermsNone = String "none"
toJSON ZeroTermsAll = String "all"
instance FromJSON ZeroTermsQuery where
parseJSON = withText "ZeroTermsQuery" parse
where
parse "none" = pure ZeroTermsNone
parse "all" = pure ZeroTermsAll
parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
data RangeExecution
= RangeExecutionIndex
| RangeExecutionFielddata
deriving (Eq, Show, Generic)
-- index for smaller ranges, fielddata for longer ranges
instance ToJSON RangeExecution where
toJSON RangeExecutionIndex = "index"
toJSON RangeExecutionFielddata = "fielddata"
instance FromJSON RangeExecution where
parseJSON = withText "RangeExecution" parse
where
parse "index" = pure RangeExecutionIndex
parse "fielddata" = pure RangeExecutionFielddata
parse t = error ("Unrecognized RangeExecution " <> show t)
newtype Regexp = Regexp Text deriving (Eq, Show, Generic, FromJSON)
data RegexpFlags
= AllRegexpFlags
| NoRegexpFlags
| SomeRegexpFlags (NonEmpty RegexpFlag)
deriving (Eq, Show, Generic)
instance ToJSON RegexpFlags where
toJSON AllRegexpFlags = String "ALL"
toJSON NoRegexpFlags = String "NONE"
toJSON (SomeRegexpFlags (h :| fs)) = String $ T.intercalate "|" flagStrs
where
flagStrs = map flagStr . nub $ h : fs
flagStr AnyString = "ANYSTRING"
flagStr Automaton = "AUTOMATON"
flagStr Complement = "COMPLEMENT"
flagStr Empty = "EMPTY"
flagStr Intersection = "INTERSECTION"
flagStr Interval = "INTERVAL"
instance FromJSON RegexpFlags where
parseJSON = withText "RegexpFlags" parse
where
parse "ALL" = pure AllRegexpFlags
parse "NONE" = pure NoRegexpFlags
parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
data RegexpFlag
= AnyString
| Automaton
| Complement
| Empty
| Intersection
| Interval
deriving (Eq, Show, Generic)
instance FromJSON RegexpFlag where
parseJSON = withText "RegexpFlag" parse
where
parse "ANYSTRING" = pure AnyString
parse "AUTOMATON" = pure Automaton
parse "COMPLEMENT" = pure Complement
parse "EMPTY" = pure Empty
parse "INTERSECTION" = pure Intersection
parse "INTERVAL" = pure Interval
parse f = fail ("Unknown RegexpFlag: " <> show f)
newtype LessThan = LessThan Double deriving (Eq, Show, Generic)
newtype LessThanEq = LessThanEq Double deriving (Eq, Show, Generic)
newtype GreaterThan = GreaterThan Double deriving (Eq, Show, Generic)
newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Show, Generic)
newtype LessThanD = LessThanD UTCTime deriving (Eq, Show, Generic)
newtype LessThanEqD = LessThanEqD UTCTime deriving (Eq, Show, Generic)
newtype GreaterThanD = GreaterThanD UTCTime deriving (Eq, Show, Generic)
newtype GreaterThanEqD = GreaterThanEqD UTCTime deriving (Eq, Show, Generic)
data RangeValue
= RangeDateLte LessThanEqD
| RangeDateLt LessThanD
| RangeDateGte GreaterThanEqD
| RangeDateGt GreaterThanD
| RangeDateGtLt GreaterThanD LessThanD
| RangeDateGteLte GreaterThanEqD LessThanEqD
| RangeDateGteLt GreaterThanEqD LessThanD
| RangeDateGtLte GreaterThanD LessThanEqD
| RangeDoubleLte LessThanEq
| RangeDoubleLt LessThan
| RangeDoubleGte GreaterThanEq
| RangeDoubleGt GreaterThan
| RangeDoubleGtLt GreaterThan LessThan
| RangeDoubleGteLte GreaterThanEq LessThanEq
| RangeDoubleGteLt GreaterThanEq LessThan
| RangeDoubleGtLte GreaterThan LessThanEq
deriving (Eq, Show, Generic)
parseRangeValue ::
( FromJSON t4,
FromJSON t3,
FromJSON t2,
FromJSON t1
) =>
(t3 -> t5) ->
(t1 -> t6) ->
(t4 -> t7) ->
(t2 -> t8) ->
(t5 -> t6 -> b) ->
(t7 -> t6 -> b) ->
(t5 -> t8 -> b) ->
(t7 -> t8 -> b) ->
(t5 -> b) ->
(t6 -> b) ->
(t7 -> b) ->
(t8 -> b) ->
Parser b ->
Object ->
Parser b
parseRangeValue
mkGt
mkLt
mkGte
mkLte
fGtLt
fGteLt
fGtLte
fGteLte
fGt
fLt
fGte
fLte
nada
o = do
lt <- o .:? "lt"
lte <- o .:? "lte"
gt <- o .:? "gt"
gte <- o .:? "gte"
case (lt, lte, gt, gte) of
(Just a, _, Just b, _) ->
return (fGtLt (mkGt b) (mkLt a))
(Just a, _, _, Just b) ->
return (fGteLt (mkGte b) (mkLt a))
(_, Just a, Just b, _) ->
return (fGtLte (mkGt b) (mkLte a))
(_, Just a, _, Just b) ->
return (fGteLte (mkGte b) (mkLte a))
(_, _, Just a, _) ->
return (fGt (mkGt a))
(Just a, _, _, _) ->
return (fLt (mkLt a))
(_, _, _, Just a) ->
return (fGte (mkGte a))
(_, Just a, _, _) ->
return (fLte (mkLte a))
(Nothing, Nothing, Nothing, Nothing) ->
nada
instance FromJSON RangeValue where
parseJSON = withObject "RangeValue" parse
where
parse o =
parseDate o
<|> parseDouble o
parseDate o =
parseRangeValue
GreaterThanD
LessThanD
GreaterThanEqD
LessThanEqD
RangeDateGtLt
RangeDateGteLt
RangeDateGtLte
RangeDateGteLte
RangeDateGt
RangeDateLt
RangeDateGte
RangeDateLte
mzero
o
parseDouble o =
parseRangeValue
GreaterThan
LessThan
GreaterThanEq
LessThanEq
RangeDoubleGtLt
RangeDoubleGteLt
RangeDoubleGtLte
RangeDoubleGteLte
RangeDoubleGt
RangeDoubleLt
RangeDoubleGte
RangeDoubleLte
mzero
o
rangeValueToPair :: RangeValue -> [Pair]
rangeValueToPair rv = case rv of
RangeDateLte (LessThanEqD t) -> ["lte" .= t]
RangeDateGte (GreaterThanEqD t) -> ["gte" .= t]
RangeDateLt (LessThanD t) -> ["lt" .= t]
RangeDateGt (GreaterThanD t) -> ["gt" .= t]
RangeDateGteLte (GreaterThanEqD l) (LessThanEqD g) -> ["gte" .= l, "lte" .= g]
RangeDateGtLte (GreaterThanD l) (LessThanEqD g) -> ["gt" .= l, "lte" .= g]
RangeDateGteLt (GreaterThanEqD l) (LessThanD g) -> ["gte" .= l, "lt" .= g]
RangeDateGtLt (GreaterThanD l) (LessThanD g) -> ["gt" .= l, "lt" .= g]
RangeDoubleLte (LessThanEq t) -> ["lte" .= t]
RangeDoubleGte (GreaterThanEq t) -> ["gte" .= t]
RangeDoubleLt (LessThan t) -> ["lt" .= t]
RangeDoubleGt (GreaterThan t) -> ["gt" .= t]
RangeDoubleGteLte (GreaterThanEq l) (LessThanEq g) -> ["gte" .= l, "lte" .= g]
RangeDoubleGtLte (GreaterThan l) (LessThanEq g) -> ["gt" .= l, "lte" .= g]
RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g]
RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
data Term = Term
{ termField :: Key,
termValue :: Text
}
deriving (Eq, Show, Generic)
instance ToJSON Term where
toJSON (Term field value) =
object
[ "term"
.= object
[field .= value]
]
instance FromJSON Term where
parseJSON = withObject "Term" parse
where
parse o = do
termObj <- o .: "term"
case HM.toList termObj of
[(fn, v)] -> Term fn <$> parseJSON v
_ -> fail "Expected object with 1 field-named key"
data BoolMatch
= MustMatch Term Cache
| MustNotMatch Term Cache
| ShouldMatch [Term] Cache
deriving (Eq, Show, Generic)
instance ToJSON BoolMatch where
toJSON (MustMatch term cache) =
object
[ "must" .= term,
"_cache" .= cache
]
toJSON (MustNotMatch term cache) =
object
[ "must_not" .= term,
"_cache" .= cache
]
toJSON (ShouldMatch terms cache) =
object
[ "should" .= fmap toJSON terms,
"_cache" .= cache
]
instance FromJSON BoolMatch where
parseJSON = withObject "BoolMatch" parse
where
parse o =
mustMatch
`taggedWith` "must"
<|> mustNotMatch
`taggedWith` "must_not"
<|> shouldMatch
`taggedWith` "should"
where
taggedWith parser k = parser =<< o .: k
mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
mustNotMatch t = MustNotMatch t <$> o .:? "_cache" .!= defaultCache
shouldMatch t = ShouldMatch t <$> o .:? "_cache" .!= defaultCache
-- "memory" or "indexed"
data GeoFilterType
= GeoFilterMemory
| GeoFilterIndexed
deriving (Eq, Show, Generic)
instance ToJSON GeoFilterType where
toJSON GeoFilterMemory = String "memory"
toJSON GeoFilterIndexed = String "indexed"
instance FromJSON GeoFilterType where
parseJSON = withText "GeoFilterType" parse
where
parse "memory" = pure GeoFilterMemory
parse "indexed" = pure GeoFilterIndexed
parse t = fail ("Unrecognized GeoFilterType: " <> show t)
data LatLon = LatLon
{ lat :: Double,
lon :: Double
}
deriving (Eq, Show, Generic)
instance ToJSON LatLon where
toJSON (LatLon lLat lLon) =
object
[ "lat" .= lLat,
"lon" .= lLon
]
instance FromJSON LatLon where
parseJSON = withObject "LatLon" parse
where
parse o =
LatLon
<$> o .: "lat"
<*> o .: "lon"
data GeoBoundingBox = GeoBoundingBox
{ topLeft :: LatLon,
bottomRight :: LatLon
}
deriving (Eq, Show, Generic)
instance ToJSON GeoBoundingBox where
toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
object
[ "top_left" .= gbbTopLeft,
"bottom_right" .= gbbBottomRight
]
instance FromJSON GeoBoundingBox where
parseJSON = withObject "GeoBoundingBox" parse
where
parse o =
GeoBoundingBox
<$> o .: "top_left"
<*> o .: "bottom_right"
data GeoBoundingBoxConstraint = GeoBoundingBoxConstraint
{ geoBBField :: FieldName,
constraintBox :: GeoBoundingBox,
bbConstraintcache :: Cache,
geoType :: GeoFilterType
}
deriving (Eq, Show, Generic)
instance ToJSON GeoBoundingBoxConstraint where
toJSON
( GeoBoundingBoxConstraint
(FieldName gbbcGeoBBField)
gbbcConstraintBox
cache
type'
) =
object
[ fromText gbbcGeoBBField .= gbbcConstraintBox,
"_cache" .= cache,
"type" .= type'
]
instance FromJSON GeoBoundingBoxConstraint where
parseJSON = withObject "GeoBoundingBoxConstraint" parse
where
parse o = case X.toList (deleteSeveral ["type", "_cache"] o) of
[(fn, v)] ->
GeoBoundingBoxConstraint (FieldName $ toText fn)
<$> parseJSON v
<*> o .:? "_cache" .!= defaultCache
<*> o .: "type"
_ -> fail "Could not find field name for GeoBoundingBoxConstraint"
data GeoPoint = GeoPoint
{ geoField :: FieldName,
latLon :: LatLon
}
deriving (Eq, Show, Generic)
instance ToJSON GeoPoint where
toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
object [fromText geoPointField .= geoPointLatLon]
data DistanceUnit
= Miles
| Yards
| Feet
| Inches
| Kilometers
| Meters
| Centimeters
| Millimeters
| NauticalMiles
deriving (Eq, Show, Generic)
instance ToJSON DistanceUnit where
toJSON Miles = String "mi"
toJSON Yards = String "yd"
toJSON Feet = String "ft"
toJSON Inches = String "in"
toJSON Kilometers = String "km"
toJSON Meters = String "m"
toJSON Centimeters = String "cm"
toJSON Millimeters = String "mm"
toJSON NauticalMiles = String "nmi"
instance FromJSON DistanceUnit where
parseJSON = withText "DistanceUnit" parse
where
parse "mi" = pure Miles
parse "yd" = pure Yards
parse "ft" = pure Feet
parse "in" = pure Inches
parse "km" = pure Kilometers
parse "m" = pure Meters
parse "cm" = pure Centimeters
parse "mm" = pure Millimeters
parse "nmi" = pure NauticalMiles
parse u = fail ("Unrecognized DistanceUnit: " <> show u)
data DistanceType
= Arc
| SloppyArc -- doesn't exist <1.0
| Plane
deriving (Eq, Show, Generic)
instance ToJSON DistanceType where
toJSON Arc = String "arc"
toJSON SloppyArc = String "sloppy_arc"
toJSON Plane = String "plane"
instance FromJSON DistanceType where
parseJSON = withText "DistanceType" parse
where
parse "arc" = pure Arc
parse "sloppy_arc" = pure SloppyArc
parse "plane" = pure Plane
parse t = fail ("Unrecognized DistanceType: " <> show t)
data OptimizeBbox
= OptimizeGeoFilterType GeoFilterType
| NoOptimizeBbox
deriving (Eq, Show, Generic)
instance ToJSON OptimizeBbox where
toJSON NoOptimizeBbox = String "none"
toJSON (OptimizeGeoFilterType gft) = toJSON gft
instance FromJSON OptimizeBbox where
parseJSON v =
withText "NoOptimizeBbox" parseNoOptimize v
<|> parseOptimize v
where
parseNoOptimize "none" = pure NoOptimizeBbox
parseNoOptimize _ = mzero
parseOptimize = fmap OptimizeGeoFilterType . parseJSON
data Distance = Distance
{ coefficient :: Double,
unit :: DistanceUnit
}
deriving (Eq, Show, Generic)
instance ToJSON Distance where
toJSON (Distance dCoefficient dUnit) =
String boltedTogether
where
coefText = showText dCoefficient
(String unitText) = toJSON dUnit
boltedTogether = mappend coefText unitText
instance FromJSON Distance where
parseJSON = withText "Distance" parse
where
parse t =
Distance
<$> parseCoeff nT
<*> parseJSON (String unitT)
where
(nT, unitT) = T.span validForNumber t
-- may be a better way to do this
validForNumber '-' = True
validForNumber '.' = True
validForNumber 'e' = True
validForNumber c = isNumber c
parseCoeff "" = fail "Empty string cannot be parsed as number"
parseCoeff s = return (read (T.unpack s))
data DistanceRange = DistanceRange
{ distanceFrom :: Distance,
distanceTo :: Distance
}
deriving (Eq, Show, Generic)
type TemplateQueryValue = Text
newtype TemplateQueryKeyValuePairs
= TemplateQueryKeyValuePairs (X.KeyMap TemplateQueryValue)
deriving (Eq, Show)
instance ToJSON TemplateQueryKeyValuePairs where
toJSON (TemplateQueryKeyValuePairs x) = Object $ String <$> x
instance FromJSON TemplateQueryKeyValuePairs where
parseJSON (Object o) =
pure . TemplateQueryKeyValuePairs $ X.mapMaybe getValue o
where
getValue (String x) = Just x
getValue _ = Nothing
parseJSON _ =
fail "error parsing TemplateQueryKeyValuePairs"
-- | 'BooleanOperator' is the usual And/Or operators with an ES compatible
-- JSON encoding baked in. Used all over the place.
data BooleanOperator = And | Or deriving (Eq, Show, Generic)
instance ToJSON BooleanOperator where
toJSON And = String "and"
toJSON Or = String "or"
instance FromJSON BooleanOperator where
parseJSON = withText "BooleanOperator" parse
where
parse "and" = pure And
parse "or" = pure Or
parse o = fail ("Unexpected BooleanOperator: " <> show o)
-- | 'Cache' is for telling ES whether it should cache a 'Filter' not.
-- 'Query's cannot be cached.
type Cache = Bool -- caching on/off
defaultCache :: Cache
defaultCache = False
data FunctionScoreQuery = FunctionScoreQuery
{ functionScoreQuery :: Maybe Query,
functionScoreBoost :: Maybe Boost,
functionScoreFunctions :: FunctionScoreFunctions,
functionScoreMaxBoost :: Maybe Boost,
functionScoreBoostMode :: Maybe BoostMode,
functionScoreMinScore :: Score,
functionScoreScoreMode :: Maybe ScoreMode
}
deriving (Eq, Show, Generic)
instance ToJSON FunctionScoreQuery where
toJSON (FunctionScoreQuery query boost fns maxBoost boostMode minScore scoreMode) =
omitNulls base
where
base =
functionScoreFunctionsPair fns
: [ "query" .= query,
"boost" .= boost,
"max_boost" .= maxBoost,
"boost_mode" .= boostMode,
"min_score" .= minScore,
"score_mode" .= scoreMode
]
instance FromJSON FunctionScoreQuery where
parseJSON = withObject "FunctionScoreQuery" parse
where
parse o =
FunctionScoreQuery
<$> o .:? "query"
<*> o .:? "boost"
<*> ( singleFunction o
<|> multipleFunctions
`taggedWith` "functions"
)
<*> o .:? "max_boost"
<*> o .:? "boost_mode"
<*> o .:? "min_score"
<*> o .:? "score_mode"
where
taggedWith parser k = parser =<< o .: k
singleFunction = fmap FunctionScoreSingle . parseFunctionScoreFunction
multipleFunctions = pure . FunctionScoreMultiple
data FunctionScoreFunctions
= FunctionScoreSingle FunctionScoreFunction
| FunctionScoreMultiple (NonEmpty ComponentFunctionScoreFunction)
deriving (Eq, Show, Generic)
data ComponentFunctionScoreFunction = ComponentFunctionScoreFunction
{ componentScoreFunctionFilter :: Maybe Filter,
componentScoreFunction :: FunctionScoreFunction,
componentScoreFunctionWeight :: Maybe Weight
}
deriving (Eq, Show, Generic)
instance ToJSON ComponentFunctionScoreFunction where
toJSON (ComponentFunctionScoreFunction filter' fn weight) =
omitNulls base
where
base =
functionScoreFunctionPair fn
: [ "filter" .= filter',
"weight" .= weight
]
instance FromJSON ComponentFunctionScoreFunction where
parseJSON = withObject "ComponentFunctionScoreFunction" parse
where
parse o =
ComponentFunctionScoreFunction
<$> o .:? "filter"
<*> parseFunctionScoreFunction o
<*> o .:? "weight"
functionScoreFunctionsPair :: FunctionScoreFunctions -> (Key, Value)
functionScoreFunctionsPair (FunctionScoreSingle fn) =
functionScoreFunctionPair fn
functionScoreFunctionsPair (FunctionScoreMultiple componentFns) =
("functions", toJSON componentFns)
fieldTagged :: (Monad m, MonadFail m) => (FieldName -> Object -> m a) -> Object -> m a
fieldTagged f o = case X.toList o of
[(k, Object o')] -> f (FieldName $ toText k) o'
_ -> fail "Expected object with 1 field-named key"
-- | Fuzziness value as a number or 'AUTO'.
-- See:
-- https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#fuzziness
data Fuzziness = Fuzziness Double | FuzzinessAuto
deriving (Eq, Show, Generic)
instance ToJSON Fuzziness where
toJSON (Fuzziness n) = toJSON n
toJSON FuzzinessAuto = String "AUTO"
instance FromJSON Fuzziness where
parseJSON (String "AUTO") = return FuzzinessAuto
parseJSON v = Fuzziness <$> parseJSON v
data InnerHits = InnerHits
{ innerHitsFrom :: Maybe Integer,
innerHitsSize :: Maybe Integer
}
deriving (Eq, Show, Generic)
instance ToJSON InnerHits where
toJSON (InnerHits ihFrom ihSize) =
omitNulls
[ "from" .= ihFrom,
"size" .= ihSize
]
instance FromJSON InnerHits where
parseJSON = withObject "InnerHits" parse
where
parse o =
InnerHits
<$> o .:? "from"
<*> o .:? "size"