git.iko.soy/typeable/bloodhound
on master help sign in
Added ability to manipulate templates
commita4d6c1e66da9324cc4654f008b6921458509c873 authorJohn Galt <centromere@users.noreply.github.com> dateFri 17 Jul 2015, 13:21 (11 years ago) parent1db8ad7
4 files changed+91−2
bloodhound.cabal+2−1 src/Database/Bloodhound/Client.hs+32 src/Database/Bloodhound/Types.hs+39−1 tests/tests.hs+18
bloodhound.cabal+2−1
@@ -38,7 +38,8 @@ library
3838 uri-bytestring >= 0.1 && <0.2,
3939 exceptions,
4040 data-default-class,
41− blaze-builder
41+ blaze-builder,
42+ unordered-containers
4243 default-language: Haskell2010
4344
4445test-suite tests
src/Database/Bloodhound/Client.hs+32
@@ -27,6 +27,9 @@ module Database.Bloodhound.Client
2727 , indexExists
2828 , openIndex
2929 , closeIndex
30+ , putTemplate
31+ , templateExists
32+ , deleteTemplate
3033 , putMapping
3134 , deleteMapping
3235 , indexDocument
@@ -301,6 +304,35 @@ openIndex = openOrCloseIndexes OpenIndex
301304closeIndex :: MonadBH m => IndexName -> m Reply
302305closeIndex = openOrCloseIndexes CloseIndex
303306
307+-- | 'putTemplate' creates a template given an 'IndexTemplate' and a 'TemplateName'.
308+-- Explained in further detail at
309+-- <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html>
310+--
311+-- >>> let idxTpl = IndexTemplate (TemplatePattern "tweet-*") (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) [toJSON TweetMapping]
312+-- >>> resp <- runBH' $ putTemplate idxTpl (TemplateName "tweet-tpl")
313+putTemplate :: MonadBH m => IndexTemplate -> TemplateName -> m Reply
314+putTemplate indexTemplate (TemplateName templateName) =
315+ bindM2 put url (return body)
316+ where url = joinPath ["_template", templateName]
317+ body = Just $ encode indexTemplate
318+
319+-- | 'templateExists' checks to see if a template exists.
320+--
321+-- >>> exists <- runBH' $ templateExists (TemplateName "tweet-tpl")
322+templateExists :: MonadBH m => TemplateName -> m Bool
323+templateExists (TemplateName templateName) = do
324+ (_, exists) <- existentialQuery =<< joinPath ["_template", templateName]
325+ return exists
326+
327+-- | 'deleteTemplate' is an HTTP DELETE and deletes a template.
328+--
329+-- >>> let idxTpl = IndexTemplate (TemplatePattern "tweet-*") (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) [toJSON TweetMapping]
330+-- >>> _ <- runBH' $ putTemplate idxTpl (TemplateName "tweet-tpl")
331+-- >>> resp <- runBH' $ deleteTemplate (TemplateName "tweet-tpl")
332+deleteTemplate :: MonadBH m => TemplateName -> m Reply
333+deleteTemplate (TemplateName templateName) =
334+ delete =<< joinPath ["_template", templateName]
335+
304336-- | 'putMapping' is an HTTP PUT and has upsert semantics. Mappings are schemas
305337-- for documents in indexes.
306338--
src/Database/Bloodhound/Types.hs+39−1
@@ -56,6 +56,7 @@ module Database.Bloodhound.Types
5656 , Existence(..)
5757 , NullValue(..)
5858 , IndexSettings(..)
59+ , IndexTemplate(..)
5960 , Server(..)
6061 , Reply
6162 , EsResult(..)
@@ -101,6 +102,8 @@ module Database.Bloodhound.Types
101102 , RegexpFlag(..)
102103 , FieldName(..)
103104 , IndexName(..)
105+ , TemplateName(..)
106+ , TemplatePattern(..)
104107 , MappingName(..)
105108 , DocId(..)
106109 , CacheName(..)
@@ -222,8 +225,9 @@ import Control.Monad.Writer
222225import Data.Aeson
223226import Data.Aeson.Types (Pair, emptyObject, parseMaybe)
224227import qualified Data.ByteString.Lazy.Char8 as L
225−import Data.List (nub)
228+import Data.List (nub, foldl')
226229import Data.List.NonEmpty (NonEmpty (..), toList)
230+import qualified Data.HashMap.Strict as HM (union)
227231import qualified Data.Map.Strict as M
228232import Data.Maybe
229233import Data.Text (Text)
@@ -348,6 +352,20 @@ data FieldType = GeoPointType
348352data FieldDefinition =
349353 FieldDefinition { fieldType :: FieldType } deriving (Eq, Show)
350354
355+{-| An 'IndexTemplate' defines a template that will automatically be
356+ applied to new indices created. The templates include both
357+ 'IndexSettings' and mappings, and a simple 'TemplatePattern' that
358+ controls if the template will be applied to the index created.
359+ Specify mappings as follows: @[toJSON TweetMapping, ...]@
360+
361+ https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
362+-}
363+data IndexTemplate =
364+ IndexTemplate { templatePattern :: TemplatePattern
365+ , templateSettings :: Maybe IndexSettings
366+ , templateMappings :: [Value]
367+ }
368+
351369data MappingField =
352370 MappingField { mappingFieldName :: FieldName
353371 , fieldDefinition :: FieldDefinition } deriving (Eq, Show)
@@ -546,6 +564,14 @@ newtype Server = Server Text deriving (Eq, Show)
546564-}
547565newtype IndexName = IndexName Text deriving (Eq, Generic, Show)
548566
567+{-| 'TemplateName' is used to describe which template to query/create/delete
568+-}
569+newtype TemplateName = TemplateName Text deriving (Eq, Show, Generic)
570+
571+{-| 'TemplatePattern' represents a pattern which is matched against index names
572+-}
573+newtype TemplatePattern = TemplatePattern Text deriving (Eq, Show, Generic)
574+
549575{-| 'MappingName' is part of mappings which are how ES describes and schematizes
550576 the data in the indices.
551577-}
@@ -1953,6 +1979,8 @@ instance ToJSON IgnoreTermFrequency
19531979instance ToJSON MaxQueryTerms
19541980instance ToJSON TypeName
19551981instance ToJSON IndexName
1982+instance ToJSON TemplateName
1983+instance ToJSON TemplatePattern
19561984instance ToJSON BoostTerms
19571985instance ToJSON MaxWordLength
19581986instance ToJSON MinWordLength
@@ -1991,6 +2019,16 @@ instance FromJSON Status where
19912019instance ToJSON IndexSettings where
19922020 toJSON (IndexSettings s r) = object ["settings" .= object ["shards" .= s, "replicas" .= r]]
19932021
2022+instance ToJSON IndexTemplate where
2023+ toJSON (IndexTemplate p s m) =
2024+ objectNoNulls [ "template" .= p
2025+ , "settings" .= s
2026+ , "mappings" .= foldl' merge (object []) m
2027+ ]
2028+ where
2029+ objectNoNulls = object . filter (\(_, v) -> v /= Null)
2030+ merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
2031+ merge _ _ = undefined
19942032
19952033instance (FromJSON a) => FromJSON (EsResult a) where
19962034 parseJSON (Object v) = EsResult <$>
tests/tests.hs+18
@@ -309,6 +309,24 @@ main = hspec $ do
309309 res' <- insertData' cfg
310310 liftIO $ isVersionConflict res' `shouldBe` True
311311
312+ describe "template API" $ do
313+ it "can create a template" $ withTestEnv $ do
314+ let idxTpl = IndexTemplate (TemplatePattern "tweet-*") (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) [toJSON TweetMapping]
315+ resp <- putTemplate idxTpl (TemplateName "tweet-tpl")
316+ liftIO $ validateStatus resp 200
317+
318+ it "can detect if a template exists" $ withTestEnv $ do
319+ exists <- templateExists (TemplateName "tweet-tpl")
320+ liftIO $ exists `shouldBe` True
321+
322+ it "can delete a template" $ withTestEnv $ do
323+ resp <- deleteTemplate (TemplateName "tweet-tpl")
324+ liftIO $ validateStatus resp 200
325+
326+ it "can detect if a template doesn't exist" $ withTestEnv $ do
327+ exists <- templateExists (TemplateName "tweet-tpl")
328+ liftIO $ exists `shouldBe` False
329+
312330 describe "bulk API" $ do
313331 it "inserts all documents we request" $ withTestEnv $ do
314332 _ <- insertData