packages feed

bloodhound-0.21.0.0: src/Database/Bloodhound/Internal/Highlight.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}

module Database.Bloodhound.Internal.Highlight where

import Bloodhound.Import
import qualified Data.Map.Strict as M
import Database.Bloodhound.Internal.Newtypes
import Database.Bloodhound.Internal.Query

type HitHighlight = M.Map Text [Text]

data Highlights = Highlights
  { globalsettings :: Maybe HighlightSettings,
    highlightFields :: [FieldHighlight]
  }
  deriving (Eq, Show)

instance ToJSON Highlights where
  toJSON (Highlights global fields) =
    omitNulls
      ( ("fields" .= fields)
          : highlightSettingsPairs global
      )

data FieldHighlight
  = FieldHighlight FieldName (Maybe HighlightSettings)
  deriving (Eq, Show)

instance ToJSON FieldHighlight where
  toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
    object [fromText fName .= fSettings]
  toJSON (FieldHighlight (FieldName fName) Nothing) =
    object [fromText fName .= emptyObject]

data HighlightSettings
  = Plain PlainHighlight
  | Postings PostingsHighlight
  | FastVector FastVectorHighlight
  deriving (Eq, Show)

instance ToJSON HighlightSettings where
  toJSON hs = omitNulls (highlightSettingsPairs (Just hs))

data PlainHighlight = PlainHighlight
  { plainCommon :: Maybe CommonHighlight,
    plainNonPost :: Maybe NonPostings
  }
  deriving (Eq, Show)

-- This requires that index_options are set to 'offset' in the mapping.
data PostingsHighlight
  = PostingsHighlight (Maybe CommonHighlight)
  deriving (Eq, Show)

-- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
data FastVectorHighlight = FastVectorHighlight
  { fvCommon :: Maybe CommonHighlight,
    fvNonPostSettings :: Maybe NonPostings,
    boundaryChars :: Maybe Text,
    boundaryMaxScan :: Maybe Int,
    fragmentOffset :: Maybe Int,
    matchedFields :: [Text],
    phraseLimit :: Maybe Int
  }
  deriving (Eq, Show)

data CommonHighlight = CommonHighlight
  { order :: Maybe Text,
    forceSource :: Maybe Bool,
    tag :: Maybe HighlightTag,
    encoder :: Maybe HighlightEncoder,
    noMatchSize :: Maybe Int,
    highlightQuery :: Maybe Query,
    requireFieldMatch :: Maybe Bool
  }
  deriving (Eq, Show)

-- Settings that are only applicable to FastVector and Plain highlighters.
data NonPostings = NonPostings
  { fragmentSize :: Maybe Int,
    numberOfFragments :: Maybe Int
  }
  deriving (Eq, Show)

data HighlightEncoder
  = DefaultEncoder
  | HTMLEncoder
  deriving (Eq, Show)

instance ToJSON HighlightEncoder where
  toJSON DefaultEncoder = String "default"
  toJSON HTMLEncoder = String "html"

-- NOTE: Should the tags use some kind of HTML type, rather than Text?
data HighlightTag
  = TagSchema Text
  | -- Only uses more than the first value in the lists if fvh
    CustomTags ([Text], [Text])
  deriving (Eq, Show)

highlightSettingsPairs :: Maybe HighlightSettings -> [Pair]
highlightSettingsPairs Nothing = []
highlightSettingsPairs (Just (Plain plh)) = plainHighPairs (Just plh)
highlightSettingsPairs (Just (Postings ph)) = postHighPairs (Just ph)
highlightSettingsPairs (Just (FastVector fvh)) = fastVectorHighPairs (Just fvh)

plainHighPairs :: Maybe PlainHighlight -> [Pair]
plainHighPairs Nothing = []
plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
  ["type" .= String "plain"]
    ++ commonHighlightPairs plCom
    ++ nonPostingsToPairs plNonPost

postHighPairs :: Maybe PostingsHighlight -> [Pair]
postHighPairs Nothing = []
postHighPairs (Just (PostingsHighlight pCom)) =
  ("type" .= String "postings")
    : commonHighlightPairs pCom

fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
fastVectorHighPairs Nothing = []
fastVectorHighPairs
  ( Just
      ( FastVectorHighlight
          fvCom
          fvNonPostSettings'
          fvBoundChars
          fvBoundMaxScan
          fvFragOff
          fvMatchedFields
          fvPhraseLim
        )
    ) =
    [ "type" .= String "fvh",
      "boundary_chars" .= fvBoundChars,
      "boundary_max_scan" .= fvBoundMaxScan,
      "fragment_offset" .= fvFragOff,
      "matched_fields" .= fvMatchedFields,
      "phraseLimit" .= fvPhraseLim
    ]
      ++ commonHighlightPairs fvCom
      ++ nonPostingsToPairs fvNonPostSettings'

commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
commonHighlightPairs Nothing = []
commonHighlightPairs
  ( Just
      ( CommonHighlight
          chScore
          chForceSource
          chTag
          chEncoder
          chNoMatchSize
          chHighlightQuery
          chRequireFieldMatch
        )
    ) =
    [ "order" .= chScore,
      "force_source" .= chForceSource,
      "encoder" .= chEncoder,
      "no_match_size" .= chNoMatchSize,
      "highlight_query" .= chHighlightQuery,
      "require_fieldMatch" .= chRequireFieldMatch
    ]
      ++ highlightTagToPairs chTag

nonPostingsToPairs :: Maybe NonPostings -> [Pair]
nonPostingsToPairs Nothing = []
nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
  [ "fragment_size" .= npFragSize,
    "number_of_fragments" .= npNumOfFrags
  ]

highlightTagToPairs :: Maybe HighlightTag -> [Pair]
highlightTagToPairs (Just (TagSchema _)) =
  [ "scheme" .= String "default"
  ]
highlightTagToPairs (Just (CustomTags (pre, post))) =
  [ "pre_tags" .= pre,
    "post_tags" .= post
  ]
highlightTagToPairs Nothing = []