{-# LANGUAGE OverloadedStrings #-} -- ---------------------------------------------------------------------------- {- | Document format for the interpreter and JSON API. It includes the document description, the index data and additional metadata. -} -- ---------------------------------------------------------------------------- module Hunt.Common.ApiDocument where import Control.Applicative import Control.DeepSeq import Control.Monad (mzero) import Data.Aeson import Data.Binary (Binary (..)) import Data.Map.Strict (Map ()) import qualified Data.Map.Strict as M import Data.Text (Text) import qualified Data.Text as T import Data.Text.Binary () import Hunt.Common.BasicTypes import qualified Hunt.Common.DocDesc as DD import Hunt.Utility.Log -- ------------------------------------------------------------ -- | The document accepted by the interpreter and JSON API. data ApiDocument = ApiDocument { adUri :: URI -- ^ The unique identifier. , adIndex :: IndexMap -- ^ The data to index according to schema associated with the context. , adDescr :: Description -- ^ The document description (a simple key-value map). , adWght :: Score -- ^ An optional document boost, (internal default is @1.0@). } deriving (Show) -- | Context map type IndexMap = Map Context Content -- | Multiple 'ApiDocument's. type ApiDocuments = [ApiDocument] -- | Text analysis function type AnalyzerFunction = Text -> [(Position, Text)] -- | Types of analyzer data AnalyzerType = DefaultAnalyzer deriving (Show) -- | Paginated result with an offset and chunk size. data LimitedResult x = LimitedResult { lrResult :: [x] -- ^ The list with at most 'lrMax' elements. , lrOffset :: Int -- ^ The offset of the result. , lrMax :: Int -- ^ The limit for the result. , lrCount :: Int -- ^ The size of the complete result. } deriving (Show, Eq) instance NFData x => NFData (LimitedResult x) where rnf (LimitedResult r o m c) = r `seq` o `seq` m `seq` c `seq` () -- ------------------------------------------------------------ -- | Create a paginated result with an offset and a chunk size. -- The result also includes the size of the complete result. mkLimitedResult :: Int -> Int -> [x] -> LimitedResult x mkLimitedResult offset mx xs = LimitedResult { lrResult = ( if mx < 0 then id else take mx ) . drop offset $ xs , lrOffset = offset , lrMax = mx , lrCount = length xs } -- | Empty index content. emptyApiDocIndexMap :: IndexMap emptyApiDocIndexMap = M.empty -- | Empty 'Document' description. emptyApiDocDescr :: Description emptyApiDocDescr = DD.empty -- | Empty 'ApiDocument'. emptyApiDoc :: ApiDocument emptyApiDoc = ApiDocument "" emptyApiDocIndexMap emptyApiDocDescr noScore -- ------------------------------------------------------------ instance NFData ApiDocument where --default -- ------------------------------------------------------------ instance Binary ApiDocument where put (ApiDocument a b c d) = put a >> put b >> put c >> put d get = ApiDocument <$> get <*> get <*> get <*> get -- ------------------------------------------------------------ instance LogShow ApiDocument where logShow o = "ApiDocument {adUri = \"" ++ (T.unpack . adUri $ o) ++ "\", ..}" -- ------------------------------------------------------------ -- JSON instances -- ------------------------------------------------------------ instance (ToJSON x) => ToJSON (LimitedResult x) where toJSON (LimitedResult res offset mx cnt) = object [ "result" .= res , "offset" .= offset , "max" .= mx , "count" .= cnt ] instance (FromJSON x) => FromJSON (LimitedResult x) where parseJSON (Object v) = do res <- v .: "result" offset <- v .: "offset" mx <- v .: "max" cnt <- v .: "count" return $ LimitedResult res offset mx cnt parseJSON _ = mzero instance FromJSON ApiDocument where parseJSON (Object o) = do parsedUri <- o .: "uri" indexMap <- o .:? "index" .!= emptyApiDocIndexMap descrMap <- o .:? "description" .!= emptyApiDocDescr weight <- mkScore <$> o .:? "weight" .!= 0.0 return ApiDocument { adUri = parsedUri , adIndex = indexMap , adDescr = descrMap , adWght = weight } parseJSON _ = mzero instance ToJSON ApiDocument where toJSON (ApiDocument u im dm wt) = object $ ( maybe [] (\ x -> ["weight" .= x]) $ getScore wt ) ++ ( if M.null im then [] else ["index" .= im] ) ++ ( if DD.null dm then [] else ["description" .= dm] ) ++ ["uri" .= u] instance FromJSON AnalyzerType where parseJSON (String s) = case s of "default" -> return DefaultAnalyzer _ -> mzero parseJSON _ = mzero instance ToJSON AnalyzerType where toJSON (DefaultAnalyzer) = "default" -- ------------------------------------------------------------