@@ -0,0 +1,1683 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
5+module Database.V1.Bloodhound.Internal.Query
7+ , module Database.V1.Bloodhound.Internal.Query
11+import Bloodhound.Import
13+import qualified Data.HashMap.Strict as HM
14+import qualified Data.Text as T
16+import Database.Bloodhound.Common.Script as X
17+import Database.V5.Bloodhound.Internal.Newtypes
21+ GeoPoint { geoField :: FieldName
22+ , latLon :: LatLon} deriving (Eq, Show)
24+instance ToJSON GeoPoint where
25+ toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
26+ object [ geoPointField .= geoPointLatLon ]
29+data LatLon = LatLon { lat :: Double
30+ , lon :: Double } deriving (Eq, Show)
32+instance ToJSON LatLon where
33+ toJSON (LatLon lLat lLon) =
34+ object ["lat" .= lLat
37+instance FromJSON LatLon where
38+ parseJSON = withObject "LatLon" parse
39+ where parse o = LatLon <$> o .: "lat"
42+data DistanceUnit = Miles
50+ | NauticalMiles deriving (Eq, Show)
52+instance ToJSON DistanceUnit where
53+ toJSON Miles = String "mi"
54+ toJSON Yards = String "yd"
55+ toJSON Feet = String "ft"
56+ toJSON Inches = String "in"
57+ toJSON Kilometers = String "km"
58+ toJSON Meters = String "m"
59+ toJSON Centimeters = String "cm"
60+ toJSON Millimeters = String "mm"
61+ toJSON NauticalMiles = String "nmi"
63+instance FromJSON DistanceUnit where
64+ parseJSON = withText "DistanceUnit" parse
65+ where parse "mi" = pure Miles
66+ parse "yd" = pure Yards
67+ parse "ft" = pure Feet
68+ parse "in" = pure Inches
69+ parse "km" = pure Kilometers
70+ parse "m" = pure Meters
71+ parse "cm" = pure Centimeters
72+ parse "mm" = pure Millimeters
73+ parse "nmi" = pure NauticalMiles
74+ parse u = fail ("Unrecognized DistanceUnit: " <> show u)
76+{-| 'Cache' is for telling ES whether it should cache a 'Filter' not.
77+ 'Query's cannot be cached.
79+type Cache = Bool -- caching on/off
82+data Filter = AndFilter [Filter] Cache
83+ | OrFilter [Filter] Cache
84+ | NotFilter Filter Cache
86+ | BoolFilter BoolMatch
87+ | ExistsFilter FieldName -- always cached
88+ | GeoBoundingBoxFilter GeoBoundingBoxConstraint
89+ | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
90+ | GeoDistanceRangeFilter GeoPoint DistanceRange
91+ | GeoPolygonFilter FieldName [LatLon]
92+ | IdsFilter MappingName [DocId]
94+ | MissingFilter FieldName Existence NullValue
95+ | PrefixFilter FieldName PrefixValue Cache
96+ | QueryFilter Query Cache
97+ | RangeFilter FieldName RangeValue RangeExecution Cache
98+ | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
99+ | TermFilter Term Cache
103+data BoolMatch = MustMatch Term Cache
104+ | MustNotMatch Term Cache
105+ | ShouldMatch [Term] Cache deriving (Eq, Show)
107+data Term = Term { termField :: Text
108+ , termValue :: Text } deriving (Eq, Show)
111+data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
112+ | NoOptimizeBbox deriving (Eq, Show)
116+ Distance { coefficient :: Double
117+ , unit :: DistanceUnit } deriving (Eq, Show)
120+ DistanceRange { distanceFrom :: Distance
121+ , distanceTo :: Distance } deriving (Eq, Show)
123+-- "memory" or "indexed"
124+data GeoFilterType = GeoFilterMemory
125+ | GeoFilterIndexed deriving (Eq, Show)
127+data GeoBoundingBoxConstraint =
128+ GeoBoundingBoxConstraint { geoBBField :: FieldName
129+ , constraintBox :: GeoBoundingBox
130+ , bbConstraintcache :: Cache
131+ , geoType :: GeoFilterType
132+ } deriving (Eq, Show)
135+data DistanceType = Arc
136+ | SloppyArc -- doesn't exist <1.0
137+ | Plane deriving (Eq, Show)
139+data GeoBoundingBox =
140+ GeoBoundingBox { topLeft :: LatLon
141+ , bottomRight :: LatLon } deriving (Eq, Show)
143+{-| 'PrefixValue' is used in 'PrefixQuery' as the main query component.
145+type PrefixValue = Text
148+data RangeValue = RangeDateLte LessThanEqD
149+ | RangeDateLt LessThanD
150+ | RangeDateGte GreaterThanEqD
151+ | RangeDateGt GreaterThanD
152+ | RangeDateGtLt GreaterThanD LessThanD
153+ | RangeDateGteLte GreaterThanEqD LessThanEqD
154+ | RangeDateGteLt GreaterThanEqD LessThanD
155+ | RangeDateGtLte GreaterThanD LessThanEqD
156+ | RangeDoubleLte LessThanEq
157+ | RangeDoubleLt LessThan
158+ | RangeDoubleGte GreaterThanEq
159+ | RangeDoubleGt GreaterThan
160+ | RangeDoubleGtLt GreaterThan LessThan
161+ | RangeDoubleGteLte GreaterThanEq LessThanEq
162+ | RangeDoubleGteLt GreaterThanEq LessThan
163+ | RangeDoubleGtLte GreaterThan LessThanEq
167+newtype LessThan = LessThan Double deriving (Eq, Show)
168+newtype LessThanEq = LessThanEq Double deriving (Eq, Show)
169+newtype GreaterThan = GreaterThan Double deriving (Eq, Show)
170+newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Show)
172+newtype LessThanD = LessThanD UTCTime deriving (Eq, Show)
173+newtype LessThanEqD = LessThanEqD UTCTime deriving (Eq, Show)
174+newtype GreaterThanD = GreaterThanD UTCTime deriving (Eq, Show)
175+newtype GreaterThanEqD = GreaterThanEqD UTCTime deriving (Eq, Show)
179+ TermQuery Term (Maybe Boost)
180+ | TermsQuery Text (NonEmpty Text)
181+ | QueryMatchQuery MatchQuery
182+ | QueryMultiMatchQuery MultiMatchQuery
183+ | QueryBoolQuery BoolQuery
184+ | QueryBoostingQuery BoostingQuery
185+ | QueryCommonTermsQuery CommonTermsQuery
186+ | ConstantScoreFilter Filter Boost
187+ | ConstantScoreQuery Query Boost
188+ | QueryDisMaxQuery DisMaxQuery
189+ | QueryFilteredQuery FilteredQuery
190+ | QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
191+ | QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
192+ | QueryFuzzyQuery FuzzyQuery
193+ | QueryHasChildQuery HasChildQuery
194+ | QueryHasParentQuery HasParentQuery
195+ | IdsQuery MappingName [DocId]
196+ | QueryIndicesQuery IndicesQuery
197+ | MatchAllQuery (Maybe Boost)
198+ | QueryMoreLikeThisQuery MoreLikeThisQuery
199+ | QueryMoreLikeThisFieldQuery MoreLikeThisFieldQuery
200+ | QueryNestedQuery NestedQuery
201+ | QueryPrefixQuery PrefixQuery
202+ | QueryQueryStringQuery QueryStringQuery
203+ | QuerySimpleQueryStringQuery SimpleQueryStringQuery
204+ | QueryRangeQuery RangeQuery
205+ | QueryRegexpQuery RegexpQuery
206+ | QueryTemplateQueryInline TemplateQueryInline
210+ RegexpQuery { regexpQueryField :: FieldName
211+ , regexpQuery :: Regexp
212+ , regexpQueryFlags :: RegexpFlags
213+ , regexpQueryBoost :: Maybe Boost
214+ } deriving (Eq, Show)
217+ RangeQuery { rangeQueryField :: FieldName
218+ , rangeQueryRange :: RangeValue
219+ , rangeQueryBoost :: Boost } deriving (Eq, Show)
221+mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
222+mkRangeQuery f r = RangeQuery f r (Boost 1.0)
224+data SimpleQueryStringQuery =
225+ SimpleQueryStringQuery
226+ { simpleQueryStringQuery :: QueryString
227+ , simpleQueryStringField :: Maybe FieldOrFields
228+ , simpleQueryStringOperator :: Maybe BooleanOperator
229+ , simpleQueryStringAnalyzer :: Maybe Analyzer
230+ , simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag)
231+ , simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded
232+ , simpleQueryStringLocale :: Maybe Locale
233+ } deriving (Eq, Show)
235+data SimpleQueryFlag =
242+ | SimpleQueryPrecedence
244+ | SimpleQueryWhitespace
247+ | SimpleQuerySlop deriving (Eq, Show)
249+-- use_dis_max and tie_breaker when fields are plural?
250+data QueryStringQuery =
252+ { queryStringQuery :: QueryString
253+ , queryStringDefaultField :: Maybe FieldName
254+ , queryStringOperator :: Maybe BooleanOperator
255+ , queryStringAnalyzer :: Maybe Analyzer
256+ , queryStringAllowLeadingWildcard :: Maybe AllowLeadingWildcard
257+ , queryStringLowercaseExpanded :: Maybe LowercaseExpanded
258+ , queryStringEnablePositionIncrements :: Maybe EnablePositionIncrements
259+ , queryStringFuzzyMaxExpansions :: Maybe MaxExpansions
260+ , queryStringFuzziness :: Maybe Fuzziness
261+ , queryStringFuzzyPrefixLength :: Maybe PrefixLength
262+ , queryStringPhraseSlop :: Maybe PhraseSlop
263+ , queryStringBoost :: Maybe Boost
264+ , queryStringAnalyzeWildcard :: Maybe AnalyzeWildcard
265+ , queryStringGeneratePhraseQueries :: Maybe GeneratePhraseQueries
266+ , queryStringMinimumShouldMatch :: Maybe MinimumMatch
267+ , queryStringLenient :: Maybe Lenient
268+ , queryStringLocale :: Maybe Locale
269+ } deriving (Eq, Show)
271+mkQueryStringQuery :: QueryString -> QueryStringQuery
272+mkQueryStringQuery qs =
273+ QueryStringQuery qs Nothing Nothing
274+ Nothing Nothing Nothing Nothing
275+ Nothing Nothing Nothing Nothing
276+ Nothing Nothing Nothing Nothing
279+data FieldOrFields = FofField FieldName
280+ | FofFields (NonEmpty FieldName) deriving (Eq, Show)
284+ { prefixQueryField :: FieldName
285+ , prefixQueryPrefixValue :: Text
286+ , prefixQueryBoost :: Maybe Boost } deriving (Eq, Show)
290+ { nestedQueryPath :: QueryPath
291+ , nestedQueryScoreType :: ScoreType
292+ , nestedQuery :: Query } deriving (Eq, Show)
294+data MoreLikeThisFieldQuery =
295+ MoreLikeThisFieldQuery
296+ { moreLikeThisFieldText :: Text
297+ , moreLikeThisFieldFields :: FieldName
298+ -- default 0.3 (30%)
299+ , moreLikeThisFieldPercentMatch :: Maybe PercentMatch
300+ , moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency
301+ , moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms
302+ , moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord)
303+ , moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency
304+ , moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency
305+ , moreLikeThisFieldMinWordLength :: Maybe MinWordLength
306+ , moreLikeThisFieldMaxWordLength :: Maybe MaxWordLength
307+ , moreLikeThisFieldBoostTerms :: Maybe BoostTerms
308+ , moreLikeThisFieldBoost :: Maybe Boost
309+ , moreLikeThisFieldAnalyzer :: Maybe Analyzer
310+ } deriving (Eq, Show)
312+data MoreLikeThisQuery =
314+ { moreLikeThisText :: Text
315+ , moreLikeThisFields :: Maybe (NonEmpty FieldName)
316+ -- default 0.3 (30%)
317+ , moreLikeThisPercentMatch :: Maybe PercentMatch
318+ , moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency
319+ , moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms
320+ , moreLikeThisStopWords :: Maybe (NonEmpty StopWord)
321+ , moreLikeThisMinDocFrequency :: Maybe MinDocFrequency
322+ , moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency
323+ , moreLikeThisMinWordLength :: Maybe MinWordLength
324+ , moreLikeThisMaxWordLength :: Maybe MaxWordLength
325+ , moreLikeThisBoostTerms :: Maybe BoostTerms
326+ , moreLikeThisBoost :: Maybe Boost
327+ , moreLikeThisAnalyzer :: Maybe Analyzer
328+ } deriving (Eq, Show)
332+ { indicesQueryIndices :: [IndexName]
333+ , indicesQuery :: Query
335+ , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Show)
337+data HasParentQuery =
339+ { hasParentQueryType :: TypeName
340+ , hasParentQuery :: Query
341+ , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Show)
345+ { hasChildQueryType :: TypeName
346+ , hasChildQuery :: Query
347+ , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Show)
353+ | ScoreTypeNone deriving (Eq, Show)
356+ FuzzyQuery { fuzzyQueryField :: FieldName
357+ , fuzzyQueryValue :: Text
358+ , fuzzyQueryPrefixLength :: PrefixLength
359+ , fuzzyQueryMaxExpansions :: MaxExpansions
360+ , fuzzyQueryFuzziness :: Fuzziness
361+ , fuzzyQueryBoost :: Maybe Boost
362+ } deriving (Eq, Show)
364+data FuzzyLikeFieldQuery =
366+ { fuzzyLikeField :: FieldName
367+ -- anaphora is good for the soul.
368+ , fuzzyLikeFieldText :: Text
369+ , fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms
370+ , fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency
371+ , fuzzyLikeFieldFuzziness :: Fuzziness
372+ , fuzzyLikeFieldPrefixLength :: PrefixLength
373+ , fuzzyLikeFieldBoost :: Boost
374+ , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
375+ } deriving (Eq, Show)
377+data FuzzyLikeThisQuery =
379+ { fuzzyLikeFields :: [FieldName]
380+ , fuzzyLikeText :: Text
381+ , fuzzyLikeMaxQueryTerms :: MaxQueryTerms
382+ , fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency
383+ , fuzzyLikeFuzziness :: Fuzziness
384+ , fuzzyLikePrefixLength :: PrefixLength
385+ , fuzzyLikeBoost :: Boost
386+ , fuzzyLikeAnalyzer :: Maybe Analyzer
387+ } deriving (Eq, Show)
391+ { filteredQuery :: Query
392+ , filteredFilter :: Filter } deriving (Eq, Show)
395+ DisMaxQuery { disMaxQueries :: [Query]
397+ , disMaxTiebreaker :: Tiebreaker
398+ , disMaxBoost :: Maybe Boost
399+ } deriving (Eq, Show)
402+ MatchQuery { matchQueryField :: FieldName
403+ , matchQueryQueryString :: QueryString
404+ , matchQueryOperator :: BooleanOperator
405+ , matchQueryZeroTerms :: ZeroTermsQuery
406+ , matchQueryCutoffFrequency :: Maybe CutoffFrequency
407+ , matchQueryMatchType :: Maybe MatchQueryType
408+ , matchQueryAnalyzer :: Maybe Analyzer
409+ , matchQueryMaxExpansions :: Maybe MaxExpansions
410+ , matchQueryLenient :: Maybe Lenient
411+ , matchQueryBoost :: Maybe Boost } deriving (Eq, Show)
413+{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
414+ enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
416+mkMatchQuery :: FieldName -> QueryString -> MatchQuery
417+mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
419+data MatchQueryType =
421+ | MatchPhrasePrefix deriving (Eq, Show)
423+data MultiMatchQuery =
424+ MultiMatchQuery { multiMatchQueryFields :: [FieldName]
425+ , multiMatchQueryString :: QueryString
426+ , multiMatchQueryOperator :: BooleanOperator
427+ , multiMatchQueryZeroTerms :: ZeroTermsQuery
428+ , multiMatchQueryTiebreaker :: Maybe Tiebreaker
429+ , multiMatchQueryType :: Maybe MultiMatchQueryType
430+ , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
431+ , multiMatchQueryAnalyzer :: Maybe Analyzer
432+ , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
433+ , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Show)
435+{-| 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
436+ enabling you to provide only the list of 'FieldName's and 'QueryString' to
437+ make a 'MultiMatchQuery'.
440+mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
441+mkMultiMatchQuery matchFields query =
442+ MultiMatchQuery matchFields query
443+ Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
445+data MultiMatchQueryType =
446+ MultiMatchBestFields
447+ | MultiMatchMostFields
448+ | MultiMatchCrossFields
450+ | MultiMatchPhrasePrefix deriving (Eq, Show)
453+ BoolQuery { boolQueryMustMatch :: [Query]
454+ , boolQueryMustNotMatch :: [Query]
455+ , boolQueryShouldMatch :: [Query]
456+ , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
457+ , boolQueryBoost :: Maybe Boost
458+ , boolQueryDisableCoord :: Maybe DisableCoord
459+ } deriving (Eq, Show)
461+mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
462+mkBoolQuery must mustNot should =
463+ BoolQuery must mustNot should Nothing Nothing Nothing
466+ BoostingQuery { positiveQuery :: Query
467+ , negativeQuery :: Query
468+ , negativeBoost :: Boost } deriving (Eq, Show)
470+data CommonTermsQuery =
471+ CommonTermsQuery { commonField :: FieldName
472+ , commonQuery :: QueryString
473+ , commonCutoffFrequency :: CutoffFrequency
474+ , commonLowFreqOperator :: BooleanOperator
475+ , commonHighFreqOperator :: BooleanOperator
476+ , commonMinimumShouldMatch :: Maybe CommonMinimumMatch
477+ , commonBoost :: Maybe Boost
478+ , commonAnalyzer :: Maybe Analyzer
479+ , commonDisableCoord :: Maybe DisableCoord
480+ } deriving (Eq, Show)
482+data CommonMinimumMatch =
483+ CommonMinimumMatchHighLow MinimumMatchHighLow
484+ | CommonMinimumMatch MinimumMatch
487+data MinimumMatchHighLow =
488+ MinimumMatchHighLow { lowFreq :: MinimumMatch
489+ , highFreq :: MinimumMatch } deriving (Eq, Show)
492+data TemplateQueryInline =
493+ TemplateQueryInline { inline :: Query
494+ , params :: TemplateQueryKeyValuePairs
498+instance ToJSON TemplateQueryInline where
499+ toJSON TemplateQueryInline{..} = object [ "query" .= inline
500+ , "params" .= params
503+instance FromJSON TemplateQueryInline where
504+ parseJSON = withObject "TemplateQueryInline" parse
505+ where parse o = TemplateQueryInline
509+{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
510+ JSON encoding baked in. Used all over the place.
512+data BooleanOperator = And | Or deriving (Eq, Show)
514+type TemplateQueryKey = Text
515+type TemplateQueryValue = Text
517+newtype TemplateQueryKeyValuePairs = TemplateQueryKeyValuePairs (HM.HashMap TemplateQueryKey TemplateQueryValue)
520+instance ToJSON TemplateQueryKeyValuePairs where
521+ toJSON (TemplateQueryKeyValuePairs x) = Object $ HM.map toJSON x
523+instance FromJSON TemplateQueryKeyValuePairs where
524+ parseJSON (Object o) = pure . TemplateQueryKeyValuePairs $ HM.mapMaybe getValue o
525+ where getValue (String x) = Just x
526+ getValue _ = Nothing
527+ parseJSON _ = fail "error parsing TemplateQueryKeyValuePairs"
529+newtype Regexp = Regexp Text deriving (Eq, Show, FromJSON)
531+data RegexpFlags = AllRegexpFlags
533+ | SomeRegexpFlags (NonEmpty RegexpFlag) deriving (Eq, Show)
535+data RegexpFlag = AnyString
540+ | Interval deriving (Eq, Show)
542+data RangeExecution = RangeExecutionIndex
543+ | RangeExecutionFielddata deriving (Eq, Show)
545+data ZeroTermsQuery = ZeroTermsNone
546+ | ZeroTermsAll deriving (Eq, Show)
548+instance ToJSON Query where
549+ toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
551+ object [termQueryField .= object merged]]
553+ base = [ "value" .= termQueryValue ]
554+ boosted = maybe [] (return . ("boost" .=)) boost
555+ merged = mappend base boosted
557+ toJSON (TermsQuery fieldName terms) =
558+ object [ "terms" .= object conjoined ]
559+ where conjoined = [fieldName .= terms]
561+ toJSON (IdsQuery idsQueryMappingName docIds) =
562+ object [ "ids" .= object conjoined ]
563+ where conjoined = [ "type" .= idsQueryMappingName
564+ , "values" .= fmap toJSON docIds ]
566+ toJSON (QueryQueryStringQuery qQueryStringQuery) =
567+ object [ "query_string" .= qQueryStringQuery ]
569+ toJSON (QueryMatchQuery matchQuery) =
570+ object [ "match" .= matchQuery ]
572+ toJSON (QueryMultiMatchQuery multiMatchQuery) =
573+ toJSON multiMatchQuery
575+ toJSON (QueryBoolQuery boolQuery) =
576+ object [ "bool" .= boolQuery ]
578+ toJSON (QueryBoostingQuery boostingQuery) =
579+ object [ "boosting" .= boostingQuery ]
581+ toJSON (QueryCommonTermsQuery commonTermsQuery) =
582+ object [ "common" .= commonTermsQuery ]
584+ toJSON (ConstantScoreFilter csFilter boost) =
585+ object ["constant_score" .= object ["filter" .= csFilter
586+ , "boost" .= boost]]
588+ toJSON (ConstantScoreQuery query boost) =
589+ object ["constant_score" .= object ["query" .= query
590+ , "boost" .= boost]]
592+ toJSON (QueryDisMaxQuery disMaxQuery) =
593+ object [ "dis_max" .= disMaxQuery ]
595+ toJSON (QueryFilteredQuery qFilteredQuery) =
596+ object [ "filtered" .= qFilteredQuery ]
598+ toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
599+ object [ "fuzzy_like_this" .= fuzzyQuery ]
601+ toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
602+ object [ "fuzzy_like_this_field" .= fuzzyFieldQuery ]
604+ toJSON (QueryFuzzyQuery fuzzyQuery) =
605+ object [ "fuzzy" .= fuzzyQuery ]
607+ toJSON (QueryHasChildQuery childQuery) =
608+ object [ "has_child" .= childQuery ]
610+ toJSON (QueryHasParentQuery parentQuery) =
611+ object [ "has_parent" .= parentQuery ]
613+ toJSON (QueryIndicesQuery qIndicesQuery) =
614+ object [ "indices" .= qIndicesQuery ]
616+ toJSON (MatchAllQuery boost) =
617+ object [ "match_all" .= omitNulls [ "boost" .= boost ] ]
619+ toJSON (QueryMoreLikeThisQuery query) =
620+ object [ "more_like_this" .= query ]
622+ toJSON (QueryMoreLikeThisFieldQuery query) =
623+ object [ "more_like_this_field" .= query ]
625+ toJSON (QueryNestedQuery query) =
626+ object [ "nested" .= query ]
628+ toJSON (QueryPrefixQuery query) =
629+ object [ "prefix" .= query ]
631+ toJSON (QueryRangeQuery query) =
632+ object [ "range" .= query ]
634+ toJSON (QueryRegexpQuery query) =
635+ object [ "regexp" .= query ]
637+ toJSON (QuerySimpleQueryStringQuery query) =
638+ object [ "simple_query_string" .= query ]
640+ toJSON (QueryTemplateQueryInline templateQuery) =
641+ object [ "template" .= templateQuery ]
643+instance FromJSON Query where
644+ parseJSON v = withObject "Query" parse v
645+ where parse o = termQuery `taggedWith` "term"
646+ <|> termsQuery `taggedWith` "terms"
647+ <|> idsQuery `taggedWith` "ids"
648+ <|> queryQueryStringQuery `taggedWith` "query_string"
649+ <|> queryMatchQuery `taggedWith` "match"
650+ <|> queryMultiMatchQuery
651+ <|> queryBoolQuery `taggedWith` "bool"
652+ <|> queryBoostingQuery `taggedWith` "boosting"
653+ <|> queryCommonTermsQuery `taggedWith` "common"
654+ <|> constantScoreFilter `taggedWith` "constant_score"
655+ <|> constantScoreQuery `taggedWith` "constant_score"
656+ <|> queryDisMaxQuery `taggedWith` "dis_max"
657+ <|> queryFilteredQuery `taggedWith` "filtered"
658+ <|> queryFuzzyLikeThisQuery `taggedWith` "fuzzy_like_this"
659+ <|> queryFuzzyLikeFieldQuery `taggedWith` "fuzzy_like_this_field"
660+ <|> queryFuzzyQuery `taggedWith` "fuzzy"
661+ <|> queryHasChildQuery `taggedWith` "has_child"
662+ <|> queryHasParentQuery `taggedWith` "has_parent"
663+ <|> queryIndicesQuery `taggedWith` "indices"
664+ <|> matchAllQuery `taggedWith` "match_all"
665+ <|> queryMoreLikeThisQuery `taggedWith` "more_like_this"
666+ <|> queryMoreLikeThisFieldQuery `taggedWith` "more_like_this_field"
667+ <|> queryNestedQuery `taggedWith` "nested"
668+ <|> queryPrefixQuery `taggedWith` "prefix"
669+ <|> queryRangeQuery `taggedWith` "range"
670+ <|> queryRegexpQuery `taggedWith` "regexp"
671+ <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
672+ <|> queryTemplateQueryInline `taggedWith` "template"
673+ where taggedWith parser k = parser =<< o .: k
674+ termQuery = fieldTagged $ \(FieldName fn) o ->
675+ TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
676+ termsQuery o = case HM.toList o of
677+ [(fn, vs)] -> do vals <- parseJSON vs
679+ x:xs -> return (TermsQuery fn (x :| xs))
680+ _ -> fail "Expected non empty list of values"
681+ _ -> fail "Expected object with 1 field-named key"
682+ idsQuery o = IdsQuery <$> o .: "type"
684+ queryQueryStringQuery = pure . QueryQueryStringQuery
685+ queryMatchQuery = pure . QueryMatchQuery
686+ queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
687+ queryBoolQuery = pure . QueryBoolQuery
688+ queryBoostingQuery = pure . QueryBoostingQuery
689+ queryCommonTermsQuery = pure . QueryCommonTermsQuery
690+ constantScoreFilter o = case HM.lookup "filter" o of
691+ Just x -> ConstantScoreFilter <$> parseJSON x
693+ _ -> fail "Does not appear to be a ConstantScoreFilter"
694+ constantScoreQuery o = case HM.lookup "query" o of
695+ Just x -> ConstantScoreQuery <$> parseJSON x
697+ _ -> fail "Does not appear to be a ConstantScoreQuery"
698+ queryDisMaxQuery = pure . QueryDisMaxQuery
699+ queryFilteredQuery = pure . QueryFilteredQuery
700+ queryFuzzyLikeThisQuery = pure . QueryFuzzyLikeThisQuery
701+ queryFuzzyLikeFieldQuery = pure . QueryFuzzyLikeFieldQuery
702+ queryFuzzyQuery = pure . QueryFuzzyQuery
703+ queryHasChildQuery = pure . QueryHasChildQuery
704+ queryHasParentQuery = pure . QueryHasParentQuery
705+ queryIndicesQuery = pure . QueryIndicesQuery
706+ matchAllQuery o = MatchAllQuery <$> o .:? "boost"
707+ queryMoreLikeThisQuery = pure . QueryMoreLikeThisQuery
708+ queryMoreLikeThisFieldQuery = pure . QueryMoreLikeThisFieldQuery
709+ queryNestedQuery = pure . QueryNestedQuery
710+ queryPrefixQuery = pure . QueryPrefixQuery
711+ queryRangeQuery = pure . QueryRangeQuery
712+ queryRegexpQuery = pure . QueryRegexpQuery
713+ querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
714+ queryTemplateQueryInline = pure . QueryTemplateQueryInline
716+instance ToJSON SimpleQueryStringQuery where
717+ toJSON SimpleQueryStringQuery {..} =
718+ omitNulls (base ++ maybeAdd)
719+ where base = [ "query" .= simpleQueryStringQuery ]
720+ maybeAdd = [ "fields" .= simpleQueryStringField
721+ , "default_operator" .= simpleQueryStringOperator
722+ , "analyzer" .= simpleQueryStringAnalyzer
723+ , "flags" .= simpleQueryStringFlags
724+ , "lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded
725+ , "locale" .= simpleQueryStringLocale ]
727+instance FromJSON SimpleQueryStringQuery where
728+ parseJSON = withObject "SimpleQueryStringQuery" parse
729+ where parse o = SimpleQueryStringQuery <$> o .: "query"
731+ <*> o .:? "default_operator"
732+ <*> o .:? "analyzer"
733+ <*> (parseFlags <$> o .:? "flags")
734+ <*> o .:? "lowercase_expanded_terms"
736+ parseFlags (Just (x:xs)) = Just (x :| xs)
737+ parseFlags _ = Nothing
739+instance ToJSON FieldOrFields where
740+ toJSON (FofField fieldName) =
742+ toJSON (FofFields fieldNames) =
745+instance FromJSON FieldOrFields where
746+ parseJSON v = FofField <$> parseJSON v
747+ <|> FofFields <$> (parseNEJSON =<< parseJSON v)
749+instance ToJSON SimpleQueryFlag where
750+ toJSON SimpleQueryAll = "ALL"
751+ toJSON SimpleQueryNone = "NONE"
752+ toJSON SimpleQueryAnd = "AND"
753+ toJSON SimpleQueryOr = "OR"
754+ toJSON SimpleQueryPrefix = "PREFIX"
755+ toJSON SimpleQueryPhrase = "PHRASE"
756+ toJSON SimpleQueryPrecedence = "PRECEDENCE"
757+ toJSON SimpleQueryEscape = "ESCAPE"
758+ toJSON SimpleQueryWhitespace = "WHITESPACE"
759+ toJSON SimpleQueryFuzzy = "FUZZY"
760+ toJSON SimpleQueryNear = "NEAR"
761+ toJSON SimpleQuerySlop = "SLOP"
763+instance FromJSON SimpleQueryFlag where
764+ parseJSON = withText "SimpleQueryFlag" parse
765+ where parse "ALL" = pure SimpleQueryAll
766+ parse "NONE" = pure SimpleQueryNone
767+ parse "AND" = pure SimpleQueryAnd
768+ parse "OR" = pure SimpleQueryOr
769+ parse "PREFIX" = pure SimpleQueryPrefix
770+ parse "PHRASE" = pure SimpleQueryPhrase
771+ parse "PRECEDENCE" = pure SimpleQueryPrecedence
772+ parse "ESCAPE" = pure SimpleQueryEscape
773+ parse "WHITESPACE" = pure SimpleQueryWhitespace
774+ parse "FUZZY" = pure SimpleQueryFuzzy
775+ parse "NEAR" = pure SimpleQueryNear
776+ parse "SLOP" = pure SimpleQuerySlop
777+ parse f = fail ("Unexpected SimpleQueryFlag: " <> show f)
779+instance ToJSON RegexpQuery where
780+ toJSON (RegexpQuery (FieldName rqQueryField)
781+ (Regexp regexpQueryQuery) rqQueryFlags
783+ object [ rqQueryField .= omitNulls base ]
784+ where base = [ "value" .= regexpQueryQuery
785+ , "flags" .= rqQueryFlags
786+ , "boost" .= rqQueryBoost ]
788+instance FromJSON RegexpQuery where
789+ parseJSON = withObject "RegexpQuery" parse
790+ where parse = fieldTagged $ \fn o ->
796+instance ToJSON QueryStringQuery where
797+ toJSON (QueryStringQuery qsQueryString
798+ qsDefaultField qsOperator
799+ qsAnalyzer qsAllowWildcard
800+ qsLowercaseExpanded qsEnablePositionIncrements
801+ qsFuzzyMaxExpansions qsFuzziness
802+ qsFuzzyPrefixLength qsPhraseSlop
803+ qsBoost qsAnalyzeWildcard
804+ qsGeneratePhraseQueries qsMinimumShouldMatch
805+ qsLenient qsLocale) =
808+ base = [ "query" .= qsQueryString
809+ , "default_field" .= qsDefaultField
810+ , "default_operator" .= qsOperator
811+ , "analyzer" .= qsAnalyzer
812+ , "allow_leading_wildcard" .= qsAllowWildcard
813+ , "lowercase_expanded_terms" .= qsLowercaseExpanded
814+ , "enable_position_increments" .= qsEnablePositionIncrements
815+ , "fuzzy_max_expansions" .= qsFuzzyMaxExpansions
816+ , "fuzziness" .= qsFuzziness
817+ , "fuzzy_prefix_length" .= qsFuzzyPrefixLength
818+ , "phrase_slop" .= qsPhraseSlop
819+ , "boost" .= qsBoost
820+ , "analyze_wildcard" .= qsAnalyzeWildcard
821+ , "auto_generate_phrase_queries" .= qsGeneratePhraseQueries
822+ , "minimum_should_match" .= qsMinimumShouldMatch
823+ , "lenient" .= qsLenient
824+ , "locale" .= qsLocale ]
826+instance FromJSON QueryStringQuery where
827+ parseJSON = withObject "QueryStringQuery" parse
828+ where parse o = QueryStringQuery
830+ <*> o .:? "default_field"
831+ <*> o .:? "default_operator"
832+ <*> o .:? "analyzer"
833+ <*> o .:? "allow_leading_wildcard"
834+ <*> o .:? "lowercase_expanded_terms"
835+ <*> o .:? "enable_position_increments"
836+ <*> o .:? "fuzzy_max_expansions"
837+ <*> o .:? "fuzziness"
838+ <*> o .:? "fuzzy_prefix_length"
839+ <*> o .:? "phrase_slop"
841+ <*> o .:? "analyze_wildcard"
842+ <*> o .:? "auto_generate_phrase_queries"
843+ <*> o .:? "minimum_should_match"
847+instance ToJSON RangeQuery where
848+ toJSON (RangeQuery (FieldName fieldName) range boost) =
849+ object [ fieldName .= object conjoined ]
850+ where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
852+instance FromJSON RangeQuery where
853+ parseJSON = withObject "RangeQuery" parse
854+ where parse = fieldTagged $ \fn o ->
856+ <$> parseJSON (Object o)
859+instance FromJSON RangeValue where
860+ parseJSON = withObject "RangeValue" parse
861+ where parse o = parseDate o
863+ parseDate o = do lt <- o .:? "lt"
867+ case (lt, lte, gt, gte) of
868+ (Just a, _, Just b, _) -> return (RangeDateGtLt (GreaterThanD b) (LessThanD a))
869+ (Just a, _, _, Just b)-> return (RangeDateGteLt (GreaterThanEqD b) (LessThanD a))
870+ (_, Just a, Just b, _)-> return (RangeDateGtLte (GreaterThanD b) (LessThanEqD a))
871+ (_, Just a, _, Just b)-> return (RangeDateGteLte (GreaterThanEqD b) (LessThanEqD a))
872+ (_, _, Just a, _)-> return (RangeDateGt (GreaterThanD a))
873+ (Just a, _, _, _)-> return (RangeDateLt (LessThanD a))
874+ (_, _, _, Just a)-> return (RangeDateGte (GreaterThanEqD a))
875+ (_, Just a, _, _)-> return (RangeDateLte (LessThanEqD a))
876+ (Nothing, Nothing, Nothing, Nothing) -> mzero
877+ parseDouble o = do lt <- o .:? "lt"
881+ case (lt, lte, gt, gte) of
882+ (Just a, _, Just b, _) -> return (RangeDoubleGtLt (GreaterThan b) (LessThan a))
883+ (Just a, _, _, Just b)-> return (RangeDoubleGteLt (GreaterThanEq b) (LessThan a))
884+ (_, Just a, Just b, _)-> return (RangeDoubleGtLte (GreaterThan b) (LessThanEq a))
885+ (_, Just a, _, Just b)-> return (RangeDoubleGteLte (GreaterThanEq b) (LessThanEq a))
886+ (_, _, Just a, _)-> return (RangeDoubleGt (GreaterThan a))
887+ (Just a, _, _, _)-> return (RangeDoubleLt (LessThan a))
888+ (_, _, _, Just a)-> return (RangeDoubleGte (GreaterThanEq a))
889+ (_, Just a, _, _)-> return (RangeDoubleLte (LessThanEq a))
890+ (Nothing, Nothing, Nothing, Nothing) -> mzero
892+instance ToJSON PrefixQuery where
893+ toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
894+ object [ fieldName .= omitNulls base ]
895+ where base = [ "value" .= queryValue
896+ , "boost" .= boost ]
898+instance FromJSON PrefixQuery where
899+ parseJSON = withObject "PrefixQuery" parse
900+ where parse = fieldTagged $ \fn o ->
905+instance ToJSON NestedQuery where
906+ toJSON (NestedQuery nqPath nqScoreType nqQuery) =
907+ object [ "path" .= nqPath
908+ , "score_mode" .= nqScoreType
909+ , "query" .= nqQuery ]
911+instance FromJSON NestedQuery where
912+ parseJSON = withObject "NestedQuery" parse
913+ where parse o = NestedQuery
915+ <*> o .: "score_mode"
918+instance ToJSON MoreLikeThisFieldQuery where
919+ toJSON (MoreLikeThisFieldQuery text (FieldName fieldName)
920+ percent mtf mqt stopwords mindf maxdf
921+ minwl maxwl boostTerms boost analyzer) =
922+ object [ fieldName .= omitNulls base ]
923+ where base = [ "like_text" .= text
924+ , "percent_terms_to_match" .= percent
925+ , "min_term_freq" .= mtf
926+ , "max_query_terms" .= mqt
927+ , "stop_words" .= stopwords
928+ , "min_doc_freq" .= mindf
929+ , "max_doc_freq" .= maxdf
930+ , "min_word_length" .= minwl
931+ , "max_word_length" .= maxwl
932+ , "boost_terms" .= boostTerms
934+ , "analyzer" .= analyzer ]
936+instance FromJSON MoreLikeThisFieldQuery where
937+ parseJSON = withObject "MoreLikeThisFieldQuery" parse
938+ where parse = fieldTagged $ \fn o ->
939+ MoreLikeThisFieldQuery
940+ <$> o .: "like_text"
942+ <*> o .:? "percent_terms_to_match"
943+ <*> o .:? "min_term_freq"
944+ <*> o .:? "max_query_terms"
945+ -- <*> (optionalNE =<< o .:? "stop_words")
946+ <*> o .:? "stop_words"
947+ <*> o .:? "min_doc_freq"
948+ <*> o .:? "max_doc_freq"
949+ <*> o .:? "min_word_length"
950+ <*> o .:? "max_word_length"
951+ <*> o .:? "boost_terms"
953+ <*> o .:? "analyzer"
954+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
956+instance ToJSON MoreLikeThisQuery where
957+ toJSON (MoreLikeThisQuery text fields percent
958+ mtf mqt stopwords mindf maxdf
959+ minwl maxwl boostTerms boost analyzer) =
961+ where base = [ "like_text" .= text
962+ , "fields" .= fields
963+ , "percent_terms_to_match" .= percent
964+ , "min_term_freq" .= mtf
965+ , "max_query_terms" .= mqt
966+ , "stop_words" .= stopwords
967+ , "min_doc_freq" .= mindf
968+ , "max_doc_freq" .= maxdf
969+ , "min_word_length" .= minwl
970+ , "max_word_length" .= maxwl
971+ , "boost_terms" .= boostTerms
973+ , "analyzer" .= analyzer ]
975+instance FromJSON MoreLikeThisQuery where
976+ parseJSON = withObject "MoreLikeThisQuery" parse
977+ where parse o = MoreLikeThisQuery
978+ <$> o .: "like_text"
979+ -- <*> (optionalNE =<< o .:? "fields")
981+ <*> o .:? "percent_terms_to_match"
982+ <*> o .:? "min_term_freq"
983+ <*> o .:? "max_query_terms"
984+ -- <*> (optionalNE =<< o .:? "stop_words")
985+ <*> o .:? "stop_words"
986+ <*> o .:? "min_doc_freq"
987+ <*> o .:? "max_doc_freq"
988+ <*> o .:? "min_word_length"
989+ <*> o .:? "max_word_length"
990+ <*> o .:? "boost_terms"
992+ <*> o .:? "analyzer"
993+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
995+instance ToJSON IndicesQuery where
996+ toJSON (IndicesQuery indices query noMatch) =
997+ omitNulls [ "indices" .= indices
998+ , "no_match_query" .= noMatch
999+ , "query" .= query ]
1001+instance FromJSON IndicesQuery where
1002+ parseJSON = withObject "IndicesQuery" parse
1003+ where parse o = IndicesQuery
1004+ <$> o .:? "indices" .!= []
1006+ <*> o .:? "no_match_query"
1008+instance ToJSON HasParentQuery where
1009+ toJSON (HasParentQuery queryType query scoreType) =
1010+ omitNulls [ "parent_type" .= queryType
1011+ , "score_type" .= scoreType
1012+ , "query" .= query ]
1014+instance FromJSON HasParentQuery where
1015+ parseJSON = withObject "HasParentQuery" parse
1016+ where parse o = HasParentQuery
1017+ <$> o .: "parent_type"
1019+ <*> o .:? "score_type"
1021+instance ToJSON HasChildQuery where
1022+ toJSON (HasChildQuery queryType query scoreType) =
1023+ omitNulls [ "query" .= query
1024+ , "score_type" .= scoreType
1025+ , "type" .= queryType ]
1027+instance FromJSON HasChildQuery where
1028+ parseJSON = withObject "HasChildQuery" parse
1029+ where parse o = HasChildQuery
1032+ <*> o .:? "score_type"
1034+instance ToJSON FuzzyQuery where
1035+ toJSON (FuzzyQuery (FieldName fieldName) queryText
1036+ prefixLength maxEx fuzziness boost) =
1037+ object [ fieldName .= omitNulls base ]
1038+ where base = [ "value" .= queryText
1039+ , "fuzziness" .= fuzziness
1040+ , "prefix_length" .= prefixLength
1042+ , "max_expansions" .= maxEx ]
1044+instance FromJSON FuzzyQuery where
1045+ parseJSON = withObject "FuzzyQuery" parse
1046+ where parse = fieldTagged $ \fn o ->
1049+ <*> o .: "prefix_length"
1050+ <*> o .: "max_expansions"
1051+ <*> o .: "fuzziness"
1054+instance ToJSON FuzzyLikeFieldQuery where
1055+ toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
1056+ fieldText maxTerms ignoreFreq fuzziness prefixLength
1058+ object [ fieldName .=
1059+ omitNulls [ "like_text" .= fieldText
1060+ , "max_query_terms" .= maxTerms
1061+ , "ignore_tf" .= ignoreFreq
1062+ , "fuzziness" .= fuzziness
1063+ , "prefix_length" .= prefixLength
1064+ , "analyzer" .= analyzer
1065+ , "boost" .= boost ]]
1067+instance FromJSON FuzzyLikeFieldQuery where
1068+ parseJSON = withObject "FuzzyLikeFieldQuery" parse
1069+ where parse = fieldTagged $ \fn o ->
1070+ FuzzyLikeFieldQuery fn
1071+ <$> o .: "like_text"
1072+ <*> o .: "max_query_terms"
1073+ <*> o .: "ignore_tf"
1074+ <*> o .: "fuzziness"
1075+ <*> o .: "prefix_length"
1077+ <*> o .:? "analyzer"
1079+instance ToJSON FuzzyLikeThisQuery where
1080+ toJSON (FuzzyLikeThisQuery fields text maxTerms
1081+ ignoreFreq fuzziness prefixLength boost analyzer) =
1083+ where base = [ "fields" .= fields
1084+ , "like_text" .= text
1085+ , "max_query_terms" .= maxTerms
1086+ , "ignore_tf" .= ignoreFreq
1087+ , "fuzziness" .= fuzziness
1088+ , "prefix_length" .= prefixLength
1089+ , "analyzer" .= analyzer
1090+ , "boost" .= boost ]
1092+instance FromJSON FuzzyLikeThisQuery where
1093+ parseJSON = withObject "FuzzyLikeThisQuery" parse
1094+ where parse o = FuzzyLikeThisQuery
1095+ <$> o .:? "fields" .!= []
1096+ <*> o .: "like_text"
1097+ <*> o .: "max_query_terms"
1098+ <*> o .: "ignore_tf"
1099+ <*> o .: "fuzziness"
1100+ <*> o .: "prefix_length"
1102+ <*> o .:? "analyzer"
1104+instance ToJSON FilteredQuery where
1105+ toJSON (FilteredQuery query fFilter) =
1106+ object [ "query" .= query
1107+ , "filter" .= fFilter ]
1109+instance FromJSON FilteredQuery where
1110+ parseJSON = withObject "FilteredQuery" parse
1111+ where parse o = FilteredQuery
1115+instance ToJSON DisMaxQuery where
1116+ toJSON (DisMaxQuery queries tiebreaker boost) =
1118+ where base = [ "queries" .= queries
1120+ , "tie_breaker" .= tiebreaker ]
1122+instance FromJSON DisMaxQuery where
1123+ parseJSON = withObject "DisMaxQuery" parse
1124+ where parse o = DisMaxQuery
1125+ <$> o .:? "queries" .!= []
1126+ <*> o .: "tie_breaker"
1129+instance ToJSON CommonTermsQuery where
1130+ toJSON (CommonTermsQuery (FieldName fieldName)
1131+ (QueryString query) cf lfo hfo msm
1132+ boost analyzer disableCoord) =
1133+ object [fieldName .= omitNulls base ]
1134+ where base = [ "query" .= query
1135+ , "cutoff_frequency" .= cf
1136+ , "low_freq_operator" .= lfo
1137+ , "minimum_should_match" .= msm
1139+ , "analyzer" .= analyzer
1140+ , "disable_coord" .= disableCoord
1141+ , "high_freq_operator" .= hfo ]
1143+instance FromJSON CommonTermsQuery where
1144+ parseJSON = withObject "CommonTermsQuery" parse
1145+ where parse = fieldTagged $ \fn o ->
1146+ CommonTermsQuery fn
1148+ <*> o .: "cutoff_frequency"
1149+ <*> o .: "low_freq_operator"
1150+ <*> o .: "high_freq_operator"
1151+ <*> o .:? "minimum_should_match"
1153+ <*> o .:? "analyzer"
1154+ <*> o .:? "disable_coord"
1156+instance ToJSON CommonMinimumMatch where
1157+ toJSON (CommonMinimumMatch mm) = toJSON mm
1158+ toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
1159+ object [ "low_freq" .= lowF
1160+ , "high_freq" .= highF ]
1162+instance FromJSON CommonMinimumMatch where
1163+ parseJSON v = parseMinimum v
1164+ <|> parseMinimumHighLow v
1165+ where parseMinimum = fmap CommonMinimumMatch . parseJSON
1166+ parseMinimumHighLow = fmap CommonMinimumMatchHighLow . withObject "CommonMinimumMatchHighLow" (\o ->
1167+ MinimumMatchHighLow
1168+ <$> o .: "low_freq"
1169+ <*> o .: "high_freq")
1172+instance ToJSON BoostingQuery where
1173+ toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
1174+ object [ "positive" .= bqPositiveQuery
1175+ , "negative" .= bqNegativeQuery
1176+ , "negative_boost" .= bqNegativeBoost ]
1178+instance FromJSON BoostingQuery where
1179+ parseJSON = withObject "BoostingQuery" parse
1180+ where parse o = BoostingQuery
1181+ <$> o .: "positive"
1182+ <*> o .: "negative"
1183+ <*> o .: "negative_boost"
1185+instance ToJSON BoolQuery where
1186+ toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
1188+ where base = [ "must" .= mustM
1189+ , "must_not" .= notM
1190+ , "should" .= shouldM
1191+ , "minimum_should_match" .= bqMin
1193+ , "disable_coord" .= disableCoord ]
1195+instance FromJSON BoolQuery where
1196+ parseJSON = withObject "BoolQuery" parse
1197+ where parse o = BoolQuery
1198+ <$> o .:? "must" .!= []
1199+ <*> o .:? "must_not" .!= []
1200+ <*> o .:? "should" .!= []
1201+ <*> o .:? "minimum_should_match"
1203+ <*> o .:? "disable_coord"
1205+instance ToJSON MatchQuery where
1206+ toJSON (MatchQuery (FieldName fieldName)
1207+ (QueryString mqQueryString) booleanOperator
1208+ zeroTermsQuery cutoffFrequency matchQueryType
1209+ analyzer maxExpansions lenient boost) =
1210+ object [ fieldName .= omitNulls base ]
1211+ where base = [ "query" .= mqQueryString
1212+ , "operator" .= booleanOperator
1213+ , "zero_terms_query" .= zeroTermsQuery
1214+ , "cutoff_frequency" .= cutoffFrequency
1215+ , "type" .= matchQueryType
1216+ , "analyzer" .= analyzer
1217+ , "max_expansions" .= maxExpansions
1218+ , "lenient" .= lenient
1219+ , "boost" .= boost ]
1221+instance FromJSON MatchQuery where
1222+ parseJSON = withObject "MatchQuery" parse
1223+ where parse = fieldTagged $ \fn o ->
1226+ <*> o .: "operator"
1227+ <*> o .: "zero_terms_query"
1228+ <*> o .:? "cutoff_frequency"
1230+ <*> o .:? "analyzer"
1231+ <*> o .:? "max_expansions"
1232+ <*> o .:? "lenient"
1235+instance ToJSON MultiMatchQuery where
1236+ toJSON (MultiMatchQuery fields (QueryString query) boolOp
1237+ ztQ tb mmqt cf analyzer maxEx lenient) =
1238+ object ["multi_match" .= omitNulls base]
1239+ where base = [ "fields" .= fmap toJSON fields
1241+ , "operator" .= boolOp
1242+ , "zero_terms_query" .= ztQ
1243+ , "tie_breaker" .= tb
1245+ , "cutoff_frequency" .= cf
1246+ , "analyzer" .= analyzer
1247+ , "max_expansions" .= maxEx
1248+ , "lenient" .= lenient ]
1250+instance FromJSON MultiMatchQuery where
1251+ parseJSON = withObject "MultiMatchQuery" parse
1252+ where parse raw = do o <- raw .: "multi_match"
1254+ <$> o .:? "fields" .!= []
1256+ <*> o .: "operator"
1257+ <*> o .: "zero_terms_query"
1258+ <*> o .:? "tie_breaker"
1260+ <*> o .:? "cutoff_frequency"
1261+ <*> o .:? "analyzer"
1262+ <*> o .:? "max_expansions"
1263+ <*> o .:? "lenient"
1265+instance ToJSON Filter where
1266+ toJSON (AndFilter filters cache) =
1268+ object [ "filters" .= fmap toJSON filters
1269+ , "_cache" .= cache]]
1271+ toJSON (OrFilter filters cache) =
1273+ object [ "filters" .= fmap toJSON filters
1274+ , "_cache" .= cache]]
1276+ toJSON (NotFilter notFilter cache) =
1278+ object ["filter" .= notFilter
1279+ , "_cache" .= cache]]
1281+ toJSON (IdentityFilter) =
1282+ object ["match_all" .= object []]
1284+ toJSON (TermFilter (Term termFilterField termFilterValue) cache) =
1285+ object ["term" .= object base]
1286+ where base = [termFilterField .= termFilterValue,
1289+ toJSON (ExistsFilter (FieldName fieldName)) =
1290+ object ["exists" .= object
1291+ ["field" .= fieldName]]
1293+ toJSON (BoolFilter boolMatch) =
1294+ object ["bool" .= boolMatch]
1296+ toJSON (GeoBoundingBoxFilter bbConstraint) =
1297+ object ["geo_bounding_box" .= bbConstraint]
1299+ toJSON (GeoDistanceFilter (GeoPoint (FieldName distanceGeoField) geoDistLatLon)
1300+ distance distanceType optimizeBbox cache) =
1301+ object ["geo_distance" .=
1302+ object ["distance" .= distance
1303+ , "distance_type" .= distanceType
1304+ , "optimize_bbox" .= optimizeBbox
1305+ , distanceGeoField .= geoDistLatLon
1306+ , "_cache" .= cache]]
1308+ toJSON (GeoDistanceRangeFilter (GeoPoint (FieldName gddrField) drLatLon)
1309+ (DistanceRange geoDistRangeDistFrom drDistanceTo)) =
1310+ object ["geo_distance_range" .=
1311+ object ["from" .= geoDistRangeDistFrom
1312+ , "to" .= drDistanceTo
1313+ , gddrField .= drLatLon]]
1315+ toJSON (GeoPolygonFilter (FieldName geoPolygonFilterField) latLons) =
1316+ object ["geo_polygon" .=
1317+ object [geoPolygonFilterField .=
1318+ object ["points" .= fmap toJSON latLons]]]
1320+ toJSON (IdsFilter (MappingName mappingName) values) =
1322+ object ["type" .= mappingName
1323+ , "values" .= fmap unpackId values]]
1325+ toJSON (LimitFilter limit) =
1326+ object ["limit" .= object ["value" .= limit]]
1328+ toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
1329+ object ["missing" .=
1330+ object [ "field" .= fieldName
1331+ , "existence" .= existence
1332+ , "null_value" .= nullValue]]
1334+ toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
1335+ object ["prefix" .=
1336+ object [fieldName .= fieldValue
1337+ , "_cache" .= cache]]
1339+ toJSON (QueryFilter query False) =
1340+ object ["query" .= toJSON query ]
1341+ toJSON (QueryFilter query True) =
1342+ object ["fquery" .=
1343+ object [ "query" .= toJSON query
1344+ , "_cache" .= True ]]
1346+ toJSON (RangeFilter (FieldName fieldName) rangeValue rangeExecution cache) =
1348+ object [ fieldName .= object (rangeValueToPair rangeValue)
1349+ , "execution" .= rangeExecution
1350+ , "_cache" .= cache]]
1352+ toJSON (RegexpFilter (FieldName fieldName)
1353+ (Regexp regexText) flags (CacheName cacheName) cache (CacheKey cacheKey)) =
1354+ object ["regexp" .=
1355+ object [fieldName .=
1356+ object ["value" .= regexText
1357+ , "flags" .= flags]
1358+ , "_name" .= cacheName
1359+ , "_cache" .= cache
1360+ , "_cache_key" .= cacheKey]]
1362+instance FromJSON Filter where
1363+ parseJSON = withObject "Filter" parse
1364+ where parse o = andFilter `taggedWith` "and"
1365+ <|> orFilter `taggedWith` "or"
1366+ <|> notFilter `taggedWith` "not"
1367+ <|> identityFilter `taggedWith` "match_all"
1368+ <|> boolFilter `taggedWith` "bool"
1369+ <|> existsFilter `taggedWith` "exists"
1370+ <|> geoBoundingBoxFilter `taggedWith` "geo_bounding_box"
1371+ <|> geoDistanceFilter `taggedWith` "geo_distance"
1372+ <|> geoDistanceRangeFilter `taggedWith` "geo_distance_range"
1373+ <|> geoPolygonFilter `taggedWith` "geo_polygon"
1374+ <|> idsFilter `taggedWith` "ids"
1375+ <|> limitFilter `taggedWith` "limit"
1376+ <|> missingFilter `taggedWith` "missing"
1377+ <|> prefixFilter `taggedWith` "prefix"
1378+ <|> queryFilter `taggedWith` "query"
1379+ <|> fqueryFilter `taggedWith` "fquery"
1380+ <|> rangeFilter `taggedWith` "range"
1381+ <|> regexpFilter `taggedWith` "regexp"
1382+ <|> termFilter `taggedWith` "term"
1383+ where taggedWith parser k = parser =<< o .: k
1384+ andFilter o = AndFilter <$> o .: "filters"
1385+ <*> o .:? "_cache" .!= defaultCache
1386+ orFilter o = OrFilter <$> o .: "filters"
1387+ <*> o .:? "_cache" .!= defaultCache
1388+ notFilter o = NotFilter <$> o .: "filter"
1389+ <*> o .: "_cache" .!= defaultCache
1390+ identityFilter :: Object -> Parser Filter
1392+ | HM.null m = pure IdentityFilter
1393+ | otherwise = fail ("Identityfilter expected empty object but got " <> show m)
1394+ boolFilter = pure . BoolFilter
1395+ existsFilter o = ExistsFilter <$> o .: "field"
1396+ geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
1397+ geoDistanceFilter o = do
1398+ case HM.toList (deleteSeveral ["distance", "distance_type", "optimize_bbox", "_cache"] o) of
1400+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
1401+ GeoDistanceFilter gp <$> o .: "distance"
1402+ <*> o .: "distance_type"
1403+ <*> o .: "optimize_bbox"
1404+ <*> o .:? "_cache" .!= defaultCache
1405+ _ -> fail "Could not find GeoDistanceFilter field name"
1406+ geoDistanceRangeFilter o = do
1407+ case HM.toList (deleteSeveral ["from", "to"] o) of
1409+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
1410+ rng <- DistanceRange <$> o .: "from" <*> o .: "to"
1411+ return (GeoDistanceRangeFilter gp rng)
1412+ _ -> fail "Could not find GeoDistanceRangeFilter field name"
1413+ geoPolygonFilter = fieldTagged $ \fn o -> GeoPolygonFilter fn <$> o .: "points"
1414+ idsFilter o = IdsFilter <$> o .: "type"
1416+ limitFilter o = LimitFilter <$> o .: "value"
1417+ missingFilter o = MissingFilter <$> o .: "field"
1418+ <*> o .: "existence"
1419+ <*> o .: "null_value"
1420+ prefixFilter o = case HM.toList (HM.delete "_cache" o) of
1421+ [(fn, String v)] -> PrefixFilter (FieldName fn) v <$> o .:? "_cache" .!= defaultCache
1422+ _ -> fail "Could not parse PrefixFilter"
1424+ queryFilter q = pure (QueryFilter q False)
1425+ fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
1426+ rangeFilter o = case HM.toList (deleteSeveral ["execution", "_cache"] o) of
1427+ [(fn, v)] -> RangeFilter (FieldName fn)
1429+ <*> o .: "execution"
1430+ <*> o .:? "_cache" .!= defaultCache
1431+ _ -> fail "Could not find field name for RangeFilter"
1432+ regexpFilter o = case HM.toList (deleteSeveral ["_name", "_cache", "_cache_key"] o) of
1433+ [(fn, Object o')] -> RegexpFilter (FieldName fn)
1437+ <*> o .:? "_cache" .!= defaultCache
1438+ <*> o .: "_cache_key"
1439+ _ -> fail "Could not find field name for RegexpFilter"
1440+ termFilter o = case HM.toList (HM.delete "_cache" o) of
1441+ [(termField, String termVal)] -> TermFilter (Term termField termVal)
1442+ <$> o .:? "_cache" .!= defaultCache
1443+ _ -> fail "Could not find term field for TermFilter"
1445+instance ToJSON BooleanOperator where
1446+ toJSON And = String "and"
1447+ toJSON Or = String "or"
1449+instance FromJSON BooleanOperator where
1450+ parseJSON = withText "BooleanOperator" parse
1451+ where parse "and" = pure And
1452+ parse "or" = pure Or
1453+ parse o = fail ("Unexpected BooleanOperator: " <> show o)
1455+instance ToJSON ZeroTermsQuery where
1456+ toJSON ZeroTermsNone = String "none"
1457+ toJSON ZeroTermsAll = String "all"
1459+instance FromJSON ZeroTermsQuery where
1460+ parseJSON = withText "ZeroTermsQuery" parse
1461+ where parse "none" = pure ZeroTermsNone
1462+ parse "all" = pure ZeroTermsAll
1463+ parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
1465+fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
1466+fieldTagged f o = case HM.toList o of
1467+ [(k, Object o')] -> f (FieldName k) o'
1468+ _ -> fail "Expected object with 1 field-named key"
1470+instance ToJSON RangeExecution where
1471+ toJSON RangeExecutionIndex = "index"
1472+ toJSON RangeExecutionFielddata = "fielddata"
1475+instance FromJSON RangeExecution where
1476+ parseJSON = withText "RangeExecution" parse
1477+ where parse "index" = pure RangeExecutionIndex
1478+ parse "fielddata" = pure RangeExecutionFielddata
1479+ parse t = error ("Unrecognized RangeExecution " <> show t)
1481+instance ToJSON RegexpFlags where
1482+ toJSON AllRegexpFlags = String "ALL"
1483+ toJSON NoRegexpFlags = String "NONE"
1484+ toJSON (SomeRegexpFlags (h :| fs)) = String $ T.intercalate "|" flagStrs
1485+ where flagStrs = map flagStr . nub $ h:fs
1486+ flagStr AnyString = "ANYSTRING"
1487+ flagStr Automaton = "AUTOMATON"
1488+ flagStr Complement = "COMPLEMENT"
1489+ flagStr Empty = "EMPTY"
1490+ flagStr Intersection = "INTERSECTION"
1491+ flagStr Interval = "INTERVAL"
1493+instance FromJSON RegexpFlags where
1494+ parseJSON = withText "RegexpFlags" parse
1495+ where parse "ALL" = pure AllRegexpFlags
1496+ parse "NONE" = pure NoRegexpFlags
1497+ parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
1499+instance FromJSON RegexpFlag where
1500+ parseJSON = withText "RegexpFlag" parse
1501+ where parse "ANYSTRING" = pure AnyString
1502+ parse "AUTOMATON" = pure Automaton
1503+ parse "COMPLEMENT" = pure Complement
1504+ parse "EMPTY" = pure Empty
1505+ parse "INTERSECTION" = pure Intersection
1506+ parse "INTERVAL" = pure Interval
1507+ parse f = fail ("Unknown RegexpFlag: " <> show f)
1509+rangeValueToPair :: RangeValue -> [Pair]
1510+rangeValueToPair rv = case rv of
1511+ RangeDateLte (LessThanEqD t) -> ["lte" .= t]
1512+ RangeDateGte (GreaterThanEqD t) -> ["gte" .= t]
1513+ RangeDateLt (LessThanD t) -> ["lt" .= t]
1514+ RangeDateGt (GreaterThanD t) -> ["gt" .= t]
1515+ RangeDateGteLte (GreaterThanEqD l) (LessThanEqD g) -> ["gte" .= l, "lte" .= g]
1516+ RangeDateGtLte (GreaterThanD l) (LessThanEqD g) -> ["gt" .= l, "lte" .= g]
1517+ RangeDateGteLt (GreaterThanEqD l) (LessThanD g) -> ["gte" .= l, "lt" .= g]
1518+ RangeDateGtLt (GreaterThanD l) (LessThanD g) -> ["gt" .= l, "lt" .= g]
1519+ RangeDoubleLte (LessThanEq t) -> ["lte" .= t]
1520+ RangeDoubleGte (GreaterThanEq t) -> ["gte" .= t]
1521+ RangeDoubleLt (LessThan t) -> ["lt" .= t]
1522+ RangeDoubleGt (GreaterThan t) -> ["gt" .= t]
1523+ RangeDoubleGteLte (GreaterThanEq l) (LessThanEq g) -> ["gte" .= l, "lte" .= g]
1524+ RangeDoubleGtLte (GreaterThan l) (LessThanEq g) -> ["gt" .= l, "lte" .= g]
1525+ RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g]
1526+ RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
1528+instance ToJSON ScoreType where
1529+ toJSON ScoreTypeMax = "max"
1530+ toJSON ScoreTypeAvg = "avg"
1531+ toJSON ScoreTypeSum = "sum"
1532+ toJSON ScoreTypeNone = "none"
1534+instance FromJSON ScoreType where
1535+ parseJSON = withText "ScoreType" parse
1536+ where parse "max" = pure ScoreTypeMax
1537+ parse "avg" = pure ScoreTypeAvg
1538+ parse "sum" = pure ScoreTypeSum
1539+ parse "none" = pure ScoreTypeNone
1540+ parse t = fail ("Unexpected ScoreType: " <> show t)
1542+instance ToJSON MatchQueryType where
1543+ toJSON MatchPhrase = "phrase"
1544+ toJSON MatchPhrasePrefix = "phrase_prefix"
1546+instance FromJSON MatchQueryType where
1547+ parseJSON = withText "MatchQueryType" parse
1548+ where parse "phrase" = pure MatchPhrase
1549+ parse "phrase_prefix" = pure MatchPhrasePrefix
1550+ parse t = fail ("Unexpected MatchQueryType: " <> show t)
1552+instance ToJSON MultiMatchQueryType where
1553+ toJSON MultiMatchBestFields = "best_fields"
1554+ toJSON MultiMatchMostFields = "most_fields"
1555+ toJSON MultiMatchCrossFields = "cross_fields"
1556+ toJSON MultiMatchPhrase = "phrase"
1557+ toJSON MultiMatchPhrasePrefix = "phrase_prefix"
1559+instance FromJSON MultiMatchQueryType where
1560+ parseJSON = withText "MultiMatchPhrasePrefix" parse
1561+ where parse "best_fields" = pure MultiMatchBestFields
1562+ parse "most_fields" = pure MultiMatchMostFields
1563+ parse "cross_fields" = pure MultiMatchCrossFields
1564+ parse "phrase" = pure MultiMatchPhrase
1565+ parse "phrase_prefix" = pure MultiMatchPhrasePrefix
1566+ parse t = fail ("Unexpected MultiMatchPhrasePrefix: " <> show t)
1568+defaultCache :: Cache
1569+defaultCache = False
1571+instance ToJSON BoolMatch where
1572+ toJSON (MustMatch term cache) = object ["must" .= term,
1574+ toJSON (MustNotMatch term cache) = object ["must_not" .= term,
1576+ toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
1579+instance FromJSON BoolMatch where
1580+ parseJSON = withObject "BoolMatch" parse
1581+ where parse o = mustMatch `taggedWith` "must"
1582+ <|> mustNotMatch `taggedWith` "must_not"
1583+ <|> shouldMatch `taggedWith` "should"
1584+ where taggedWith parser k = parser =<< o .: k
1585+ mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
1586+ mustNotMatch t = MustNotMatch t <$> o .:? "_cache" .!= defaultCache
1587+ shouldMatch t = ShouldMatch t <$> o .:? "_cache" .!= defaultCache
1589+instance ToJSON GeoBoundingBoxConstraint where
1590+ toJSON (GeoBoundingBoxConstraint
1591+ (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =
1592+ object [gbbcGeoBBField .= gbbcConstraintBox
1593+ , "_cache" .= cache
1596+instance FromJSON GeoBoundingBoxConstraint where
1597+ parseJSON = withObject "GeoBoundingBoxConstraint" parse
1598+ where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of
1599+ [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)
1601+ <*> o .:? "_cache" .!= defaultCache
1603+ _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
1605+instance ToJSON Distance where
1606+ toJSON (Distance dCoefficient dUnit) =
1607+ String boltedTogether where
1608+ coefText = showText dCoefficient
1609+ (String unitText) = toJSON dUnit
1610+ boltedTogether = mappend coefText unitText
1612+instance FromJSON Distance where
1613+ parseJSON = withText "Distance" parse
1614+ where parse t = Distance <$> parseCoeff nT
1615+ <*> parseJSON (String unitT)
1616+ where (nT, unitT) = T.span validForNumber t
1617+ -- may be a better way to do this
1618+ validForNumber '-' = True
1619+ validForNumber '.' = True
1620+ validForNumber 'e' = True
1621+ validForNumber c = isNumber c
1622+ parseCoeff "" = fail "Empty string cannot be parsed as number"
1623+ parseCoeff s = return (read (T.unpack s))
1625+instance ToJSON DistanceType where
1626+ toJSON Arc = String "arc"
1627+ toJSON SloppyArc = String "sloppy_arc"
1628+ toJSON Plane = String "plane"
1630+instance FromJSON DistanceType where
1631+ parseJSON = withText "DistanceType" parse
1632+ where parse "arc" = pure Arc
1633+ parse "sloppy_arc" = pure SloppyArc
1634+ parse "plane" = pure Plane
1635+ parse t = fail ("Unrecognized DistanceType: " <> show t)
1637+instance ToJSON OptimizeBbox where
1638+ toJSON NoOptimizeBbox = String "none"
1639+ toJSON (OptimizeGeoFilterType gft) = toJSON gft
1641+instance FromJSON OptimizeBbox where
1642+ parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
1643+ <|> parseOptimize v
1644+ where parseNoOptimize "none" = pure NoOptimizeBbox
1645+ parseNoOptimize _ = mzero
1646+ parseOptimize = fmap OptimizeGeoFilterType . parseJSON
1648+instance ToJSON Term where
1649+ toJSON (Term field value) = object ["term" .= object
1652+instance FromJSON Term where
1653+ parseJSON = withObject "Term" parse
1654+ where parse o = do termObj <- o .: "term"
1655+ case HM.toList termObj of
1656+ [(fn, v)] -> Term fn <$> parseJSON v
1657+ _ -> fail "Expected object with 1 field-named key"
1659+instance ToJSON GeoBoundingBox where
1660+ toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
1661+ object ["top_left" .= gbbTopLeft
1662+ , "bottom_right" .= gbbBottomRight]
1664+instance FromJSON GeoBoundingBox where
1665+ parseJSON = withObject "GeoBoundingBox" parse
1666+ where parse o = GeoBoundingBox
1667+ <$> o .: "top_left"
1668+ <*> o .: "bottom_right"
1670+instance ToJSON GeoFilterType where
1671+ toJSON GeoFilterMemory = String "memory"
1672+ toJSON GeoFilterIndexed = String "indexed"
1674+instance FromJSON GeoFilterType where
1675+ parseJSON = withText "GeoFilterType" parse
1676+ where parse "memory" = pure GeoFilterMemory
1677+ parse "indexed" = pure GeoFilterIndexed
1678+ parse t = fail ("Unrecognized GeoFilterType: " <> show t)
1680+{-| 'unpackId' is a silly convenience function that gets used once.
1682+unpackId :: DocId -> Text
1683+unpackId (DocId docId) = docId