@@ -414,112 +414,16 @@ module Database.V5.Bloodhound.Types
414414
415415import Bloodhound.Import
416416
417−import qualified Data.HashMap.Strict as HM
418−import qualified Data.Map.Strict as M
419−import qualified Data.Text as T
417+import qualified Data.HashMap.Strict as HM
418+import qualified Data.Map.Strict as M
420419
421420import Database.V5.Bloodhound.Types.Class
422421import Database.V5.Bloodhound.Internal.Analysis
422+import Database.V5.Bloodhound.Internal.Aggregation
423423import Database.V5.Bloodhound.Internal.Client
424424import Database.V5.Bloodhound.Internal.Newtypes
425425import Database.V5.Bloodhound.Internal.Query
426−
427−{-| 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order
428− dependent with later sorts acting as tie-breakers for earlier sorts.
429−-}
430−type Sort = [SortSpec]
431−
432−{-| The two main kinds of 'SortSpec' are 'DefaultSortSpec' and
433− 'GeoDistanceSortSpec'. The latter takes a 'SortOrder', 'GeoPoint', and
434− 'DistanceUnit' to express "nearness" to a single geographical point as a
435− sort specification.
436−
437−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
438−-}
439−data SortSpec =
440− DefaultSortSpec DefaultSort
441− | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit
442− deriving (Eq, Show)
443−
444−instance ToJSON SortSpec where
445− toJSON (DefaultSortSpec
446− (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped
447− dsSortMode dsMissingSort dsNestedFilter)) =
448− object [dsSortFieldName .= omitNulls base] where
449− base = [ "order" .= dsSortOrder
450− , "unmapped_type" .= dsIgnoreUnmapped
451− , "mode" .= dsSortMode
452− , "missing" .= dsMissingSort
453− , "nested_filter" .= dsNestedFilter ]
454−
455− toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
456− object [ "unit" .= units
457− , field .= gdsLatLon
458− , "order" .= gdsSortOrder ]
459−
460−{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
461− 'mkSort' convenience function for when you want to specify only the most
462− common parameters.
463−
464− The `ignoreUnmapped`, when `Just` field is used to set the elastic 'unmapped_type'
465−
466−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
467−-}
468−data DefaultSort =
469− DefaultSort { sortFieldName :: FieldName
470− , sortOrder :: SortOrder
471− -- default False
472− , ignoreUnmapped :: Maybe Text
473− , sortMode :: Maybe SortMode
474− , missingSort :: Maybe Missing
475− , nestedFilter :: Maybe Filter } deriving (Eq, Show)
476−
477−{-| 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
478− encoded into "asc" or "desc" when turned into JSON.
479−
480−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
481−-}
482−data SortOrder = Ascending
483− | Descending deriving (Eq, Show)
484−
485−instance ToJSON SortOrder where
486− toJSON Ascending = String "asc"
487− toJSON Descending = String "desc"
488−
489−{-| 'Missing' prescribes how to handle missing fields. A missing field can be
490− sorted last, first, or using a custom value as a substitute.
491−
492−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_missing_values>
493−-}
494−data Missing = LastMissing
495− | FirstMissing
496− | CustomMissing Text deriving (Eq, Show)
497−
498−instance ToJSON Missing where
499− toJSON LastMissing = String "_last"
500− toJSON FirstMissing = String "_first"
501− toJSON (CustomMissing txt) = String txt
502−
503−{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
504−
505−http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
506−-}
507−data SortMode = SortMin
508− | SortMax
509− | SortSum
510− | SortAvg deriving (Eq, Show)
511−
512−instance ToJSON SortMode where
513− toJSON SortMin = String "min"
514− toJSON SortMax = String "max"
515− toJSON SortSum = String "sum"
516− toJSON SortAvg = String "avg"
517−
518−{-| 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so
519− that you can concisely describe the usual kind of 'SortSpec's you want.
520−-}
521−mkSort :: FieldName -> SortOrder -> DefaultSort
522−mkSort fieldName sOrder = DefaultSort fieldName sOrder Nothing Nothing Nothing Nothing
426+import Database.V5.Bloodhound.Internal.Sort
523427
524428{-| 'unpackId' is a silly convenience function that gets used once.
525429-}
@@ -527,8 +431,6 @@ unpackId :: DocId -> Text
527431unpackId (DocId docId) = docId
528432
529433type TrackSortScores = Bool
530−newtype From = From Int deriving (Eq, Show, ToJSON)
531−newtype Size = Size Int deriving (Eq, Show, ToJSON, FromJSON)
532434
533435data Search = Search { queryBody :: Maybe Query
534436 , filterBody :: Maybe Filter
@@ -546,6 +448,31 @@ data Search = Search { queryBody :: Maybe Query
546448 , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
547449 } deriving (Eq, Show)
548450
451+
452+instance ToJSON Search where
453+ toJSON (Search mquery sFilter sort searchAggs
454+ highlight sTrackSortScores sFrom sSize _ sFields
455+ sScriptFields sSource sSuggest) =
456+ omitNulls [ "query" .= query'
457+ , "sort" .= sort
458+ , "aggregations" .= searchAggs
459+ , "highlight" .= highlight
460+ , "from" .= sFrom
461+ , "size" .= sSize
462+ , "track_scores" .= sTrackSortScores
463+ , "fields" .= sFields
464+ , "script_fields" .= sScriptFields
465+ , "_source" .= sSource
466+ , "suggest" .= sSuggest]
467+
468+ where query' = case sFilter of
469+ Nothing -> mquery
470+ Just x ->
471+ Just
472+ . QueryBoolQuery
473+ $ mkBoolQuery (maybeToList mquery)
474+ [x] [] []
475+
549476data SearchType = SearchTypeQueryThenFetch
550477 | SearchTypeDfsQueryThenFetch
551478 deriving (Eq, Show)
@@ -644,7 +571,6 @@ data SearchResult a =
644571 }
645572 deriving (Eq, Show)
646573
647−
648574instance (FromJSON a) => FromJSON (SearchResult a) where
649575 parseJSON (Object v) = SearchResult <$>
650576 v .: "took" <*>
@@ -674,7 +600,8 @@ instance (FromJSON a) => FromJSON (SearchHits a) where
674600 parseJSON _ = empty
675601
676602instance Semigroup (SearchHits a) where
677− (SearchHits ta ma ha) <> (SearchHits tb mb hb) = SearchHits (ta + tb) (max ma mb) (ha <> hb)
603+ (SearchHits ta ma ha) <> (SearchHits tb mb hb) =
604+ SearchHits (ta + tb) (max ma mb) (ha <> hb)
678605
679606instance Monoid (SearchHits a) where
680607 mempty = SearchHits 0 Nothing mempty
@@ -710,297 +637,6 @@ instance FromJSON HitFields where
710637
711638type HitHighlight = M.Map Text [Text]
712639
713−type Aggregations = M.Map Text Aggregation
714−
715−emptyAggregations :: Aggregations
716−emptyAggregations = M.empty
717−
718−mkAggregations :: Text -> Aggregation -> Aggregations
719−mkAggregations name aggregation = M.insert name aggregation emptyAggregations
720−
721−data TermOrder = TermOrder
722− { termSortField :: Text
723− , termSortOrder :: SortOrder } deriving (Eq, Show)
724−
725−instance ToJSON TermOrder where
726− toJSON (TermOrder termSortField termSortOrder) =
727− object [termSortField .= termSortOrder]
728−
729−data TermInclusion = TermInclusion Text
730− | TermPattern Text Text deriving (Eq, Show)
731−
732−instance ToJSON TermInclusion where
733− toJSON (TermInclusion x) = toJSON x
734− toJSON (TermPattern pattern flags) =
735− omitNulls [ "pattern" .= pattern
736− , "flags" .= flags]
737−
738−data CollectionMode = BreadthFirst
739− | DepthFirst deriving (Eq, Show)
740−
741−instance ToJSON CollectionMode where
742− toJSON BreadthFirst = "breadth_first"
743− toJSON DepthFirst = "depth_first"
744−
745−data ExecutionHint = Ordinals
746− | GlobalOrdinals
747− | GlobalOrdinalsHash
748− | GlobalOrdinalsLowCardinality
749− | Map deriving (Eq, Show)
750−
751−instance ToJSON ExecutionHint where
752− toJSON Ordinals = "ordinals"
753− toJSON GlobalOrdinals = "global_ordinals"
754− toJSON GlobalOrdinalsHash = "global_ordinals_hash"
755− toJSON GlobalOrdinalsLowCardinality = "global_ordinals_low_cardinality"
756− toJSON Map = "map"
757−
758−data Aggregation = TermsAgg TermsAggregation
759− | CardinalityAgg CardinalityAggregation
760− | DateHistogramAgg DateHistogramAggregation
761− | ValueCountAgg ValueCountAggregation
762− | FilterAgg FilterAggregation
763− | DateRangeAgg DateRangeAggregation
764− | MissingAgg MissingAggregation
765− | TopHitsAgg TopHitsAggregation
766− | StatsAgg StatisticsAggregation
767− deriving (Eq, Show)
768−
769−instance ToJSON Aggregation where
770− toJSON (TermsAgg (TermsAggregation term include exclude order minDocCount size shardSize collectMode executionHint termAggs)) =
771− omitNulls ["terms" .= omitNulls [ toJSON' term,
772− "include" .= include,
773− "exclude" .= exclude,
774− "order" .= order,
775− "min_doc_count" .= minDocCount,
776− "size" .= size,
777− "shard_size" .= shardSize,
778− "collect_mode" .= collectMode,
779− "execution_hint" .= executionHint
780− ],
781− "aggs" .= termAggs ]
782− where
783− toJSON' x = case x of { Left y -> "field" .= y; Right y -> "script" .= y }
784−
785− toJSON (CardinalityAgg (CardinalityAggregation field precisionThreshold)) =
786− object ["cardinality" .= omitNulls [ "field" .= field,
787− "precisionThreshold" .= precisionThreshold
788− ]
789− ]
790−
791− toJSON (DateHistogramAgg
792− (DateHistogramAggregation field interval format
793− preZone postZone preOffset postOffset dateHistoAggs)) =
794− omitNulls ["date_histogram" .= omitNulls [ "field" .= field,
795− "interval" .= interval,
796− "format" .= format,
797− "pre_zone" .= preZone,
798− "post_zone" .= postZone,
799− "pre_offset" .= preOffset,
800− "post_offset" .= postOffset
801− ],
802− "aggs" .= dateHistoAggs ]
803− toJSON (ValueCountAgg a) = object ["value_count" .= v]
804− where v = case a of
805− (FieldValueCount (FieldName n)) ->
806− object ["field" .= n]
807− (ScriptValueCount s) ->
808− object ["script" .= s]
809− toJSON (FilterAgg (FilterAggregation filt ags)) =
810− omitNulls [ "filter" .= filt
811− , "aggs" .= ags]
812− toJSON (DateRangeAgg a) = object [ "date_range" .= a
813− ]
814− toJSON (MissingAgg (MissingAggregation{..})) =
815− object ["missing" .= object ["field" .= maField]]
816−
817− toJSON (TopHitsAgg (TopHitsAggregation mfrom msize msort)) =
818− omitNulls ["top_hits" .= omitNulls [ "size" .= msize
819− , "from" .= mfrom
820− , "sort" .= msort
821− ]
822− ]
823−
824− toJSON (StatsAgg (StatisticsAggregation typ field)) =
825− object [stType .= omitNulls [ "field" .= field ]]
826− where
827− stType | typ == Basic = "stats"
828− | otherwise = "extended_stats"
829−
830−data TopHitsAggregation = TopHitsAggregation
831− { taFrom :: Maybe From
832− , taSize :: Maybe Size
833− , taSort :: Maybe Sort
834− } deriving (Eq, Show)
835−
836−data MissingAggregation = MissingAggregation
837− { maField :: Text
838− } deriving (Eq, Show)
839−
840−data TermsAggregation = TermsAggregation
841− { term :: Either Text Text
842− , termInclude :: Maybe TermInclusion
843− , termExclude :: Maybe TermInclusion
844− , termOrder :: Maybe TermOrder
845− , termMinDocCount :: Maybe Int
846− , termSize :: Maybe Int
847− , termShardSize :: Maybe Int
848− , termCollectMode :: Maybe CollectionMode
849− , termExecutionHint :: Maybe ExecutionHint
850− , termAggs :: Maybe Aggregations
851− } deriving (Eq, Show)
852−
853−data CardinalityAggregation = CardinalityAggregation
854− { cardinalityField :: FieldName,
855− precisionThreshold :: Maybe Int
856− } deriving (Eq, Show)
857−
858−data DateHistogramAggregation = DateHistogramAggregation
859− { dateField :: FieldName
860− , dateInterval :: Interval
861− , dateFormat :: Maybe Text
862− -- pre and post deprecated in 1.5
863− , datePreZone :: Maybe Text
864− , datePostZone :: Maybe Text
865− , datePreOffset :: Maybe Text
866− , datePostOffset :: Maybe Text
867− , dateAggs :: Maybe Aggregations
868− } deriving (Eq, Show)
869−
870−data DateRangeAggregation = DateRangeAggregation
871− { draField :: FieldName
872− , draFormat :: Maybe Text
873− , draRanges :: NonEmpty DateRangeAggRange
874− } deriving (Eq, Show)
875−
876−instance ToJSON DateRangeAggregation where
877− toJSON DateRangeAggregation {..} =
878− omitNulls [ "field" .= draField
879− , "format" .= draFormat
880− , "ranges" .= toList draRanges
881− ]
882−
883−data DateRangeAggRange =
884− DateRangeFrom DateMathExpr
885− | DateRangeTo DateMathExpr
886− | DateRangeFromAndTo DateMathExpr DateMathExpr
887− deriving (Eq, Show)
888−
889−instance ToJSON DateRangeAggRange where
890− toJSON (DateRangeFrom e) = object [ "from" .= e ]
891− toJSON (DateRangeTo e) = object [ "to" .= e ]
892− toJSON (DateRangeFromAndTo f t) = object [ "from" .= f, "to" .= t ]
893−
894−-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math> for more information.
895−data DateMathExpr =
896− DateMathExpr DateMathAnchor [DateMathModifier]
897− deriving (Eq, Show)
898−
899−instance ToJSON DateMathExpr where
900− toJSON (DateMathExpr a mods) = String (fmtA a <> mconcat (fmtMod <$> mods))
901− where fmtA DMNow = "now"
902− fmtA (DMDate date) = (T.pack $ showGregorian date) <> "||"
903− fmtMod (AddTime n u) = "+" <> showText n <> fmtU u
904− fmtMod (SubtractTime n u) = "-" <> showText n <> fmtU u
905− fmtMod (RoundDownTo u) = "/" <> fmtU u
906− fmtU DMYear = "y"
907− fmtU DMMonth = "M"
908− fmtU DMWeek = "w"
909− fmtU DMDay = "d"
910− fmtU DMHour = "h"
911− fmtU DMMinute = "m"
912− fmtU DMSecond = "s"
913−
914−-- | Starting point for a date range. This along with the 'DateMathModifiers' gets you the date ES will start from.
915−data DateMathAnchor =
916− DMNow
917− | DMDate Day
918− deriving (Eq, Show)
919−
920−data DateMathModifier =
921− AddTime Int DateMathUnit
922− | SubtractTime Int DateMathUnit
923− | RoundDownTo DateMathUnit
924− deriving (Eq, Show)
925−
926−data DateMathUnit =
927− DMYear
928− | DMMonth
929− | DMWeek
930− | DMDay
931− | DMHour
932− | DMMinute
933− | DMSecond
934− deriving (Eq, Show)
935−
936−-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html> for more information.
937−data ValueCountAggregation =
938− FieldValueCount FieldName
939− | ScriptValueCount Script
940− deriving (Eq, Show)
941−
942−-- | Single-bucket filter aggregations. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html#search-aggregations-bucket-filter-aggregation> for more information.
943−data FilterAggregation = FilterAggregation
944− { faFilter :: Filter
945− , faAggs :: Maybe Aggregations }
946− deriving (Eq, Show)
947−
948−data StatisticsAggregation = StatisticsAggregation
949− { statsType :: StatsType
950− , statsField :: FieldName }
951− deriving (Eq, Show)
952−
953−data StatsType
954− = Basic
955− | Extended
956− deriving (Eq, Show)
957−
958−mkTermsAggregation :: Text -> TermsAggregation
959−mkTermsAggregation t =
960− TermsAggregation (Left t)
961− Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
962−
963−mkTermsScriptAggregation :: Text -> TermsAggregation
964−mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
965−
966−mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
967−mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
968−
969−mkCardinalityAggregation :: FieldName -> CardinalityAggregation
970−mkCardinalityAggregation t = CardinalityAggregation t Nothing
971−
972−mkStatsAggregation :: FieldName -> StatisticsAggregation
973−mkStatsAggregation = StatisticsAggregation Basic
974−
975−mkExtendedStatsAggregation :: FieldName -> StatisticsAggregation
976−mkExtendedStatsAggregation = StatisticsAggregation Extended
977−
978−type AggregationResults = M.Map Text Value
979−
980−class BucketAggregation a where
981− key :: a -> BucketValue
982− docCount :: a -> Int
983− aggs :: a -> Maybe AggregationResults
984−
985−data Bucket a = Bucket
986− { buckets :: [a]
987− } deriving (Read, Show)
988−
989−instance (FromJSON a) => FromJSON (Bucket a) where
990− parseJSON (Object v) = Bucket <$>
991− v .: "buckets"
992− parseJSON _ = mempty
993−
994−data BucketValue = TextValue Text
995− | ScientificValue Scientific
996− | BoolValue Bool deriving (Read, Show)
997−
998−instance FromJSON BucketValue where
999− parseJSON (String t) = return $ TextValue t
1000− parseJSON (Number s) = return $ ScientificValue s
1001− parseJSON (Bool b) = return $ BoolValue b
1002− parseJSON _ = mempty
1003−
1004640data MissingResult = MissingResult
1005641 { missingDocCount :: Int
1006642 } deriving (Show)
@@ -1093,7 +729,7 @@ instance BucketAggregation DateRangeResult where
1093729 docCount = dateRangeDocCount
1094730 aggs = dateRangeAggs
1095731
1096−toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
732+toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
1097733toTerms = toAggResult
1098734
1099735toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
@@ -1118,30 +754,6 @@ getNamedSubAgg o knownKeys = maggRes
1118754 | HM.null unknownKeys = Nothing
1119755 | otherwise = Just . M.fromList $ HM.toList unknownKeys
1120756
1121−instance ToJSON Search where
1122− toJSON (Search mquery sFilter sort searchAggs
1123− highlight sTrackSortScores sFrom sSize _ sFields
1124− sScriptFields sSource sSuggest) =
1125− omitNulls [ "query" .= query'
1126− , "sort" .= sort
1127− , "aggregations" .= searchAggs
1128− , "highlight" .= highlight
1129− , "from" .= sFrom
1130− , "size" .= sSize
1131− , "track_scores" .= sTrackSortScores
1132− , "fields" .= sFields
1133− , "script_fields" .= sScriptFields
1134− , "_source" .= sSource
1135− , "suggest" .= sSuggest]
1136−
1137− where query' = case sFilter of
1138− Nothing -> mquery
1139− Just x ->
1140− Just
1141− . QueryBoolQuery
1142− $ mkBoolQuery (maybeToList mquery)
1143− [x] [] []
1144−
1145757instance ToJSON Source where
1146758 toJSON NoSource = toJSON False
1147759 toJSON (SourcePatterns patterns) = toJSON patterns