{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Database.Bloodhound.Internal.Sort where import Bloodhound.Import import Database.Bloodhound.Internal.Newtypes import Database.Bloodhound.Internal.Query -- | 'SortMode' prescribes how to handle sorting array/multi-valued fields. -- -- http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option data SortMode = SortMin | SortMax | SortSum | SortAvg deriving (Eq, Show) instance ToJSON SortMode where toJSON SortMin = String "min" toJSON SortMax = String "max" toJSON SortSum = String "sum" toJSON SortAvg = String "avg" -- | 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so -- that you can concisely describe the usual kind of 'SortSpec's you want. mkSort :: FieldName -> SortOrder -> DefaultSort mkSort fieldName sOrder = DefaultSort fieldName sOrder Nothing Nothing Nothing Nothing -- | 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order -- dependent with later sorts acting as tie-breakers for earlier sorts. type Sort = [SortSpec] -- | The two main kinds of 'SortSpec' are 'DefaultSortSpec' and -- 'GeoDistanceSortSpec'. The latter takes a 'SortOrder', 'GeoPoint', and -- 'DistanceUnit' to express "nearness" to a single geographical point as a -- sort specification. -- -- data SortSpec = DefaultSortSpec DefaultSort | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Show) instance ToJSON SortSpec where toJSON ( DefaultSortSpec ( DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped dsSortMode dsMissingSort dsNestedFilter ) ) = object [fromText dsSortFieldName .= omitNulls base] where base = [ "order" .= dsSortOrder, "unmapped_type" .= dsIgnoreUnmapped, "mode" .= dsSortMode, "missing" .= dsMissingSort, "nested_filter" .= dsNestedFilter ] toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) = object [ "unit" .= units, fromText field .= gdsLatLon, "order" .= gdsSortOrder ] -- | 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a -- 'mkSort' convenience function for when you want to specify only the most -- common parameters. -- -- The `ignoreUnmapped`, when `Just` field is used to set the elastic 'unmapped_type' -- -- data DefaultSort = DefaultSort { sortFieldName :: FieldName, sortOrder :: SortOrder, -- default False ignoreUnmapped :: Maybe Text, sortMode :: Maybe SortMode, missingSort :: Maybe Missing, nestedFilter :: Maybe Filter } deriving (Eq, Show) -- | 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get -- encoded into "asc" or "desc" when turned into JSON. -- -- data SortOrder = Ascending | Descending deriving (Eq, Show) instance ToJSON SortOrder where toJSON Ascending = String "asc" toJSON Descending = String "desc" -- | 'Missing' prescribes how to handle missing fields. A missing field can be -- sorted last, first, or using a custom value as a substitute. -- -- data Missing = LastMissing | FirstMissing | CustomMissing Text deriving (Eq, Show) instance ToJSON Missing where toJSON LastMissing = String "_last" toJSON FirstMissing = String "_first" toJSON (CustomMissing txt) = String txt