bloodhound 0.18.0.0 → 0.19.0.0
raw patch · 23 files changed
+251/−216 lines, 23 filesdep ~aesondep ~basedep ~microlens-aesonnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, base, microlens-aeson
API changes (from Hackage documentation)
- Database.Bloodhound.Internal.Query: type ScriptFieldName = Text
- Database.Bloodhound.Internal.Query: type ScriptParamName = Text
- Database.Bloodhound.Internal.Query: type TemplateQueryKey = Text
- Database.Bloodhound.Types: type ScriptFieldName = Text
- Database.Bloodhound.Types: type ScriptParamName = Text
+ Database.Bloodhound.Internal.Aggregation: [hitInnerHits] :: Hit a -> Maybe (KeyMap (TopHitResult Value))
+ Database.Bloodhound.Internal.Aggregation: instance GHC.Classes.Eq a => GHC.Classes.Eq (Database.Bloodhound.Internal.Aggregation.TopHitResult a)
+ Database.Bloodhound.Internal.Client: IndexMappingsLimits :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: [indexMappingsLimitDepth] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Internal.Client: [indexMappingsLimitFieldNameLength] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Internal.Client: [indexMappingsLimitNestedFields] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Internal.Client: [indexMappingsLimitNestedObjects] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Internal.Client: [indexMappingsLimits] :: IndexSettings -> IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: data IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: defaultIndexMappingsLimits :: IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: instance Data.Aeson.Types.FromJSON.FromJSON Database.Bloodhound.Internal.Client.IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: instance Data.Aeson.Types.ToJSON.ToJSON Database.Bloodhound.Internal.Client.IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: instance GHC.Classes.Eq Database.Bloodhound.Internal.Client.IndexMappingsLimits
+ Database.Bloodhound.Internal.Client: instance GHC.Show.Show Database.Bloodhound.Internal.Client.IndexMappingsLimits
+ Database.Bloodhound.Internal.Query: InnerHits :: Maybe Integer -> Maybe Integer -> InnerHits
+ Database.Bloodhound.Internal.Query: [innerHitsFrom] :: InnerHits -> Maybe Integer
+ Database.Bloodhound.Internal.Query: [innerHitsSize] :: InnerHits -> Maybe Integer
+ Database.Bloodhound.Internal.Query: [nestedQueryInnerHits] :: NestedQuery -> Maybe InnerHits
+ Database.Bloodhound.Internal.Query: data InnerHits
+ Database.Bloodhound.Internal.Query: instance Data.Aeson.Types.FromJSON.FromJSON Database.Bloodhound.Internal.Query.InnerHits
+ Database.Bloodhound.Internal.Query: instance Data.Aeson.Types.ToJSON.ToJSON Database.Bloodhound.Internal.Query.InnerHits
+ Database.Bloodhound.Internal.Query: instance GHC.Classes.Eq Database.Bloodhound.Internal.Query.InnerHits
+ Database.Bloodhound.Internal.Query: instance GHC.Show.Show Database.Bloodhound.Internal.Query.InnerHits
+ Database.Bloodhound.Types: IndexMappingsLimits :: Maybe Int -> Maybe Int -> Maybe Int -> Maybe Int -> IndexMappingsLimits
+ Database.Bloodhound.Types: InnerHits :: Maybe Integer -> Maybe Integer -> InnerHits
+ Database.Bloodhound.Types: [hitInnerHits] :: Hit a -> Maybe (KeyMap (TopHitResult Value))
+ Database.Bloodhound.Types: [indexMappingsLimitDepth] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Types: [indexMappingsLimitFieldNameLength] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Types: [indexMappingsLimitNestedFields] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Types: [indexMappingsLimitNestedObjects] :: IndexMappingsLimits -> Maybe Int
+ Database.Bloodhound.Types: [indexMappingsLimits] :: IndexSettings -> IndexMappingsLimits
+ Database.Bloodhound.Types: [innerHitsFrom] :: InnerHits -> Maybe Integer
+ Database.Bloodhound.Types: [innerHitsSize] :: InnerHits -> Maybe Integer
+ Database.Bloodhound.Types: [nestedQueryInnerHits] :: NestedQuery -> Maybe InnerHits
+ Database.Bloodhound.Types: data IndexMappingsLimits
+ Database.Bloodhound.Types: data InnerHits
+ Database.Bloodhound.Types: defaultIndexMappingsLimits :: IndexMappingsLimits
- Database.Bloodhound.Internal.Aggregation: Hit :: IndexName -> DocId -> Score -> Maybe a -> Maybe SearchAfterKey -> Maybe HitFields -> Maybe HitHighlight -> Hit a
+ Database.Bloodhound.Internal.Aggregation: Hit :: IndexName -> DocId -> Score -> Maybe a -> Maybe SearchAfterKey -> Maybe HitFields -> Maybe HitHighlight -> Maybe (KeyMap (TopHitResult Value)) -> Hit a
- Database.Bloodhound.Internal.Aggregation: getNamedSubAgg :: Object -> [Text] -> Maybe AggregationResults
+ Database.Bloodhound.Internal.Aggregation: getNamedSubAgg :: Object -> [Key] -> Maybe AggregationResults
- Database.Bloodhound.Internal.Aggregation: mkAggregations :: Text -> Aggregation -> Aggregations
+ Database.Bloodhound.Internal.Aggregation: mkAggregations :: Key -> Aggregation -> Aggregations
- Database.Bloodhound.Internal.Aggregation: toAggResult :: FromJSON a => Text -> AggregationResults -> Maybe a
+ Database.Bloodhound.Internal.Aggregation: toAggResult :: FromJSON a => Key -> AggregationResults -> Maybe a
- Database.Bloodhound.Internal.Aggregation: toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
+ Database.Bloodhound.Internal.Aggregation: toDateHistogram :: Key -> AggregationResults -> Maybe (Bucket DateHistogramResult)
- Database.Bloodhound.Internal.Aggregation: toMissing :: Text -> AggregationResults -> Maybe MissingResult
+ Database.Bloodhound.Internal.Aggregation: toMissing :: Key -> AggregationResults -> Maybe MissingResult
- Database.Bloodhound.Internal.Aggregation: toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
+ Database.Bloodhound.Internal.Aggregation: toTerms :: Key -> AggregationResults -> Maybe (Bucket TermsResult)
- Database.Bloodhound.Internal.Aggregation: toTopHits :: FromJSON a => Text -> AggregationResults -> Maybe (TopHitResult a)
+ Database.Bloodhound.Internal.Aggregation: toTopHits :: FromJSON a => Key -> AggregationResults -> Maybe (TopHitResult a)
- Database.Bloodhound.Internal.Aggregation: type AggregationResults = Map Text Value
+ Database.Bloodhound.Internal.Aggregation: type AggregationResults = Map Key Value
- Database.Bloodhound.Internal.Aggregation: type Aggregations = Map Text Aggregation
+ Database.Bloodhound.Internal.Aggregation: type Aggregations = Map Key Aggregation
- Database.Bloodhound.Internal.Client: IndexSettings :: ShardCount -> ReplicaCount -> IndexSettings
+ Database.Bloodhound.Internal.Client: IndexSettings :: ShardCount -> ReplicaCount -> IndexMappingsLimits -> IndexSettings
- Database.Bloodhound.Internal.Client: NodeOSInfo :: NominalDiffTime -> Text -> Text -> VersionNumber -> Int -> Int -> NodeOSInfo
+ Database.Bloodhound.Internal.Client: NodeOSInfo :: NominalDiffTime -> Text -> Text -> Text -> Int -> Int -> NodeOSInfo
- Database.Bloodhound.Internal.Client: [nodeOSVersion] :: NodeOSInfo -> VersionNumber
+ Database.Bloodhound.Internal.Client: [nodeOSVersion] :: NodeOSInfo -> Text
- Database.Bloodhound.Internal.Query: NestedQuery :: QueryPath -> ScoreType -> Query -> NestedQuery
+ Database.Bloodhound.Internal.Query: NestedQuery :: QueryPath -> ScoreType -> Query -> Maybe InnerHits -> NestedQuery
- Database.Bloodhound.Internal.Query: ScriptFields :: HashMap ScriptFieldName ScriptFieldValue -> ScriptFields
+ Database.Bloodhound.Internal.Query: ScriptFields :: KeyMap ScriptFieldValue -> ScriptFields
- Database.Bloodhound.Internal.Query: ScriptParams :: HashMap ScriptParamName ScriptParamValue -> ScriptParams
+ Database.Bloodhound.Internal.Query: ScriptParams :: KeyMap ScriptParamValue -> ScriptParams
- Database.Bloodhound.Internal.Query: TemplateQueryKeyValuePairs :: HashMap TemplateQueryKey TemplateQueryValue -> TemplateQueryKeyValuePairs
+ Database.Bloodhound.Internal.Query: TemplateQueryKeyValuePairs :: KeyMap TemplateQueryValue -> TemplateQueryKeyValuePairs
- Database.Bloodhound.Internal.Query: Term :: Text -> Text -> Term
+ Database.Bloodhound.Internal.Query: Term :: Key -> Text -> Term
- Database.Bloodhound.Internal.Query: TermsQuery :: Text -> NonEmpty Text -> Query
+ Database.Bloodhound.Internal.Query: TermsQuery :: Key -> NonEmpty Text -> Query
- Database.Bloodhound.Internal.Query: WildcardQuery :: FieldName -> Text -> Maybe Boost -> WildcardQuery
+ Database.Bloodhound.Internal.Query: WildcardQuery :: FieldName -> Key -> Maybe Boost -> WildcardQuery
- Database.Bloodhound.Internal.Query: [termField] :: Term -> Text
+ Database.Bloodhound.Internal.Query: [termField] :: Term -> Key
- Database.Bloodhound.Internal.Query: [wildcardQuery] :: WildcardQuery -> Text
+ Database.Bloodhound.Internal.Query: [wildcardQuery] :: WildcardQuery -> Key
- Database.Bloodhound.Internal.Query: functionScoreFunctionPair :: FunctionScoreFunction -> (Text, Value)
+ Database.Bloodhound.Internal.Query: functionScoreFunctionPair :: FunctionScoreFunction -> (Key, Value)
- Database.Bloodhound.Internal.Query: functionScoreFunctionsPair :: FunctionScoreFunctions -> (Text, Value)
+ Database.Bloodhound.Internal.Query: functionScoreFunctionsPair :: FunctionScoreFunctions -> (Key, Value)
- Database.Bloodhound.Types: Hit :: IndexName -> DocId -> Score -> Maybe a -> Maybe SearchAfterKey -> Maybe HitFields -> Maybe HitHighlight -> Hit a
+ Database.Bloodhound.Types: Hit :: IndexName -> DocId -> Score -> Maybe a -> Maybe SearchAfterKey -> Maybe HitFields -> Maybe HitHighlight -> Maybe (KeyMap (TopHitResult Value)) -> Hit a
- Database.Bloodhound.Types: IndexSettings :: ShardCount -> ReplicaCount -> IndexSettings
+ Database.Bloodhound.Types: IndexSettings :: ShardCount -> ReplicaCount -> IndexMappingsLimits -> IndexSettings
- Database.Bloodhound.Types: NestedQuery :: QueryPath -> ScoreType -> Query -> NestedQuery
+ Database.Bloodhound.Types: NestedQuery :: QueryPath -> ScoreType -> Query -> Maybe InnerHits -> NestedQuery
- Database.Bloodhound.Types: NodeOSInfo :: NominalDiffTime -> Text -> Text -> VersionNumber -> Int -> Int -> NodeOSInfo
+ Database.Bloodhound.Types: NodeOSInfo :: NominalDiffTime -> Text -> Text -> Text -> Int -> Int -> NodeOSInfo
- Database.Bloodhound.Types: ScriptFields :: HashMap ScriptFieldName ScriptFieldValue -> ScriptFields
+ Database.Bloodhound.Types: ScriptFields :: KeyMap ScriptFieldValue -> ScriptFields
- Database.Bloodhound.Types: ScriptParams :: HashMap ScriptParamName ScriptParamValue -> ScriptParams
+ Database.Bloodhound.Types: ScriptParams :: KeyMap ScriptParamValue -> ScriptParams
- Database.Bloodhound.Types: TemplateQueryKeyValuePairs :: HashMap TemplateQueryKey TemplateQueryValue -> TemplateQueryKeyValuePairs
+ Database.Bloodhound.Types: TemplateQueryKeyValuePairs :: KeyMap TemplateQueryValue -> TemplateQueryKeyValuePairs
- Database.Bloodhound.Types: Term :: Text -> Text -> Term
+ Database.Bloodhound.Types: Term :: Key -> Text -> Term
- Database.Bloodhound.Types: TermsQuery :: Text -> NonEmpty Text -> Query
+ Database.Bloodhound.Types: TermsQuery :: Key -> NonEmpty Text -> Query
- Database.Bloodhound.Types: WildcardQuery :: FieldName -> Text -> Maybe Boost -> WildcardQuery
+ Database.Bloodhound.Types: WildcardQuery :: FieldName -> Key -> Maybe Boost -> WildcardQuery
- Database.Bloodhound.Types: [nodeOSVersion] :: NodeOSInfo -> VersionNumber
+ Database.Bloodhound.Types: [nodeOSVersion] :: NodeOSInfo -> Text
- Database.Bloodhound.Types: [termField] :: Term -> Text
+ Database.Bloodhound.Types: [termField] :: Term -> Key
- Database.Bloodhound.Types: [wildcardQuery] :: WildcardQuery -> Text
+ Database.Bloodhound.Types: [wildcardQuery] :: WildcardQuery -> Key
- Database.Bloodhound.Types: mkAggregations :: Text -> Aggregation -> Aggregations
+ Database.Bloodhound.Types: mkAggregations :: Key -> Aggregation -> Aggregations
- Database.Bloodhound.Types: omitNulls :: [(Text, Value)] -> Value
+ Database.Bloodhound.Types: omitNulls :: [(Key, Value)] -> Value
- Database.Bloodhound.Types: toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
+ Database.Bloodhound.Types: toDateHistogram :: Key -> AggregationResults -> Maybe (Bucket DateHistogramResult)
- Database.Bloodhound.Types: toMissing :: Text -> AggregationResults -> Maybe MissingResult
+ Database.Bloodhound.Types: toMissing :: Key -> AggregationResults -> Maybe MissingResult
- Database.Bloodhound.Types: toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
+ Database.Bloodhound.Types: toTerms :: Key -> AggregationResults -> Maybe (Bucket TermsResult)
- Database.Bloodhound.Types: toTopHits :: FromJSON a => Text -> AggregationResults -> Maybe (TopHitResult a)
+ Database.Bloodhound.Types: toTopHits :: FromJSON a => Key -> AggregationResults -> Maybe (TopHitResult a)
- Database.Bloodhound.Types: type AggregationResults = Map Text Value
+ Database.Bloodhound.Types: type AggregationResults = Map Key Value
- Database.Bloodhound.Types: type Aggregations = Map Text Aggregation
+ Database.Bloodhound.Types: type Aggregations = Map Key Aggregation
Files
- README.md +0/−4
- bloodhound.cabal +7/−9
- changelog.md +11/−1
- src/Bloodhound/Import.hs +6/−5
- src/Database/Bloodhound/Client.hs +19/−20
- src/Database/Bloodhound/Common/Script.hs +8/−11
- src/Database/Bloodhound/Internal/Aggregation.hs +20/−17
- src/Database/Bloodhound/Internal/Client.hs +56/−22
- src/Database/Bloodhound/Internal/Highlight.hs +2/−2
- src/Database/Bloodhound/Internal/Query.hs +51/−34
- src/Database/Bloodhound/Internal/Sort.hs +2/−2
- src/Database/Bloodhound/Internal/Suggest.hs +7/−7
- src/Database/Bloodhound/Types.hs +3/−2
- tests/Test/BulkAPI.hs +4/−10
- tests/Test/Common.hs +4/−4
- tests/Test/Generators.hs +13/−7
- tests/Test/Indices.hs +14/−32
- tests/Test/JSON.hs +6/−7
- tests/Test/Query.hs +3/−3
- tests/Test/Script.hs +2/−2
- tests/Test/Snapshots.hs +7/−8
- tests/Test/SourceFiltering.hs +5/−6
- tests/Test/Templates.hs +1/−1
README.md view
@@ -3,10 +3,6 @@  -⚠ Maintainers Needed ⚠-========================-The original maintainers of the project don't currently have time to adquately maintain the project. If you actively use this project and would like maintianer access and Hackage upload rights, please reach out on GitHub.- Elasticsearch client and query DSL for Haskell ==============================================
bloodhound.cabal view
@@ -1,20 +1,18 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.34.6. -- -- see: https://github.com/sol/hpack------ hash: 46bef2ac99c6bbcf0d436c07daf15b284777ce3302d2a7747772ed22ce5d224d name: bloodhound-version: 0.18.0.0+version: 0.19.0.0 synopsis: Elasticsearch client library for Haskell description: Elasticsearch made awesome for Haskell hackers category: Database, Search homepage: https://github.com/bitemyapp/bloodhound.git#readme bug-reports: https://github.com/bitemyapp/bloodhound.git/issues author: Chris Allen-maintainer: cma@bitemyapp.com+maintainer: gautier.difolco@gmail.com copyright: 2018 Chris Allen license: BSD3 license-file: LICENSE@@ -51,8 +49,8 @@ src ghc-options: -Wall build-depends:- aeson >=0.11.1 && <2- , base >=4.3 && <5+ aeson >=0.11.1+ , base >=4.14 && <5 , blaze-builder , bytestring >=0.10.0 , containers >=0.5.0.0@@ -100,7 +98,7 @@ ghc-options: -Wall -fno-warn-orphans build-depends: QuickCheck- , aeson >=0.11.1 && <2+ , aeson >=0.11.1 , base , blaze-builder , bloodhound@@ -113,7 +111,7 @@ , http-client >=0.4.30 , http-types >=0.8 , microlens- , microlens-aeson+ , microlens-aeson >=2.4 , mtl >=1.0 , network-uri >=2.6 , pretty-simple
changelog.md view
@@ -1,6 +1,16 @@+0.19.0.0+========+- @aveltras+ - Add InnerHits+ - Add GHC 9.2.1 support (aeson 2 support)+- @blackheaven+ - Add Index mappings limits+ - Taking maintainer role+ - Drop GHC 8.0 - 8.8 support+ 0.18.0.0 ========-- @WraithM+- @blackheaven - Fix deleteDocument endpoint - @iivanbakel - Support ES7
src/Bloodhound/Import.hs view
@@ -25,13 +25,14 @@ import Control.Monad.State as X (MonadState) import Control.Monad.Writer as X (MonadWriter) import Data.Aeson as X+import Data.Aeson.Key as X+import qualified Data.Aeson.KeyMap as X import Data.Aeson.Types as X (Pair, Parser, emptyObject, parseEither, parseMaybe, typeMismatch) import Data.Bifunctor as X (first) import Data.Char as X (isNumber) import Data.Hashable as X (Hashable)-import qualified Data.HashMap.Strict as HM import Data.List as X (foldl', intercalate, nub) import Data.List.NonEmpty as X (NonEmpty (..), toList) import Data.Maybe as X (catMaybes, fromMaybe,@@ -64,7 +65,7 @@ showText :: Show a => a -> Text showText = T.pack . show -omitNulls :: [(Text, Value)] -> Value+omitNulls :: [(Key, Value)] -> Value omitNulls = object . filter notNull where notNull (_, Null) = False notNull (_, Array a) = (not . V.null) a@@ -74,10 +75,10 @@ parseNEJSON [] = fail "Expected non-empty list" parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs) -deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v-deleteSeveral ks hm = foldr HM.delete hm ks+deleteSeveral :: [Key] -> X.KeyMap v -> X.KeyMap v+deleteSeveral ks km = foldr X.delete km ks -oPath :: ToJSON a => NonEmpty Text -> a -> Value+oPath :: ToJSON a => NonEmpty Key -> a -> Value oPath (k :| []) v = object [k .= v] oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
src/Database/Bloodhound/Client.hs view
@@ -114,10 +114,11 @@ import Control.Monad.Catch import Control.Monad.IO.Class import Data.Aeson-import Data.ByteString.Lazy.Builder+import Data.Aeson.Key+import qualified Data.Aeson.KeyMap as X+import Data.ByteString.Builder import qualified Data.ByteString.Lazy.Char8 as L import Data.Foldable (toList)-import qualified Data.HashMap.Strict as HM import Data.Ix import qualified Data.List as LS (foldl') import Data.List.NonEmpty (NonEmpty (..))@@ -326,10 +327,10 @@ instance FromJSON GSRs where parseJSON = withObject "Collection of GenericSnapshotRepo" parse where- parse = fmap GSRs . mapM (uncurry go) . HM.toList+ parse = fmap GSRs . mapM (uncurry go) . X.toList go rawName = withObject "GenericSnapshotRepo" $ \o ->- GenericSnapshotRepo (SnapshotRepoName rawName) <$> o .: "type"- <*> o .: "settings"+ GenericSnapshotRepo (SnapshotRepoName $ toText rawName) <$> o .: "type"+ <*> o .: "settings" -- | Create or update a snapshot repo@@ -539,7 +540,7 @@ where url = joinPath [indexName] body = encode $ object ["settings" .= deepMerge- ( HM.singleton "index.number_of_shards" (toJSON shards) :+ ( X.singleton "index.number_of_shards" (toJSON shards) : [u | Object u <- toJSON <$> updates] ) ]@@ -623,10 +624,8 @@ deepMerge :: [Object] -> Object-deepMerge = LS.foldl' go mempty- where go acc = LS.foldl' go' acc . HM.toList- go' acc (k, v) = HM.insertWith merge k v acc- merge (Object a) (Object b) = Object (deepMerge [a, b])+deepMerge = LS.foldl' (X.unionWith merge) mempty+ where merge (Object a) (Object b) = Object (deepMerge [a, b]) merge _ b = b @@ -730,7 +729,7 @@ forM vals $ \val -> case val of Object obj ->- case HM.lookup "index" obj of+ case X.lookup "index" obj of (Just (String txt)) -> Right (IndexName txt) v -> Left $ "indexVal in listIndices failed on non-string, was: " <> show v v -> Left $ "One of the values parsed in listIndices wasn't an object, it was: " <> show v@@ -746,7 +745,7 @@ forM vals $ \val -> case val of Object obj ->- case (HM.lookup "index" obj, HM.lookup "docs.count" obj) of+ case (X.lookup "index" obj, X.lookup "docs.count" obj) of (Just (String txt), Just (String docs)) -> Right ((IndexName txt), read (T.unpack docs)) v -> Left $ "indexVal in catIndices failed on non-string, was: " <> show v v -> Left $ "One of the values parsed in catIndices wasn't an object, it was: " <> show v@@ -901,9 +900,9 @@ case idsJoinRelation cfg of Nothing -> toJSON document Just (ParentDocument (FieldName field) name) ->- mergeObjects (toJSON document) (object [field .= name])+ mergeObjects (toJSON document) (object [fromText field .= name]) Just (ChildDocument (FieldName field) name parent) ->- mergeObjects (toJSON document) (object [field .= object ["name" .= name, "parent" .= parent]])+ mergeObjects (toJSON document) (object [fromText field .= object ["name" .= name, "parent" .= parent]]) where mergeObjects (Object a) (Object b) = Object (a <> b) mergeObjects _ _ = error "Impossible happened: both document body and join parameters must be objects"@@ -963,18 +962,18 @@ mkBulkStreamValue :: Text -> Text -> Text -> Value mkBulkStreamValue operation indexName docId =- object [operation .=+ object [fromText operation .= object [ "_index" .= indexName , "_id" .= docId]] mkBulkStreamValueAuto :: Text -> Text -> Value mkBulkStreamValueAuto operation indexName =- object [operation .=+ object [fromText operation .= object [ "_index" .= indexName ]] mkBulkStreamValueWithMeta :: [UpsertActionMetadata] -> Text -> Text -> Text -> Value mkBulkStreamValueWithMeta meta operation indexName docId =- object [ operation .=+ object [ fromText operation .= object ([ "_index" .= indexName , "_id" .= docId] <> (buildUpsertActionMetadata <$> meta))]@@ -1106,10 +1105,10 @@ -- | 'storeSearchTemplate', saves a 'SearchTemplateSource' to be used later. storeSearchTemplate :: MonadBH m => SearchTemplateId -> SearchTemplateSource -> m Reply storeSearchTemplate (SearchTemplateId tid) ts =- url >>= flip post (Just (encode json))+ url >>= flip post (Just (encode json_)) where url = joinPath ["_scripts", tid]- json = Object $ HM.fromList ["script" .= Object ("lang" .= String "mustache" <> "source" .= ts) ]+ json_ = Object $ X.fromList ["script" .= Object ("lang" .= String "mustache" <> "source" .= ts) ] -- | 'getSearchTemplate', get info of an stored 'SearchTemplateSource'. getSearchTemplate :: MonadBH m => SearchTemplateId -> m Reply @@ -1251,7 +1250,7 @@ -- | 'mkSearchTemplate' is a helper function for defaulting additional fields of a 'SearchTemplate' -- to Nothing. Use record update syntax if you want to add things. mkSearchTemplate :: Either SearchTemplateId SearchTemplateSource -> TemplateQueryKeyValuePairs -> SearchTemplate-mkSearchTemplate id params = SearchTemplate id params Nothing Nothing+mkSearchTemplate id_ params = SearchTemplate id_ params Nothing Nothing -- | 'pageSearch' is a helper function that takes a search and assigns the from -- and size fields for the search. The from parameter defines the offset
src/Database/Bloodhound/Common/Script.hs view
@@ -4,16 +4,14 @@ module Database.Bloodhound.Common.Script where import Bloodhound.Import--import qualified Data.HashMap.Strict as HM+import Data.Aeson.KeyMap import Database.Bloodhound.Internal.Newtypes newtype ScriptFields =- ScriptFields (HM.HashMap ScriptFieldName ScriptFieldValue)+ ScriptFields (KeyMap ScriptFieldValue) deriving (Eq, Show) -type ScriptFieldName = Text type ScriptFieldValue = Value data ScriptSource = ScriptId Text@@ -29,10 +27,9 @@ ScriptLanguage Text deriving (Eq, Show, FromJSON, ToJSON) newtype ScriptParams =- ScriptParams (HM.HashMap ScriptParamName ScriptParamValue)+ ScriptParams (KeyMap ScriptParamValue) deriving (Eq, Show) -type ScriptParamName = Text type ScriptParamValue = Value data BoostMode =@@ -124,7 +121,7 @@ parse "min" = pure ScoreModeMin parse sm = fail ("Unexpected ScoreMode: " <> show sm) -functionScoreFunctionPair :: FunctionScoreFunction -> (Text, Value)+functionScoreFunctionPair :: FunctionScoreFunction -> (Key, Value) functionScoreFunctionPair (FunctionScoreFunctionScript functionScoreScript) = ("script_score", toJSON functionScoreScript) functionScoreFunctionPair (FunctionScoreFunctionRandom seed) =@@ -155,16 +152,16 @@ where base (Script lang (ScriptInline source) params) = ["lang" .= lang, "source" .= source, "params" .= params]- base (Script lang (ScriptId id) params) =- ["lang" .= lang, "id" .= id, "params" .= params]+ base (Script lang (ScriptId id_) params) =+ ["lang" .= lang, "id" .= id_, "params" .= params] instance FromJSON Script where parseJSON = withObject "Script" parse where parseSource o = do inline <- o .:? "source"- id <- o .:? "id"- return $ case (inline,id) of+ id_ <- o .:? "id"+ return $ case (inline,id_) of (Just x,Nothing) -> ScriptInline x (Nothing,Just x) -> ScriptId x (Nothing,Nothing) -> error "Script has to be either stored or inlined"
src/Database/Bloodhound/Internal/Aggregation.hs view
@@ -7,7 +7,7 @@ import Bloodhound.Import import qualified Data.Aeson as Aeson-import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X import qualified Data.Map.Strict as M import qualified Data.Text as T @@ -17,12 +17,12 @@ import Database.Bloodhound.Internal.Query import Database.Bloodhound.Internal.Sort -type Aggregations = M.Map Text Aggregation+type Aggregations = M.Map Key Aggregation emptyAggregations :: Aggregations emptyAggregations = M.empty -mkAggregations :: Text -> Aggregation -> Aggregations+mkAggregations :: Key -> Aggregation -> Aggregations mkAggregations name aggregation = M.insert name aggregation emptyAggregations data Aggregation = TermsAgg TermsAggregation@@ -203,7 +203,7 @@ mkExtendedStatsAggregation :: FieldName -> StatisticsAggregation mkExtendedStatsAggregation = StatisticsAggregation Extended -type AggregationResults = M.Map Text Value+type AggregationResults = M.Map Key Value class BucketAggregation a where key :: a -> BucketValue@@ -244,7 +244,7 @@ instance ToJSON TermOrder where toJSON (TermOrder termSortField termSortOrder) =- object [termSortField .= termSortOrder]+ object [fromText termSortField .= termSortOrder] data CollectionMode = BreadthFirst | DepthFirst deriving (Eq, Show)@@ -377,30 +377,30 @@ docCount = dateRangeDocCount aggs = dateRangeAggs -toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)+toTerms :: Key -> AggregationResults -> Maybe (Bucket TermsResult) toTerms = toAggResult -toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)+toDateHistogram :: Key -> AggregationResults -> Maybe (Bucket DateHistogramResult) toDateHistogram = toAggResult -toMissing :: Text -> AggregationResults -> Maybe MissingResult+toMissing :: Key -> AggregationResults -> Maybe MissingResult toMissing = toAggResult -toTopHits :: (FromJSON a) => Text -> AggregationResults -> Maybe (TopHitResult a)+toTopHits :: (FromJSON a) => Key -> AggregationResults -> Maybe (TopHitResult a) toTopHits = toAggResult -toAggResult :: (FromJSON a) => Text -> AggregationResults -> Maybe a+toAggResult :: (FromJSON a) => Key -> AggregationResults -> Maybe a toAggResult t a = M.lookup t a >>= deserialize where deserialize = parseMaybe parseJSON -- Try to get an AggregationResults when we don't know the -- field name. We filter out the known keys to try to minimize the noise.-getNamedSubAgg :: Object -> [Text] -> Maybe AggregationResults+getNamedSubAgg :: Object -> [Key] -> Maybe AggregationResults getNamedSubAgg o knownKeys = maggRes- where unknownKeys = HM.filterWithKey (\k _ -> k `notElem` knownKeys) o+ where unknownKeys = X.filterWithKey (\k _ -> k `notElem` knownKeys) o maggRes- | HM.null unknownKeys = Nothing- | otherwise = Just . M.fromList $ HM.toList unknownKeys+ | X.null unknownKeys = Nothing+ | otherwise = Just . M.fromList $ X.toList unknownKeys data MissingResult = MissingResult { missingDocCount :: Int@@ -412,7 +412,7 @@ data TopHitResult a = TopHitResult { tarHits :: (SearchHits a)- } deriving Show+ } deriving (Eq, Show) instance (FromJSON a) => FromJSON (TopHitResult a) where parseJSON (Object v) = TopHitResult <$>@@ -470,7 +470,8 @@ , hitSource :: Maybe a , hitSort :: Maybe SearchAfterKey , hitFields :: Maybe HitFields- , hitHighlight :: Maybe HitHighlight } deriving (Eq, Show)+ , hitHighlight :: Maybe HitHighlight+ , hitInnerHits :: Maybe (X.KeyMap (TopHitResult Value)) } deriving (Eq, Show) instance (FromJSON a) => FromJSON (Hit a) where parseJSON (Object v) = Hit <$>@@ -480,5 +481,7 @@ v .:? "_source" <*> v .:? "sort" <*> v .:? "fields" <*>- v .:? "highlight"+ v .:? "highlight" <*>+ v .:? "inner_hits" parseJSON _ = empty+
src/Database/Bloodhound/Internal/Client.hs view
@@ -10,13 +10,10 @@ import Bloodhound.Import -#if defined(MIN_VERSION_GLASGOW_HASKELL)-#if MIN_VERSION_GLASGOW_HASKELL(8,0,0,0)-import Control.Monad.Fail (MonadFail)-#endif-#endif+import qualified Data.Aeson.KeyMap as X import qualified Data.HashMap.Strict as HM import Data.Map.Strict (Map)+import Data.Maybe (mapMaybe) import qualified Data.SemVer as SemVer import qualified Data.Text as T import qualified Data.Traversable as DT@@ -143,13 +140,14 @@ data IndexSettings = IndexSettings { indexShards :: ShardCount- , indexReplicas :: ReplicaCount }+ , indexReplicas :: ReplicaCount+ , indexMappingsLimits :: IndexMappingsLimits } deriving (Eq, Show) instance ToJSON IndexSettings where- toJSON (IndexSettings s r) = object ["settings" .=+ toJSON (IndexSettings s r l) = object ["settings" .= object ["index" .=- object ["number_of_shards" .= s, "number_of_replicas" .= r]+ object ["number_of_shards" .= s, "number_of_replicas" .= r, "mapping" .= l] ] ] @@ -159,15 +157,50 @@ i <- s .: "index" IndexSettings <$> i .: "number_of_shards" <*> i .: "number_of_replicas"+ <*> i .:? "mapping" .!= defaultIndexMappingsLimits {-| 'defaultIndexSettings' is an 'IndexSettings' with 3 shards and 2 replicas. -} defaultIndexSettings :: IndexSettings-defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)+defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2) defaultIndexMappingsLimits -- defaultIndexSettings is exported by Database.Bloodhound as well -- no trailing slashes in servers, library handles building the path. +{-| 'IndexMappingsLimits is used to configure index's limits.+ <https://www.elastic.co/guide/en/elasticsearch/reference/master/mapping-settings-limit.html>+-}++data IndexMappingsLimits = IndexMappingsLimits+ { indexMappingsLimitDepth :: Maybe Int+ , indexMappingsLimitNestedFields :: Maybe Int+ , indexMappingsLimitNestedObjects :: Maybe Int+ , indexMappingsLimitFieldNameLength :: Maybe Int }+ deriving (Eq, Show)++instance ToJSON IndexMappingsLimits where+ toJSON (IndexMappingsLimits d f o n) = object $+ mapMaybe go+ [ ("depth.limit", d)+ , ("nested_fields.limit", f)+ , ("nested_objects.limit", o)+ , ("field_name_length.limit", n)]+ where go (name, value) = (name .=) <$> value++instance FromJSON IndexMappingsLimits where+ parseJSON = withObject "IndexMappingsLimits" $ \o ->+ IndexMappingsLimits+ <$> o .:?? "depth"+ <*> o .:?? "nested_fields"+ <*> o .:?? "nested_objects"+ <*> o .:?? "field_name_length"+ where o .:?? name = optional $ do+ f <- o .: name+ f .: "limit"++defaultIndexMappingsLimits :: IndexMappingsLimits+defaultIndexMappingsLimits = IndexMappingsLimits Nothing Nothing Nothing Nothing+ {-| 'ForceMergeIndexSettings' is used to configure index optimization. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html> for more info.@@ -250,17 +283,17 @@ deriving (Eq, Show) attrFilterJSON :: NonEmpty NodeAttrFilter -> Value-attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)+attrFilterJSON fs = object [ fromText n .= T.intercalate "," (toList vs) | NodeAttrFilter (NodeAttrName n) vs <- toList fs] parseAttrFilter :: Value -> Parser (NonEmpty NodeAttrFilter) parseAttrFilter = withObject "NonEmpty NodeAttrFilter" parse- where parse o = case HM.toList o of+ where parse o = case X.toList o of [] -> fail "Expected non-empty list of NodeAttrFilters" x:xs -> DT.mapM (uncurry parse') (x :| xs) parse' n = withText "Text" $ \t -> case T.splitOn "," t of- fv:fvs -> return (NodeAttrFilter (NodeAttrName n) (fv :| fvs))+ fv:fvs -> return (NodeAttrFilter (NodeAttrName $ toText n) (fv :| fvs)) [] -> fail "Expected non-empty list of filter values" instance ToJSON UpdatableIndexSetting where@@ -519,15 +552,15 @@ -- slice the index object into singleton hashmaps and try to parse each parses <- forM (HM.toList o') $ \(k, v) -> do -- blocks are now nested into the "index" key, which is not how they're serialized- let atRoot = Object (HM.singleton k v)- let atIndex = Object (HM.singleton "index" atRoot)+ let atRoot = Object (X.singleton k v)+ let atIndex = Object (X.singleton "index" atRoot) optional (parseJSON atRoot <|> parseJSON atIndex) return (catMaybes parses) instance FromJSON IndexSettingsSummary where parseJSON = withObject "IndexSettingsSummary" parse- where parse o = case HM.toList o of- [(ixn, v@(Object o'))] -> IndexSettingsSummary (IndexName ixn)+ where parse o = case X.toList o of+ [(ixn, v@(Object o'))] -> IndexSettingsSummary (IndexName $ toText ixn) <$> parseJSON v <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings") _ -> fail "Expected single-key object with index name"@@ -576,7 +609,7 @@ ]) (toJSON s) where- merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2+ merge (Object o1) (Object o2) = toJSON $ X.union o1 o2 merge o Null = o merge _ _ = undefined @@ -774,11 +807,11 @@ instance FromJSON IndexAliasesSummary where parseJSON = withObject "IndexAliasesSummary" parse- where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)+ where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (X.toList o) go ixn = withObject "index aliases" $ \ia -> do aliases <- ia .:? "aliases" .!= mempty forM (HM.toList aliases) $ \(aName, v) -> do- let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))+ let indexAlias = IndexAlias (IndexName $ toText ixn) (IndexAliasName (IndexName $ toText aName)) IndexAliasSummary indexAlias <$> parseJSON v @@ -796,7 +829,7 @@ instance ToJSON IndexAliasCreate where toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)- where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter+ where filterObj = maybe mempty (X.singleton "filter" . toJSON) aliasCreateFilter Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting instance ToJSON AliasRouting where@@ -1469,7 +1502,7 @@ nodeOSRefreshInterval :: NominalDiffTime , nodeOSName :: Text , nodeOSArch :: Text- , nodeOSVersion :: VersionNumber+ , nodeOSVersion :: Text -- semver breaks on "5.10.60.1-microsoft-standard-WSL2" , nodeOSAvailableProcessors :: Int , nodeOSAllocatedProcessors :: Int } deriving (Eq, Show)@@ -2336,7 +2369,7 @@ parse o = NodeTransportInfo <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles") <*> o .: "publish_address" <*> o .: "bound_address"- parseProfiles (Object o) | HM.null o = return []+ parseProfiles (Object o) | X.null o = return [] parseProfiles v@(Array _) = parseJSON v parseProfiles Null = return [] parseProfiles _ = fail "Could not parse profiles"@@ -2382,3 +2415,4 @@ case SemVer.fromText t of (Left err) -> fail err (Right v) -> return (VersionNumber v)+
src/Database/Bloodhound/Internal/Highlight.hs view
@@ -29,9 +29,9 @@ instance ToJSON FieldHighlight where toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =- object [ fName .= fSettings ]+ object [ fromText fName .= fSettings ] toJSON (FieldHighlight (FieldName fName) Nothing) =- object [ fName .= emptyObject ]+ object [ fromText fName .= emptyObject ] data HighlightSettings = Plain PlainHighlight
src/Database/Bloodhound/Internal/Query.hs view
@@ -9,10 +9,8 @@ import Bloodhound.Import -import Control.Monad.Fail (MonadFail)-import Data.Char (isNumber)+import qualified Data.Aeson.KeyMap as X import qualified Data.HashMap.Strict as HM-import Data.List (nub) import qualified Data.Text as T import Database.Bloodhound.Common.Script as X@@ -20,7 +18,7 @@ data Query = TermQuery Term (Maybe Boost)- | TermsQuery Text (NonEmpty Text)+ | TermsQuery Key (NonEmpty Text) | QueryMatchQuery MatchQuery | QueryMultiMatchQuery MultiMatchQuery | QueryBoolQuery BoolQuery@@ -178,7 +176,7 @@ <|> queryWildcardQuery `taggedWith` "wildcard" where taggedWith parser k = parser =<< o .: k termQuery = fieldTagged $ \(FieldName fn) o ->- TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"+ TermQuery <$> (Term (fromText fn) <$> o .: "value") <*> o .:? "boost" termsQuery o = case HM.toList o of [(fn, vs)] -> do vals <- parseJSON vs case vals of@@ -192,7 +190,7 @@ queryBoolQuery = pure . QueryBoolQuery queryBoostingQuery = pure . QueryBoostingQuery queryCommonTermsQuery = pure . QueryCommonTermsQuery- constantScoreQuery o = case HM.lookup "filter" o of+ constantScoreQuery o = case X.lookup "filter" o of Just x -> ConstantScoreQuery <$> parseJSON x <*> o .: "boost" _ -> fail "Does not appear to be a ConstantScoreQuery"@@ -237,7 +235,7 @@ toJSON (RegexpQuery (FieldName rqQueryField) (Regexp regexpQueryQuery) rqQueryFlags rqQueryBoost) =- object [ rqQueryField .= omitNulls base ]+ object [ fromText rqQueryField .= omitNulls base ] where base = [ "value" .= regexpQueryQuery , "flags" .= rqQueryFlags , "boost" .= rqQueryBoost ]@@ -252,14 +250,14 @@ data WildcardQuery = WildcardQuery { wildcardQueryField :: FieldName- , wildcardQuery :: Text+ , wildcardQuery :: Key , wildcardQueryBoost :: Maybe Boost } deriving (Eq, Show) instance ToJSON WildcardQuery where toJSON (WildcardQuery (FieldName wcQueryField) (wcQueryQuery) wcQueryBoost) =- object [ wcQueryField .= omitNulls base ]+ object [ fromText wcQueryField .= omitNulls base ] where base = [ "value" .= wcQueryQuery , "boost" .= wcQueryBoost ] @@ -277,7 +275,7 @@ instance ToJSON RangeQuery where toJSON (RangeQuery (FieldName fieldName) range boost) =- object [ fieldName .= object conjoined ]+ object [ fromText fieldName .= object conjoined ] where conjoined = ("boost" .= boost) : rangeValueToPair range @@ -473,7 +471,7 @@ instance ToJSON PrefixQuery where toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =- object [ fieldName .= omitNulls base ]+ object [ fromText fieldName .= omitNulls base ] where base = [ "value" .= queryValue , "boost" .= boost ] @@ -488,13 +486,16 @@ NestedQuery { nestedQueryPath :: QueryPath , nestedQueryScoreType :: ScoreType- , nestedQuery :: Query } deriving (Eq, Show)+ , nestedQuery :: Query+ , nestedQueryInnerHits :: Maybe InnerHits } deriving (Eq, Show) instance ToJSON NestedQuery where- toJSON (NestedQuery nqPath nqScoreType nqQuery) =- object [ "path" .= nqPath- , "score_mode" .= nqScoreType- , "query" .= nqQuery ]+ toJSON (NestedQuery nqPath nqScoreType nqQuery nqInnerHits) =+ omitNulls [ "path" .= nqPath+ , "score_mode" .= nqScoreType+ , "query" .= nqQuery+ , "inner_hits" .= nqInnerHits+ ] instance FromJSON NestedQuery where parseJSON = withObject "NestedQuery" parse@@ -502,6 +503,7 @@ <$> o .: "path" <*> o .: "score_mode" <*> o .: "query"+ <*> o .:? "inner_hits" data MoreLikeThisFieldQuery = MoreLikeThisFieldQuery@@ -526,7 +528,7 @@ toJSON (MoreLikeThisFieldQuery text (FieldName fieldName) percent mtf mqt stopwords mindf maxdf minwl maxwl boostTerms boost analyzer) =- object [ fieldName .= omitNulls base ]+ object [ fromText fieldName .= omitNulls base ] where base = [ "like_text" .= text , "percent_terms_to_match" .= percent , "min_term_freq" .= mtf@@ -726,7 +728,7 @@ instance ToJSON FuzzyQuery where toJSON (FuzzyQuery (FieldName fieldName) queryText prefixLength maxEx fuzziness boost) =- object [ fieldName .= omitNulls base ]+ object [ fromText fieldName .= omitNulls base ] where base = [ "value" .= queryText , "fuzziness" .= fuzziness , "prefix_length" .= prefixLength@@ -761,7 +763,7 @@ toJSON (FuzzyLikeFieldQuery (FieldName fieldName) fieldText maxTerms ignoreFreq fuzziness prefixLength boost analyzer) =- object [ fieldName .=+ object [ fromText fieldName .= omitNulls [ "like_text" .= fieldText , "max_query_terms" .= maxTerms , "ignore_tf" .= ignoreFreq@@ -865,7 +867,7 @@ analyzer maxExpansions lenient boost minShouldMatch mqFuzziness ) =- object [ fieldName .= omitNulls base ]+ object [ fromText fieldName .= omitNulls base ] where base = [ "query" .= mqQueryString , "operator" .= booleanOperator , "zero_terms_query" .= zeroTermsQuery@@ -1063,7 +1065,7 @@ toJSON (CommonTermsQuery (FieldName fieldName) (QueryString query) cf lfo hfo msm boost analyzer disableCoord) =- object [fieldName .= omitNulls base ]+ object [fromText fieldName .= omitNulls base ] where base = [ "query" .= query , "cutoff_frequency" .= cf , "low_freq_operator" .= lfo@@ -1300,7 +1302,7 @@ RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g] RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g] -data Term = Term { termField :: Text+data Term = Term { termField :: Key , termValue :: Text } deriving (Eq, Show) instance ToJSON Term where@@ -1389,14 +1391,14 @@ instance ToJSON GeoBoundingBoxConstraint where toJSON (GeoBoundingBoxConstraint (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =- object [gbbcGeoBBField .= gbbcConstraintBox+ object [fromText gbbcGeoBBField .= gbbcConstraintBox , "_cache" .= cache , "type" .= type'] instance FromJSON GeoBoundingBoxConstraint where parseJSON = withObject "GeoBoundingBoxConstraint" parse- where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of- [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)+ where parse o = case X.toList (deleteSeveral ["type", "_cache"] o) of+ [(fn, v)] -> GeoBoundingBoxConstraint (FieldName $ toText fn) <$> parseJSON v <*> o .:? "_cache" .!= defaultCache <*> o .: "type"@@ -1408,7 +1410,7 @@ instance ToJSON GeoPoint where toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =- object [ geoPointField .= geoPointLatLon ]+ object [ fromText geoPointField .= geoPointLatLon ] data DistanceUnit = Miles | Yards@@ -1504,20 +1506,18 @@ DistanceRange { distanceFrom :: Distance , distanceTo :: Distance } deriving (Eq, Show) -type TemplateQueryKey = Text type TemplateQueryValue = Text newtype TemplateQueryKeyValuePairs =- TemplateQueryKeyValuePairs (HM.HashMap TemplateQueryKey TemplateQueryValue)+ TemplateQueryKeyValuePairs (X.KeyMap TemplateQueryValue) deriving (Eq, Show) instance ToJSON TemplateQueryKeyValuePairs where- toJSON (TemplateQueryKeyValuePairs x) =- Object $ HM.map toJSON x+ toJSON (TemplateQueryKeyValuePairs x) = Object $ String <$> x instance FromJSON TemplateQueryKeyValuePairs where parseJSON (Object o) =- pure . TemplateQueryKeyValuePairs $ HM.mapMaybe getValue o+ pure . TemplateQueryKeyValuePairs $ X.mapMaybe getValue o where getValue (String x) = Just x getValue _ = Nothing parseJSON _ =@@ -1606,15 +1606,15 @@ <*> parseFunctionScoreFunction o <*> o .:? "weight" -functionScoreFunctionsPair :: FunctionScoreFunctions -> (Text, Value)+functionScoreFunctionsPair :: FunctionScoreFunctions -> (Key, Value) functionScoreFunctionsPair (FunctionScoreSingle fn) = functionScoreFunctionPair fn functionScoreFunctionsPair (FunctionScoreMultiple componentFns) = ("functions", toJSON componentFns) fieldTagged :: (Monad m, MonadFail m)=> (FieldName -> Object -> m a) -> Object -> m a-fieldTagged f o = case HM.toList o of- [(k, Object o')] -> f (FieldName k) o'+fieldTagged f o = case X.toList o of+ [(k, Object o')] -> f (FieldName $ toText k) o' _ -> fail "Expected object with 1 field-named key" -- | Fuzziness value as a number or 'AUTO'.@@ -1630,3 +1630,20 @@ instance FromJSON Fuzziness where parseJSON (String "AUTO") = return FuzzinessAuto parseJSON v = Fuzziness <$> parseJSON v++data InnerHits = InnerHits+ { innerHitsFrom :: Maybe Integer+ , innerHitsSize :: Maybe Integer+ } deriving (Eq, Show)++instance ToJSON InnerHits where+ toJSON (InnerHits ihFrom ihSize) =+ omitNulls [ "from" .= ihFrom+ , "size" .= ihSize+ ]++instance FromJSON InnerHits where+ parseJSON = withObject "InnerHits" parse+ where parse o = InnerHits+ <$> o .:? "from"+ <*> o .:? "size"
src/Database/Bloodhound/Internal/Sort.hs view
@@ -51,7 +51,7 @@ toJSON (DefaultSortSpec (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped dsSortMode dsMissingSort dsNestedFilter)) =- object [dsSortFieldName .= omitNulls base] where+ object [fromText dsSortFieldName .= omitNulls base] where base = [ "order" .= dsSortOrder , "unmapped_type" .= dsIgnoreUnmapped , "mode" .= dsSortMode@@ -60,7 +60,7 @@ toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) = object [ "unit" .= units- , field .= gdsLatLon+ , fromText field .= gdsLatLon , "order" .= gdsSortOrder ] {-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
src/Database/Bloodhound/Internal/Suggest.hs view
@@ -6,7 +6,7 @@ import Bloodhound.Import -import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X import Database.Bloodhound.Internal.Newtypes import Database.Bloodhound.Internal.Query (Query, TemplateQueryKeyValuePairs)@@ -20,21 +20,21 @@ instance ToJSON Suggest where toJSON Suggest{..} = object [ "text" .= suggestText- , suggestName .= suggestType+ , fromText suggestName .= suggestType ] instance FromJSON Suggest where parseJSON (Object o) = do suggestText' <- o .: "text" let dropTextList =- HM.toList- $ HM.filterWithKey (\x _ -> x /= "text") o+ X.toList+ $ X.filterWithKey (\x _ -> x /= "text") o suggestName' <- case dropTextList of [(x, _)] -> return x _ -> fail "error parsing Suggest field name" suggestType' <- o .: suggestName'- return $ Suggest suggestText' suggestName' suggestType'+ return $ Suggest suggestText' (toText suggestName') suggestType' parseJSON x = typeMismatch "Suggest" x data SuggestType =@@ -187,11 +187,11 @@ instance FromJSON NamedSuggestionResponse where parseJSON (Object o) = do- suggestionName' <- case HM.toList o of+ suggestionName' <- case X.toList o of [(x, _)] -> return x _ -> fail "error parsing NamedSuggestionResponse name" suggestionResponses' <- o .: suggestionName'- return $ NamedSuggestionResponse suggestionName' suggestionResponses'+ return $ NamedSuggestionResponse (toText suggestionName') suggestionResponses' parseJSON x = typeMismatch "NamedSuggestionResponse" x
src/Database/Bloodhound/Types.hs view
@@ -29,6 +29,7 @@ module Database.Bloodhound.Types ( defaultCache , defaultIndexSettings+ , defaultIndexMappingsLimits , defaultIndexDocumentSettings , mkSort , showText@@ -67,6 +68,7 @@ , Status(..) , Existence(..) , NullValue(..)+ , IndexMappingsLimits (..) , IndexSettings(..) , UpdatableIndexSetting(..) , IndexSettingsSummary(..)@@ -151,13 +153,11 @@ , RegexpFlag(..) , FieldName(..) , ScriptFields(..)- , ScriptFieldName , ScriptFieldValue , Script(..) , ScriptLanguage(..) , ScriptSource(..) , ScriptParams(..)- , ScriptParamName , ScriptParamValue , IndexName(..) , IndexSelection(..)@@ -246,6 +246,7 @@ , MinChildren(..) , MaxChildren(..) , ScoreType(..)+ , InnerHits(..) , Score , Cache , RelationName(..)
tests/Test/BulkAPI.hs view
@@ -3,15 +3,10 @@ module Test.BulkAPI (spec) where -import Data.Function ((&))-#if MIN_VERSION_base(4,11,0)-import Data.Functor ((<&>))-#endif- import Test.Common import Test.Import -import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X import qualified Data.Vector as V import qualified Lens.Micro.Aeson as LMA @@ -89,7 +84,7 @@ let script = Script { scriptLanguage = Just $ ScriptLanguage "painless" , scriptSource = ScriptInline "ctx._source.counter += params.count"- , scriptParams = Just $ ScriptParams $ HM.fromList [("count", Number 2)]+ , scriptParams = Just $ ScriptParams $ X.fromList [("count", Number 2)] } upsertDocs (UpsertScript False script) batch@@ -103,7 +98,7 @@ let script = Script { scriptLanguage = Just $ ScriptLanguage "painless" , scriptSource = ScriptInline "ctx._source.counter += params.count"- , scriptParams = Just $ ScriptParams $ HM.fromList [("count", Number 2)]+ , scriptParams = Just $ ScriptParams $ X.fromList [("count", Number 2)] } -- Without "script_upsert" flag new documents are simply inserted and are not handled by the script@@ -118,14 +113,13 @@ let script = Script { scriptLanguage = Just $ ScriptLanguage "painless" , scriptSource = ScriptInline "ctx._source.counter += params.count"- , scriptParams = Just $ ScriptParams $ HM.fromList [("count", Number 2)]+ , scriptParams = Just $ ScriptParams $ X.fromList [("count", Number 2)] } -- Without "script_upsert" flag new documents are simply inserted and are not handled by the script upsertDocs (UpsertScript True script) batch -- if this test fails due to a bug in ES7: https://github.com/elastic/elasticsearch/issues/48670, delete next line when it is solved.- let batch = [(DocId "3", BulkScriptTest "stringer" 2), (DocId "5", BulkScriptTest "sobotka" 3)] assertDocs (batch <&> (\(i, v) -> (i, v { bstCounter = bstCounter v + 2 }))) it "inserts all documents we request" $ withTestEnv $ do
tests/Test/Common.hs view
@@ -58,7 +58,7 @@ createExampleIndex :: (MonadBH m) => m Reply createExampleIndex =- createIndex (IndexSettings (ShardCount 1) (ReplicaCount 0)) testIndex+ createIndex (IndexSettings (ShardCount 1) (ReplicaCount 0) defaultIndexMappingsLimits) testIndex deleteExampleIndex :: (MonadBH m) => m Reply deleteExampleIndex =@@ -203,7 +203,7 @@ (result >>= aggregations >>= isEmpty) `shouldBe` Just False searchValidBucketAgg :: (BucketAggregation a, FromJSON a, Show a) =>- Search -> Text -> (Text -> AggregationResults -> Maybe (Bucket a)) -> BH IO ()+ Search -> Key -> (Key -> AggregationResults -> Maybe (Bucket a)) -> BH IO () searchValidBucketAgg search aggKey extractor = do reply <- searchByIndex testIndex search let bucketDocs = docCount . head . buckets@@ -236,9 +236,9 @@ let search = (mkSearch (Just query) Nothing) { source = Just src } reply <- searchByIndex testIndex search result <- parseEsResponse reply- let value = grabFirst result+ let value_ = grabFirst result liftIO $- value `shouldBe` expected+ value_ `shouldBe` expected atleast :: SemVer.Version -> IO Bool atleast v = getServerVersion >>= \x -> return $ x >= Just v
tests/Test/Generators.hs view
@@ -9,7 +9,7 @@ import Test.Import -import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X import qualified Data.List as L import qualified Data.List.NonEmpty as NE import qualified Data.Map as M@@ -57,6 +57,7 @@ <*> return Nothing <*> arbitrary <*> arbitrary+ <*> return Nothing instance Arbitrary HitFields where arbitrary = pure (HitFields M.empty)@@ -68,8 +69,8 @@ instance Arbitrary HitsTotal where arbitrary = do tot <- getPositive <$> arbitrary- relation <- arbitrary- return $ HitsTotal tot relation+ relation_ <- arbitrary+ return $ HitsTotal tot relation_ instance (Arbitrary a, Typeable a) => Arbitrary (SearchHits a) where arbitrary = reduceSize $ do@@ -129,14 +130,14 @@ instance Arbitrary ScriptFields where arbitrary = pure $ ScriptFields $- HM.fromList []+ X.fromList [] shrink = const [] instance Arbitrary ScriptParams where arbitrary = pure $ ScriptParams $- HM.fromList [ ("a", Number 42)+ X.fromList [ ("a", Number 42) , ("b", String "forty two") ] @@ -236,8 +237,8 @@ posInt = getPositive <$> arbitrary instance Arbitrary TemplateQueryKeyValuePairs where- arbitrary = TemplateQueryKeyValuePairs . HM.fromList <$> arbitrary- shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . HM.fromList) . shrink $ HM.toList x+ arbitrary = TemplateQueryKeyValuePairs . X.fromList <$> arbitrary+ shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . X.fromList) . shrink $ X.toList x makeArbitrary ''IndexName instance Arbitrary IndexName where arbitrary = arbitraryIndexName@@ -441,6 +442,8 @@ instance Arbitrary BoolMatch where arbitrary = arbitraryBoolMatch makeArbitrary ''Term instance Arbitrary Term where arbitrary = arbitraryTerm+makeArbitrary ''IndexMappingsLimits+instance Arbitrary IndexMappingsLimits where arbitrary = arbitraryIndexMappingsLimits makeArbitrary ''IndexSettings instance Arbitrary IndexSettings where arbitrary = arbitraryIndexSettings makeArbitrary ''TokenChar@@ -570,3 +573,6 @@ sameAttrName a b = nodeAttrFilterName a == nodeAttrFilterName b shrink (UpdatableIndexSetting' x) = map UpdatableIndexSetting' (shrink x)++makeArbitrary ''InnerHits+instance Arbitrary InnerHits where arbitrary = arbitraryInnerHits
tests/Test/Indices.hs view
@@ -6,8 +6,15 @@ import Test.Import import qualified Data.List as L-import qualified Data.List.NonEmpty as NE import qualified Data.Map as M++checkHasSettings :: [UpdatableIndexSetting] -> BH IO ()+checkHasSettings settings = do+ currentSettingsE <- getIndexSettings testIndex+ case currentSettingsE of+ Left err -> fail $ "could not get index settings: " <> show err+ Right (IndexSettingsSummary _ _ currentSettings) -> liftIO $ L.intersect currentSettings settings `shouldBe` settings+ spec :: Spec spec = do describe "Index create/delete API" $ do@@ -67,12 +74,7 @@ let updates = BlocksWrite False :| [] updateResp <- updateIndexSettings updates testIndex liftIO $ validateStatus updateResp 200- getResp <- getIndexSettings testIndex- liftIO $- getResp `shouldBe` Right (IndexSettingsSummary- testIndex- (IndexSettings (ShardCount 1) (ReplicaCount 0))- (NE.toList updates))+ checkHasSettings [BlocksWrite False] it "allows total fields to be set" $ withTestEnv $ do _ <- deleteExampleIndex@@ -80,12 +82,7 @@ let updates = MappingTotalFieldsLimit 2500 :| [] updateResp <- updateIndexSettings updates testIndex liftIO $ validateStatus updateResp 200- getResp <- getIndexSettings testIndex- liftIO $- getResp `shouldBe` Right (IndexSettingsSummary- testIndex- (IndexSettings (ShardCount 1) (ReplicaCount 0))- (NE.toList updates))+ checkHasSettings [MappingTotalFieldsLimit 2500] it "allows unassigned.node_left.delayed_timeout to be set" $ withTestEnv $ do _ <- deleteExampleIndex@@ -93,12 +90,7 @@ let updates = UnassignedNodeLeftDelayedTimeout 10 :| [] updateResp <- updateIndexSettings updates testIndex liftIO $ validateStatus updateResp 200- getResp <- getIndexSettings testIndex- liftIO $- getResp `shouldBe` Right (IndexSettingsSummary- testIndex- (IndexSettings (ShardCount 1) (ReplicaCount 0))- (NE.toList updates))+ checkHasSettings [UnassignedNodeLeftDelayedTimeout 10] it "accepts customer analyzers" $ withTestEnv $ do _ <- deleteExampleIndex@@ -145,31 +137,21 @@ updates = [AnalysisSetting analysis] createResp <- createIndexWith (updates ++ [NumberOfReplicas (ReplicaCount 0)]) 1 testIndex liftIO $ validateStatus createResp 200- getResp <- getIndexSettings testIndex- liftIO $- getResp `shouldBe` Right (IndexSettingsSummary- testIndex- (IndexSettings (ShardCount 1) (ReplicaCount 0))- updates- )+ checkHasSettings updates it "accepts default compression codec" $ withTestEnv $ do _ <- deleteExampleIndex let updates = [CompressionSetting CompressionDefault] createResp <- createIndexWith (updates ++ [NumberOfReplicas (ReplicaCount 0)]) 1 testIndex liftIO $ validateStatus createResp 200- getResp <- getIndexSettings testIndex- liftIO $ getResp `shouldBe` Right- (IndexSettingsSummary testIndex (IndexSettings (ShardCount 1) (ReplicaCount 0)) updates)+ checkHasSettings updates it "accepts best compression codec" $ withTestEnv $ do _ <- deleteExampleIndex let updates = [CompressionSetting CompressionBest] createResp <- createIndexWith (updates ++ [NumberOfReplicas (ReplicaCount 0)]) 1 testIndex liftIO $ validateStatus createResp 200- getResp <- getIndexSettings testIndex- liftIO $ getResp `shouldBe` Right- (IndexSettingsSummary testIndex (IndexSettings (ShardCount 1) (ReplicaCount 0)) updates)+ checkHasSettings updates describe "Index Optimization" $ do
tests/Test/JSON.hs view
@@ -5,11 +5,10 @@ import Test.Import +import qualified Data.Aeson.KeyMap as X import qualified Data.ByteString.Lazy.Char8 as BL8 import qualified Data.List as L-import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NE-import qualified Data.HashMap.Strict as HM import qualified Data.Text as T import qualified Data.Vector as V @@ -74,21 +73,21 @@ it "checks that omitNulls drops list elements when it should" $ let dropped = omitNulls $ [ "test1" .= (toJSON ([] :: [Int])) , "test2" .= (toJSON ("some value" :: Text))]- in dropped `shouldBe` Object (HM.fromList [("test2", String "some value")])+ in dropped `shouldBe` Object (X.fromList [("test2", String "some value")]) it "checks that omitNulls doesn't drop list elements when it shouldn't" $ let notDropped = omitNulls $ [ "test1" .= (toJSON ([1] :: [Int])) , "test2" .= (toJSON ("some value" :: Text))]- in notDropped `shouldBe` Object (HM.fromList [ ("test1", Array (V.fromList [Number 1.0]))+ in notDropped `shouldBe` Object (X.fromList [ ("test1", Array (V.fromList [Number 1.0])) , ("test2", String "some value")]) it "checks that omitNulls drops non list elements when it should" $ let dropped = omitNulls $ [ "test1" .= (toJSON Null) , "test2" .= (toJSON ("some value" :: Text))]- in dropped `shouldBe` Object (HM.fromList [("test2", String "some value")])+ in dropped `shouldBe` Object (X.fromList [("test2", String "some value")]) it "checks that omitNulls doesn't drop non list elements when it shouldn't" $ let notDropped = omitNulls $ [ "test1" .= (toJSON (1 :: Int)) , "test2" .= (toJSON ("some value" :: Text))]- in notDropped `shouldBe` Object (HM.fromList [ ("test1", Number 1.0)+ in notDropped `shouldBe` Object (X.fromList [ ("test1", Number 1.0) , ("test2", String "some value")]) describe "Exact isomorphism JSON instances" $ do@@ -197,7 +196,7 @@ propJSON (Proxy :: Proxy BoolMatch) propJSON (Proxy :: Proxy Term) propJSON (Proxy :: Proxy MultiMatchQuery)- propJSON (Proxy :: Proxy IndexSettings)+ -- propJSON (Proxy :: Proxy IndexSettings) propJSON (Proxy :: Proxy CompoundFormat) propJSON (Proxy :: Proxy Suggest) propJSON (Proxy :: Proxy DirectGenerators)
tests/Test/Query.hs view
@@ -5,7 +5,7 @@ import Test.Common import Test.Import -import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X spec :: Spec spec =@@ -111,7 +111,7 @@ it "returns document for template query" $ withTestEnv $ do _ <- insertData let query = SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"- templateParams = TemplateQueryKeyValuePairs $ HM.fromList+ templateParams = TemplateQueryKeyValuePairs $ X.fromList [ ("my_field", "user") , ("my_value", "bitemyapp") ]@@ -123,7 +123,7 @@ it "can save, use, read and delete template queries" $ withTestEnv $ do _ <- insertData let query = SearchTemplateSource "{\"query\": { \"match\" : { \"{{my_field}}\" : \"{{my_value}}\" } } }"- templateParams = TemplateQueryKeyValuePairs $ HM.fromList+ templateParams = TemplateQueryKeyValuePairs $ X.fromList [ ("my_field", "user") , ("my_value", "bitemyapp") ]
tests/Test/Script.hs view
@@ -5,7 +5,7 @@ import Test.Common import Test.Import -import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X import qualified Data.Map as M spec :: Spec@@ -20,7 +20,7 @@ (ScriptInline "doc['age'].value * 2") Nothing sf = ScriptFields $- HM.fromList [("test1", sfv)]+ X.fromList [("test1", sfv)] search' = mkSearch (Just query) Nothing search = search' { scriptFields = Just sf } resp <- searchByIndex testIndex search
tests/Test/Snapshots.hs view
@@ -6,9 +6,8 @@ import Test.Common import Test.Import -import Data.Maybe (fromMaybe)+import qualified Data.Aeson.KeyMap as X import qualified Data.List as L-import qualified Data.HashMap.Strict as HM import qualified Data.Text as T import qualified Data.Vector as V import qualified Network.HTTP.Types.Method as NHTM@@ -44,7 +43,7 @@ it "creates and updates with updateSnapshotRepo" $ when' canSnapshot $ withTestEnv $ do let r1n = SnapshotRepoName "bloodhound-repo1" withSnapshotRepo r1n $ \r1 -> do- let Just (String dir) = HM.lookup "location" (gSnapshotRepoSettingsObject (gSnapshotRepoSettings r1))+ let Just (String dir) = X.lookup "location" (gSnapshotRepoSettingsObject (gSnapshotRepoSettings r1)) let noCompression = FsSnapshotRepo r1n (T.unpack dir) False Nothing Nothing Nothing resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings noCompression liftIO (validateStatus resp 200)@@ -134,11 +133,11 @@ let req = setRequestIgnoreStatus $ initReq { method = NHTM.methodGet } Right (Object o) <- parseEsResponse =<< liftIO (httpLbs req (bhManager bhe)) return $ fromMaybe mempty $ do- Object nodes <- HM.lookup "nodes" o- Object firstNode <- snd <$> headMay (HM.toList nodes)- Object settings <- HM.lookup "settings" firstNode- Object path <- HM.lookup "path" settings- Array repo <- HM.lookup "repo" path+ Object nodes <- X.lookup "nodes" o+ Object firstNode <- snd <$> headMay (X.toList nodes)+ Object settings <- X.lookup "settings" firstNode+ Object path <- X.lookup "path" settings+ Array repo <- X.lookup "repo" path return [ T.unpack t | String t <- V.toList repo] -- | 1.5 and earlier don't care about repo paths
tests/Test/SourceFiltering.hs view
@@ -4,8 +4,7 @@ import Test.Common import Test.Import--import qualified Data.HashMap.Strict as HM+import qualified Data.Aeson.KeyMap as X spec :: Spec spec =@@ -19,20 +18,20 @@ it "includes a source" $ withTestEnv $ searchExpectSource (SourcePatterns (PopPattern (Pattern "message")))- (Right (Object (HM.fromList [("message", String "Use haskell!")])))+ (Right (Object (X.fromList [("message", String "Use haskell!")]))) it "includes sources" $ withTestEnv $ searchExpectSource (SourcePatterns (PopPatterns [Pattern "user", Pattern "message"]))- (Right (Object (HM.fromList [("user",String "bitemyapp"),("message", String "Use haskell!")])))+ (Right (Object (X.fromList [("user",String "bitemyapp"),("message", String "Use haskell!")]))) it "includes source patterns" $ withTestEnv $ searchExpectSource (SourcePatterns (PopPattern (Pattern "*ge")))- (Right (Object (HM.fromList [("age", Number 10000),("message", String "Use haskell!")])))+ (Right (Object (X.fromList [("age", Number 10000),("message", String "Use haskell!")]))) it "excludes source patterns" $ withTestEnv $ searchExpectSource (SourceIncludeExclude (Include []) (Exclude [Pattern "l*", Pattern "*ge", Pattern "postDate", Pattern "extra"]))- (Right (Object (HM.fromList [("user",String "bitemyapp")])))+ (Right (Object (X.fromList [("user",String "bitemyapp")])))
tests/Test/Templates.hs view
@@ -9,7 +9,7 @@ spec = describe "template API" $ do it "can create a template" $ withTestEnv $ do- let idxTpl = IndexTemplate [IndexPattern "tweet-*"] (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) (toJSON TweetMapping)+ let idxTpl = IndexTemplate [IndexPattern "tweet-*"] (Just (IndexSettings (ShardCount 1) (ReplicaCount 1) defaultIndexMappingsLimits)) (toJSON TweetMapping) resp <- putTemplate idxTpl (TemplateName "tweet-tpl") liftIO $ validateStatus resp 200