git.iko.soy/typeable/bloodhound
on master help sign in
V1 refactor building and passing tests now
14379a3Michael Xavier
bloodhound.cabal+9−11
@@ -30,7 +30,7 @@ Flag ES1
30Flag ES5
30Flag ES5
31 Description: Run the test suite against an Elasticsearch 5.x server
31 Description: Run the test suite against an Elasticsearch 5.x server
32 Default: True
32 Default: True
33−
33+
34library
34library
35 ghc-options: -Wall
35 ghc-options: -Wall
36 exposed-modules: Database.V5.Bloodhound
36 exposed-modules: Database.V5.Bloodhound
@@ -51,16 +51,15 @@ library
51 Database.V1.Bloodhound.Client
51 Database.V1.Bloodhound.Client
52 Database.V1.Bloodhound.Types
52 Database.V1.Bloodhound.Types
53 Database.V1.Bloodhound.Types.Class
53 Database.V1.Bloodhound.Types.Class
54−
55− -- Database.V1.Bloodhound.Internal.Aggregation
54+ Database.V1.Bloodhound.Internal.Aggregation
56− -- Database.V1.Bloodhound.Internal.Analysis
57− -- Database.V1.Bloodhound.Internal.Client
55+ Database.V1.Bloodhound.Internal.Client
58− -- Database.V1.Bloodhound.Internal.Highlight
56+ Database.V1.Bloodhound.Internal.Highlight
59− -- Database.V1.Bloodhound.Internal.Newtypes
57+ Database.V1.Bloodhound.Internal.Newtypes
60− -- Database.V1.Bloodhound.Internal.Query
58+ Database.V1.Bloodhound.Internal.Query
61− -- Database.V1.Bloodhound.Internal.Sort
59+ Database.V1.Bloodhound.Internal.Sort
62 Database.V1.Bloodhound.Internal.StringlyTyped
60 Database.V1.Bloodhound.Internal.StringlyTyped
63− -- Database.V1.Bloodhound.Internal.Suggest
61+ Database.V1.Bloodhound.Internal.Suggest
62+
64 other-modules: Bloodhound.Import
63 other-modules: Bloodhound.Import
65 Database.Bloodhound.Common.Script
64 Database.Bloodhound.Common.Script
66 hs-source-dirs: src
65 hs-source-dirs: src
@@ -103,7 +102,6 @@ test-suite bloodhound-tests
103 Test.Indices
102 Test.Indices
104 Test.JSON
103 Test.JSON
105 Test.Query
104 Test.Query
106− Test.Script
107 Test.Snapshots
105 Test.Snapshots
108 Test.Sorting
106 Test.Sorting
109 Test.SourceFiltering
107 Test.SourceFiltering
src/Bloodhound/Import.hs+5
@@ -8,6 +8,7 @@ module Bloodhound.Import
8 , readMay
8 , readMay
9 , showText
9 , showText
10 , deleteSeveral
10 , deleteSeveral
11+ , oPath
11 ) where
12 ) where
12
13
13import Control.Applicative as X (Alternative (..), optional)
14import Control.Applicative as X (Alternative (..), optional)
@@ -74,3 +75,7 @@ parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
74
75
75deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
76deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
76deleteSeveral ks hm = foldr HM.delete hm ks
77deleteSeveral ks hm = foldr HM.delete hm ks
78+
79+oPath :: ToJSON a => NonEmpty Text -> a -> Value
80+oPath (k :| []) v = object [k .= v]
81+oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
src/Database/V1/Bloodhound/Internal/Aggregation.hs+196−6
@@ -1,14 +1,16 @@
1+{-# LANGUAGE OverloadedStrings #-}
1−{-# LANGUAGE RecordWildCards #-}
2+{-# LANGUAGE RecordWildCards #-}
2
3
3module Database.V1.Bloodhound.Internal.Aggregation where
4module Database.V1.Bloodhound.Internal.Aggregation where
4
5
5import Bloodhound.Import
6import Bloodhound.Import
6
7
7−import qualified Data.HashMap.Strict as HM
8+import qualified Data.HashMap.Strict as HM
8−import qualified Data.Map.Strict as M
9+import qualified Data.Map.Strict as M
9−import Data.Text
10−import qualified Data.Text as T
10+import qualified Data.Text as T
11
11
12+import Database.V1.Bloodhound.Internal.Client
13+import Database.V1.Bloodhound.Internal.Highlight (HitHighlight)
12import Database.V1.Bloodhound.Internal.Newtypes
14import Database.V1.Bloodhound.Internal.Newtypes
13import Database.V1.Bloodhound.Internal.Query
15import Database.V1.Bloodhound.Internal.Query
14import Database.V1.Bloodhound.Internal.Sort
16import Database.V1.Bloodhound.Internal.Sort
@@ -88,7 +90,7 @@ data TopHitsAggregation = TopHitsAggregation
88 { taFrom :: Maybe From
90 { taFrom :: Maybe From
89 , taSize :: Maybe Size
91 , taSize :: Maybe Size
90 , taSort :: Maybe Sort
92 , taSort :: Maybe Sort
91− } deriving (Eq, Read, Show)
93+ } deriving (Eq, Show)
92
94
93data MissingAggregation = MissingAggregation
95data MissingAggregation = MissingAggregation
94 { maField :: Text
96 { maField :: Text
@@ -224,3 +226,191 @@ data DateMathUnit =
224 | DMMinute
226 | DMMinute
225 | DMSecond
227 | DMSecond
226 deriving (Eq, Show)
228 deriving (Eq, Show)
229+
230+data CollectionMode = BreadthFirst
231+ | DepthFirst deriving (Eq, Show)
232+
233+type AggregationResults = M.Map Text Value
234+
235+class BucketAggregation a where
236+ key :: a -> BucketValue
237+ docCount :: a -> Int
238+ aggs :: a -> Maybe AggregationResults
239+
240+data BucketValue = TextValue Text
241+ | ScientificValue Scientific
242+ | BoolValue Bool deriving (Show)
243+
244+data Bucket a = Bucket { buckets :: [a]} deriving (Show)
245+
246+data TermsResult = TermsResult { termKey :: BucketValue
247+ , termsDocCount :: Int
248+ , termsAggs :: Maybe AggregationResults } deriving (Show)
249+
250+data DateHistogramResult = DateHistogramResult { dateKey :: Int
251+ , dateKeyStr :: Maybe Text
252+ , dateDocCount :: Int
253+ , dateHistogramAggs :: Maybe AggregationResults } deriving (Show)
254+
255+data DateRangeResult = DateRangeResult { dateRangeKey :: Text
256+ , dateRangeFrom :: Maybe UTCTime
257+ , dateRangeFromAsString :: Maybe Text
258+ , dateRangeTo :: Maybe UTCTime
259+ , dateRangeToAsString :: Maybe Text
260+ , dateRangeDocCount :: Int
261+ , dateRangeAggs :: Maybe AggregationResults } deriving (Show, Eq)
262+
263+toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
264+toTerms = toAggResult
265+
266+toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
267+toDateHistogram = toAggResult
268+
269+toMissing :: Text -> AggregationResults -> Maybe MissingResult
270+toMissing = toAggResult
271+
272+toTopHits :: (FromJSON a) => Text -> AggregationResults -> Maybe (TopHitResult a)
273+toTopHits = toAggResult
274+
275+toAggResult :: (FromJSON a) => Text -> AggregationResults -> Maybe a
276+toAggResult t a = M.lookup t a >>= deserialize
277+ where deserialize = parseMaybe parseJSON
278+
279+instance BucketAggregation TermsResult where
280+ key = termKey
281+ docCount = termsDocCount
282+ aggs = termsAggs
283+
284+instance BucketAggregation DateHistogramResult where
285+ key = TextValue . showText . dateKey
286+ docCount = dateDocCount
287+ aggs = dateHistogramAggs
288+
289+instance BucketAggregation DateRangeResult where
290+ key = TextValue . dateRangeKey
291+ docCount = dateRangeDocCount
292+ aggs = dateRangeAggs
293+
294+instance (FromJSON a) => FromJSON (Bucket a) where
295+ parseJSON (Object v) = Bucket <$>
296+ v .: "buckets"
297+ parseJSON _ = mempty
298+
299+instance FromJSON BucketValue where
300+ parseJSON (String t) = return $ TextValue t
301+ parseJSON (Number s) = return $ ScientificValue s
302+ parseJSON (Bool b) = return $ BoolValue b
303+ parseJSON _ = mempty
304+
305+instance FromJSON MissingResult where
306+ parseJSON = withObject "MissingResult" parse
307+ where parse v = MissingResult <$> v .: "doc_count"
308+
309+instance FromJSON TermsResult where
310+ parseJSON (Object v) = TermsResult <$>
311+ v .: "key" <*>
312+ v .: "doc_count" <*>
313+ (pure $ getNamedSubAgg v ["key", "doc_count"])
314+ parseJSON _ = mempty
315+
316+instance FromJSON DateHistogramResult where
317+ parseJSON (Object v) = DateHistogramResult <$>
318+ v .: "key" <*>
319+ v .:? "key_as_string" <*>
320+ v .: "doc_count" <*>
321+ (pure $ getNamedSubAgg v [ "key"
322+ , "doc_count"
323+ , "key_as_string"
324+ ]
325+ )
326+ parseJSON _ = mempty
327+
328+instance FromJSON DateRangeResult where
329+ parseJSON = withObject "DateRangeResult" parse
330+ where parse v = DateRangeResult <$>
331+ v .: "key" <*>
332+ (fmap posixMS <$> v .:? "from") <*>
333+ v .:? "from_as_string" <*>
334+ (fmap posixMS <$> v .:? "to") <*>
335+ v .:? "to_as_string" <*>
336+ v .: "doc_count" <*>
337+ (pure $ getNamedSubAgg v [ "key"
338+ , "from"
339+ , "from_as_string"
340+ , "to"
341+ , "to_as_string"
342+ , "doc_count"
343+ ]
344+ )
345+
346+instance (FromJSON a) => FromJSON (TopHitResult a) where
347+ parseJSON (Object v) = TopHitResult <$>
348+ v .: "hits"
349+ parseJSON _ = fail "Failure in FromJSON (TopHitResult a)"
350+
351+data MissingResult = MissingResult { missingDocCount :: Int } deriving (Show)
352+
353+data TopHitResult a = TopHitResult { tarHits :: (SearchHits a)
354+ } deriving Show
355+
356+data SearchHits a =
357+ SearchHits { hitsTotal :: Int
358+ , maxScore :: Score
359+ , hits :: [Hit a] } deriving (Eq, Show)
360+
361+instance Semigroup (SearchHits a) where
362+ (SearchHits ta ma ha) <> (SearchHits tb mb hb) = SearchHits (ta + tb) (max ma mb) (ha <> hb)
363+
364+instance Monoid (SearchHits a) where
365+ mempty = SearchHits 0 Nothing mempty
366+ mappend = (<>)
367+
368+data Hit a =
369+ Hit { hitIndex :: IndexName
370+ , hitType :: MappingName
371+ , hitDocId :: DocId
372+ , hitScore :: Score
373+ , hitSource :: Maybe a
374+ , hitHighlight :: Maybe HitHighlight } deriving (Eq, Show)
375+
376+-- Try to get an AggregationResults when we don't know the
377+-- field name. We filter out the known keys to try to minimize the noise.
378+getNamedSubAgg :: Object -> [Text] -> Maybe AggregationResults
379+getNamedSubAgg o knownKeys = maggRes
380+ where unknownKeys = HM.filterWithKey (\k _ -> k `notElem` knownKeys) o
381+ maggRes
382+ | HM.null unknownKeys = Nothing
383+ | otherwise = Just . M.fromList $ HM.toList unknownKeys
384+
385+instance ToJSON CollectionMode where
386+ toJSON BreadthFirst = "breadth_first"
387+ toJSON DepthFirst = "depth_first"
388+
389+instance ToJSON DateRangeAggregation where
390+ toJSON DateRangeAggregation {..} =
391+ omitNulls [ "field" .= draField
392+ , "format" .= draFormat
393+ , "ranges" .= toList draRanges
394+ ]
395+
396+instance (FromJSON a) => FromJSON (SearchHits a) where
397+ parseJSON (Object v) = SearchHits <$>
398+ v .: "total" <*>
399+ v .: "max_score" <*>
400+ v .: "hits"
401+ parseJSON _ = empty
402+
403+instance ToJSON DateRangeAggRange where
404+ toJSON (DateRangeFrom e) = object [ "from" .= e ]
405+ toJSON (DateRangeTo e) = object [ "to" .= e ]
406+ toJSON (DateRangeFromAndTo f t) = object [ "from" .= f, "to" .= t ]
407+
408+instance (FromJSON a) => FromJSON (Hit a) where
409+ parseJSON (Object v) = Hit <$>
410+ v .: "_index" <*>
411+ v .: "_type" <*>
412+ v .: "_id" <*>
413+ v .: "_score" <*>
414+ v .:? "_source" <*>
415+ v .:? "highlight"
416+ parseJSON _ = empty
src/Database/V1/Bloodhound/Internal/Client.hs+2018−31
@@ -2,20 +2,29 @@
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE RecordWildCards #-}
5{-# LANGUAGE UndecidableInstances #-}
6{-# LANGUAGE UndecidableInstances #-}
6
7
7module Database.V1.Bloodhound.Internal.Client where
8module Database.V1.Bloodhound.Internal.Client where
8
9
9import Bloodhound.Import
10import Bloodhound.Import
10
11
11−import Control.Applicative as A
12+import Control.Applicative as A
13+import qualified Data.HashMap.Strict as HM
12−import Data.Text (Text)
14+import Data.Text (Text)
13−import qualified Data.Version as Vers
15+import qualified Data.Text as T
16+import qualified Data.Traversable as DT
17+import qualified Data.Vector as V
18+import qualified Data.Version as Vers
19+import GHC.Enum
14import Network.HTTP.Client
20import Network.HTTP.Client
21+import qualified Text.ParserCombinators.ReadP as RP
15−import Text.Read (Read (..))
22+import Text.Read (Read (..))
16−import qualified Text.Read as TR
23+import qualified Text.Read as TR
17
24
18import Database.V1.Bloodhound.Internal.Newtypes
25import Database.V1.Bloodhound.Internal.Newtypes
26+import Database.V1.Bloodhound.Internal.Query
27+import Database.V1.Bloodhound.Internal.StringlyTyped
19
28
20
29
21{-| Common environment for Elasticsearch calls. Connections will be
30{-| Common environment for Elasticsearch calls. Connections will be
@@ -99,6 +108,22 @@ data Version = Version { number :: VersionNumber
99 , build_snapshot :: Bool
108 , build_snapshot :: Bool
100 , lucene_version :: VersionNumber } deriving (Eq, Show)
109 , lucene_version :: VersionNumber } deriving (Eq, Show)
101
110
111+instance ToJSON Version where
112+ toJSON Version {..} = object ["number" .= number
113+ ,"build_hash" .= build_hash
114+ ,"build_timestamp" .= build_timestamp
115+ ,"build_snapshot" .= build_snapshot
116+ ,"lucene_version" .= lucene_version]
117+
118+instance FromJSON Version where
119+ parseJSON = withObject "Version" parse
120+ where parse o = Version
121+ <$> o .: "number"
122+ <*> o .: "build_hash"
123+ <*> o .: "build_timestamp"
124+ <*> o .: "build_snapshot"
125+ <*> o .: "lucene_version"
126+
102-- | Traditional software versioning number
127-- | Traditional software versioning number
103newtype VersionNumber = VersionNumber { versionNumber :: Vers.Version
128newtype VersionNumber = VersionNumber { versionNumber :: Vers.Version
104 } deriving (Eq, Show, Ord)
129 } deriving (Eq, Show, Ord)
@@ -115,6 +140,15 @@ data Status = Status { ok :: Maybe Bool
115 , version :: Version
140 , version :: Version
116 , tagline :: Text } deriving (Eq, Show)
141 , tagline :: Text } deriving (Eq, Show)
117
142
143+instance FromJSON Status where
144+ parseJSON (Object v) = Status <$>
145+ v .:? "ok" <*>
146+ (v .:? "status" .!= 200) <*>
147+ v .: "name" <*>
148+ v .: "version" <*>
149+ v .: "tagline"
150+ parseJSON _ = empty
151+
118{-| 'IndexSettings' is used to configure the shards and replicas when you create
152{-| 'IndexSettings' is used to configure the shards and replicas when you create
119 an Elasticsearch Index.
153 an Elasticsearch Index.
120
154
@@ -244,7 +278,6 @@ megabytes n = kilobytes (1000 * n)
244kilobytes :: Int -> Bytes
278kilobytes :: Int -> Bytes
245kilobytes n = Bytes (1000 * n)
279kilobytes n = Bytes (1000 * n)
246
280
247−
248data Interval = Year
281data Interval = Year
249 | Quarter
282 | Quarter
250 | Month
283 | Month
@@ -252,31 +285,8 @@ data Interval = Year
252 | Day
285 | Day
253 | Hour
286 | Hour
254 | Minute
287 | Minute
255− | Second deriving (Eq, Show)
288+ | Second
256−
289+ | FractionalInterval Float TimeInterval deriving (Eq, Show)
257−instance ToJSON Interval where
258− toJSON Year = "year"
259− toJSON Quarter = "quarter"
260− toJSON Month = "month"
261− toJSON Week = "week"
262− toJSON Day = "day"
263− toJSON Hour = "hour"
264− toJSON Minute = "minute"
265− toJSON Second = "second"
266−
267−parseStringInterval :: (Monad m) => String -> m NominalDiffTime
268−parseStringInterval s = case span isNumber s of
269− ("", _) -> fail "Invalid interval"
270− (nS, unitS) -> case (readMay nS, readMay unitS) of
271− (Just n, Just unit) -> return (fromInteger (n * unitNDT unit))
272− (Nothing, _) -> fail "Invalid interval number"
273− (_, Nothing) -> fail "Invalid interval unit"
274− where
275− unitNDT Seconds = 1
276− unitNDT Minutes = 60
277− unitNDT Hours = 60 * 60
278− unitNDT Days = 24 * 60 * 60
279− unitNDT Weeks = 7 * 24 * 60 * 60
280
290
281data TimeInterval = Weeks
291data TimeInterval = Weeks
282 | Days
292 | Days
@@ -352,3 +362,1980 @@ data CompoundFormat = CompoundFileFormat Bool
352 | MergeSegmentVsTotalIndex Double
362 | MergeSegmentVsTotalIndex Double
353 -- ^ percentage between 0 and 1 where 0 is false, 1 is true
363 -- ^ percentage between 0 and 1 where 0 is false, 1 is true
354 deriving (Eq, Show)
364 deriving (Eq, Show)
365+
366+attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
367+attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
368+ | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
369+
370+parseAttrFilter :: Value -> Parser (NonEmpty NodeAttrFilter)
371+parseAttrFilter = withObject "NonEmpty NodeAttrFilter" parse
372+ where parse o = case HM.toList o of
373+ [] -> fail "Expected non-empty list of NodeAttrFilters"
374+ x:xs -> DT.mapM (uncurry parse') (x :| xs)
375+ parse' n = withText "Text" $ \t ->
376+ case T.splitOn "," t of
377+ fv:fvs -> return (NodeAttrFilter (NodeAttrName n) (fv :| fvs))
378+ [] -> fail "Expected non-empty list of filter values"
379+
380+newtype NominalDiffTimeJSON = NominalDiffTimeJSON { ndtJSON :: NominalDiffTime }
381+
382+data IndexSettingsSummary = IndexSettingsSummary { sSummaryIndexName :: IndexName
383+ , sSummaryFixedSettings :: IndexSettings
384+ , sSummaryUpdateable :: [UpdatableIndexSetting]}
385+ deriving (Eq, Show)
386+
387+parseSettings :: Object -> Parser [UpdatableIndexSetting]
388+parseSettings o = do
389+ o' <- o .: "index"
390+ -- slice the index object into singleton hashmaps and try to parse each
391+ parses <- forM (HM.toList o') $ \(k, v) -> do
392+ -- blocks are now nested into the "index" key, which is not how they're serialized
393+ let atRoot = Object (HM.singleton k v)
394+ let atIndex = Object (HM.singleton "index" atRoot)
395+ optional (parseJSON atRoot <|> parseJSON atIndex)
396+ return (catMaybes parses)
397+
398+{-| 'OpenCloseIndex' is a sum type for opening and closing indices.
399+
400+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html>
401+-}
402+data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Show)
403+
404+data FieldType = GeoPointType
405+ | GeoShapeType
406+ | FloatType
407+ | IntegerType
408+ | LongType
409+ | ShortType
410+ | ByteType deriving (Eq, Show)
411+
412+data FieldDefinition =
413+ FieldDefinition { fieldType :: FieldType } deriving (Eq, Show)
414+
415+{-| An 'IndexTemplate' defines a template that will automatically be
416+ applied to new indices created. The templates include both
417+ 'IndexSettings' and mappings, and a simple 'TemplatePattern' that
418+ controls if the template will be applied to the index created.
419+ Specify mappings as follows: @[toJSON TweetMapping, ...]@
420+
421+ https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
422+-}
423+data IndexTemplate =
424+ IndexTemplate { templatePattern :: TemplatePattern
425+ , templateSettings :: Maybe IndexSettings
426+ , templateMappings :: [Value]
427+ }
428+
429+data MappingField =
430+ MappingField { mappingFieldName :: FieldName
431+ , fieldDefinition :: FieldDefinition } deriving (Eq, Show)
432+
433+{-| Support for type reification of 'Mapping's is currently incomplete, for
434+ now the mapping API verbiage expects a 'ToJSON'able blob.
435+
436+ Indexes have mappings, mappings are schemas for the documents contained in the
437+ index. I'd recommend having only one mapping per index, always having a mapping,
438+ and keeping different kinds of documents separated if possible.
439+-}
440+data Mapping = Mapping { typeName :: TypeName
441+ , mappingFields :: [MappingField] } deriving (Eq, Show)
442+
443+{-| 'BulkOperation' is a sum type for expressing the four kinds of bulk
444+ operation index, create, delete, and update. 'BulkIndex' behaves like an
445+ "upsert", 'BulkCreate' will fail if a document already exists at the DocId.
446+
447+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk>
448+-}
449+data BulkOperation =
450+ BulkIndex IndexName MappingName DocId Value
451+ | BulkCreate IndexName MappingName DocId Value
452+ | BulkDelete IndexName MappingName DocId
453+ | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Show)
454+
455+{-| 'EsResult' describes the standard wrapper JSON document that you see in
456+ successful Elasticsearch lookups or lookups that couldn't find the document.
457+-}
458+data EsResult a = EsResult { _index :: Text
459+ , _type :: Text
460+ , _id :: Text
461+ , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Show)
462+
463+instance (FromJSON a) => FromJSON (EsResult a) where
464+ parseJSON jsonVal@(Object v) = do
465+ found <- v .:? "found" .!= False
466+ fr <- if found
467+ then parseJSON jsonVal
468+ else return Nothing
469+ EsResult <$> v .: "_index" <*>
470+ v .: "_type" <*>
471+ v .: "_id" <*>
472+ pure fr
473+ parseJSON _ = empty
474+
475+{-| 'EsResultFound' contains the document and its metadata inside of an
476+ 'EsResult' when the document was successfully found.
477+-}
478+data EsResultFound a = EsResultFound { _version :: DocVersion
479+ , _source :: a } deriving (Eq, Show)
480+
481+instance (FromJSON a) => FromJSON (EsResultFound a) where
482+ parseJSON (Object v) = EsResultFound <$>
483+ v .: "_version" <*>
484+ v .: "_source"
485+ parseJSON _ = empty
486+
487+{-| 'EsError' is the generic type that will be returned when there was a
488+ problem. If you can't parse the expected response, its a good idea to
489+ try parsing this.
490+-}
491+data EsError = EsError { errorStatus :: Int
492+ , errorMessage :: Text } deriving (Eq, Show)
493+
494+{-| 'EsProtocolException' will be thrown if Bloodhound cannot parse a response
495+returned by the ElasticSearch server. If you encounter this error, please
496+verify that your domain data types and FromJSON instances are working properly
497+(for example, the 'a' of '[Hit a]' in 'SearchResult.searchHits.hits'). If you're
498+sure that your mappings are correct, then this error may be an indication of an
499+incompatibility between Bloodhound and ElasticSearch. Please open a bug report
500+and be sure to include the exception body.
501+-}
502+data EsProtocolException = EsProtocolException { esProtoExBody :: LByteString }
503+ deriving (Eq, Show)
504+
505+instance Exception EsProtocolException
506+
507+data IndexAlias = IndexAlias { srcIndex :: IndexName
508+ , indexAlias :: IndexAliasName } deriving (Eq, Show)
509+
510+{-| 'DocVersion' is an integer version number for a document between 1
511+and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
512+-}
513+newtype DocVersion = DocVersion {
514+ docVersionNumber :: Int
515+ } deriving (Eq, Show, Ord, ToJSON)
516+
517+instance FromJSON DocVersion where
518+ parseJSON v = do
519+ i <- parseJSON v
520+ maybe (fail "DocVersion out of range") return $ mkDocVersion i
521+
522+-- | Smart constructor for in-range doc version
523+mkDocVersion :: Int -> Maybe DocVersion
524+mkDocVersion i
525+ | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
526+ Just $ DocVersion i
527+ | otherwise = Nothing
528+
529+data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
530+ | RemoveAlias IndexAlias deriving (Show, Eq)
531+
532+data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
533+ , aliasCreateFilter :: Maybe Filter}
534+ deriving (Show, Eq)
535+
536+data AliasRouting = AllAliasRouting RoutingValue
537+ | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
538+ deriving (Show, Eq)
539+
540+newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Show, Eq)
541+
542+newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Show, Eq, ToJSON, FromJSON)
543+
544+newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Show, Eq, ToJSON, FromJSON)
545+
546+newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Show, Eq)
547+
548+{-| 'IndexAliasSummary' is a summary of an index alias configured for a server. -}
549+data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
550+ , indexAliasSummaryCreate :: IndexAliasCreate} deriving (Show, Eq)
551+
552+{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
553+own version numbers instead of ones from ES.
554+-}
555+newtype ExternalDocVersion = ExternalDocVersion DocVersion
556+ deriving (Eq, Show, Ord, Bounded, Enum, ToJSON)
557+
558+{-| 'VersionControl' is specified when indexing documents as a
559+optimistic concurrency control.
560+-}
561+data VersionControl = NoVersionControl
562+ -- ^ Don't send a version. This is a pure overwrite.
563+ | InternalVersion DocVersion
564+ -- ^ Use the default ES versioning scheme. Only
565+ -- index the document if the version is the same
566+ -- as the one specified. Only applicable to
567+ -- updates, as you should be getting Version from
568+ -- a search result.
569+ | ExternalGT ExternalDocVersion
570+ -- ^ Use your own version numbering. Only index
571+ -- the document if the version is strictly higher
572+ -- OR the document doesn't exist. The given
573+ -- version will be used as the new version number
574+ -- for the stored document. N.B. All updates must
575+ -- increment this number, meaning there is some
576+ -- global, external ordering of updates.
577+ | ExternalGTE ExternalDocVersion
578+ -- ^ Use your own version numbering. Only index
579+ -- the document if the version is equal or higher
580+ -- than the stored version. Will succeed if there
581+ -- is no existing document. The given version will
582+ -- be used as the new version number for the
583+ -- stored document. Use with care, as this could
584+ -- result in data loss.
585+ | ForceVersion ExternalDocVersion
586+ -- ^ The document will always be indexed and the
587+ -- given version will be the new version. This is
588+ -- typically used for correcting errors. Use with
589+ -- care, as this could result in data loss.
590+ deriving (Show, Eq, Ord)
591+
592+{-| 'DocumentParent' is used to specify a parent document.
593+-}
594+newtype DocumentParent = DocumentParent DocId
595+ deriving (Eq, Show)
596+
597+{-| 'IndexDocumentSettings' are special settings supplied when indexing
598+a document. For the best backwards compatiblity when new fields are
599+added, you should probably prefer to start with 'defaultIndexDocumentSettings'
600+-}
601+data IndexDocumentSettings =
602+ IndexDocumentSettings { idsVersionControl :: VersionControl
603+ , idsParent :: Maybe DocumentParent
604+ } deriving (Eq, Show)
605+
606+{-| Reasonable default settings. Chooses no version control and no parent.
607+-}
608+defaultIndexDocumentSettings :: IndexDocumentSettings
609+defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl Nothing
610+
611+{-| 'IndexSelection' is used for APIs which take a single index, a list of
612+ indexes, or the special @_all@ index.
613+-}
614+--TODO: this does not fully support <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/multi-index.html multi-index syntax>. It wouldn't be too hard to implement but you'd have to add the optional parameters (ignore_unavailable, allow_no_indices, expand_wildcards) to any APIs using it. Also would be a breaking API.
615+data IndexSelection = IndexList (NonEmpty IndexName)
616+ | AllIndexes deriving (Eq, Show)
617+
618+{-| 'NodeSelection' is used for most cluster APIs. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes here> for more details.
619+-}
620+data NodeSelection = LocalNode
621+ -- ^ Whatever node receives this request
622+ | NodeList (NonEmpty NodeSelector)
623+ | AllNodes deriving (Eq, Show)
624+
625+
626+-- | An exact match or pattern to identify a node. Note that All of
627+-- these options support wildcarding, so your node name, server, attr
628+-- name can all contain * characters to be a fuzzy match.
629+data NodeSelector = NodeByName NodeName
630+ | NodeByFullNodeId FullNodeId
631+ | NodeByHost Server
632+ -- ^ e.g. 10.0.0.1 or even 10.0.0.*
633+ | NodeByAttribute NodeAttrName Text
634+ -- ^ NodeAttrName can be a pattern, e.g. rack*. The value can too.
635+ deriving (Eq, Show)
636+
637+-- | A human-readable node name that is supplied by the user in the
638+-- node config or automatically generated by ElasticSearch.
639+newtype NodeName = NodeName { nodeName :: Text }
640+ deriving (Eq, Ord, Show, FromJSON)
641+
642+-- | Unique, automatically-generated name assigned to nodes that are
643+-- usually returned in node-oriented APIs.
644+newtype FullNodeId = FullNodeId { fullNodeId :: Text }
645+ deriving (Eq, Ord, Show, FromJSON)
646+
647+-- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
648+newtype EsUsername = EsUsername { esUsername :: Text } deriving (Show, Eq)
649+
650+-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
651+newtype EsPassword = EsPassword { esPassword :: Text } deriving (Show, Eq)
652+
653+data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
654+ | AllSnapshotRepos deriving (Eq, Show)
655+
656+
657+-- | Either specifies an exact repo name or one with globs in it,
658+-- e.g. @RepoPattern "foo*"@ __NOTE__: Patterns are not supported on ES < 1.7
659+data SnapshotRepoPattern = ExactRepo SnapshotRepoName
660+ | RepoPattern Text
661+ deriving (Eq, Show)
662+
663+-- | The unique name of a snapshot repository.
664+newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
665+ deriving (Eq, Ord, Show, ToJSON, FromJSON)
666+
667+
668+-- | A generic representation of a snapshot repo. This is what gets
669+-- sent to and parsed from the server. For repo types enabled by
670+-- plugins that aren't exported by this library, consider making a
671+-- custom type which implements 'SnapshotRepo'. If it is a common repo
672+-- type, consider submitting a pull request to have it included in the
673+-- library proper
674+data GenericSnapshotRepo = GenericSnapshotRepo {
675+ gSnapshotRepoName :: SnapshotRepoName
676+ , gSnapshotRepoType :: SnapshotRepoType
677+ , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
678+ } deriving (Eq, Show)
679+
680+-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
681+class SnapshotRepo r where
682+ toGSnapshotRepo :: r -> GenericSnapshotRepo
683+ fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
684+
685+data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType SnapshotRepoType
686+ -- ^ Expected type and actual type
687+ | OtherRepoConversionError Text
688+ deriving (Show, Eq)
689+
690+instance SnapshotRepo GenericSnapshotRepo where
691+ toGSnapshotRepo = id
692+ fromGSnapshotRepo = Right
693+
694+
695+newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
696+ deriving (Eq, Ord, Show, ToJSON, FromJSON)
697+
698+
699+-- | Opaque representation of snapshot repo settings. Instances of
700+-- 'SnapshotRepo' will produce this.
701+newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
702+ deriving (Eq, Show, ToJSON)
703+
704+
705+ -- Regardless of whether you send strongly typed json, my version of
706+ -- ES sends back stringly typed json in the settings, e.g. booleans
707+ -- as strings, so we'll try to convert them.
708+instance FromJSON GenericSnapshotRepoSettings where
709+ parseJSON = fmap (GenericSnapshotRepoSettings . fmap unStringlyTypeJSON). parseJSON
710+
711+-- | The result of running 'verifySnapshotRepo'.
712+newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
713+ deriving (Eq, Show)
714+
715+
716+instance FromJSON SnapshotVerification where
717+ parseJSON = withObject "SnapshotVerification" parse
718+ where
719+ parse o = do
720+ o2 <- o .: "nodes"
721+ SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
722+ parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
723+ SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
724+
725+
726+-- | A node that has verified a snapshot
727+data SnapshotNodeVerification = SnapshotNodeVerification {
728+ snvFullId :: FullNodeId
729+ , snvNodeName :: NodeName
730+ } deriving (Eq, Show)
731+
732+newtype ClusterName = ClusterName { clusterName :: Text }
733+ deriving (Eq, Ord, Show, FromJSON)
734+
735+data NodesInfo = NodesInfo {
736+ nodesInfo :: [NodeInfo]
737+ , nodesClusterName :: ClusterName
738+ } deriving (Eq, Show)
739+
740+instance FromJSON NodesInfo where
741+ parseJSON = withObject "NodesInfo" parse
742+ where
743+ parse o = do
744+ nodes <- o .: "nodes"
745+ infos <- forM (HM.toList nodes) $ \(fullNID, v) -> do
746+ node <- parseJSON v
747+ parseNodeInfo (FullNodeId fullNID) node
748+ cn <- o .: "cluster_name"
749+ return (NodesInfo infos cn)
750+
751+data NodesStats = NodesStats {
752+ nodesStats :: [NodeStats]
753+ , nodesStatsClusterName :: ClusterName
754+ } deriving (Eq, Show)
755+
756+data NodeStats = NodeStats {
757+ nodeStatsName :: NodeName
758+ , nodeStatsFullId :: FullNodeId
759+ , nodeStatsBreakersStats :: Maybe NodeBreakersStats
760+ , nodeStatsHTTP :: NodeHTTPStats
761+ , nodeStatsTransport :: NodeTransportStats
762+ , nodeStatsFS :: NodeFSStats
763+ , nodeStatsNetwork :: NodeNetworkStats
764+ , nodeStatsThreadPool :: NodeThreadPoolsStats
765+ , nodeStatsJVM :: NodeJVMStats
766+ , nodeStatsProcess :: NodeProcessStats
767+ , nodeStatsOS :: NodeOSStats
768+ , nodeStatsIndices :: NodeIndicesStats
769+ } deriving (Eq, Show)
770+
771+data NodeBreakersStats = NodeBreakersStats {
772+ nodeStatsParentBreaker :: NodeBreakerStats
773+ , nodeStatsRequestBreaker :: NodeBreakerStats
774+ , nodeStatsFieldDataBreaker :: NodeBreakerStats
775+ } deriving (Eq, Show)
776+
777+data NodeBreakerStats = NodeBreakerStats {
778+ nodeBreakersTripped :: Int
779+ , nodeBreakersOverhead :: Double
780+ , nodeBreakersEstSize :: Bytes
781+ , nodeBreakersLimitSize :: Bytes
782+ } deriving (Eq, Show)
783+
784+data NodeHTTPStats = NodeHTTPStats {
785+ nodeHTTPTotalOpened :: Int
786+ , nodeHTTPCurrentOpen :: Int
787+ } deriving (Eq, Show)
788+
789+data NodeTransportStats = NodeTransportStats {
790+ nodeTransportTXSize :: Bytes
791+ , nodeTransportCount :: Int
792+ , nodeTransportRXSize :: Bytes
793+ , nodeTransportRXCount :: Int
794+ , nodeTransportServerOpen :: Int
795+ } deriving (Eq, Show)
796+
797+data NodeFSStats = NodeFSStats {
798+ nodeFSDataPaths :: [NodeDataPathStats]
799+ , nodeFSTotal :: NodeFSTotalStats
800+ , nodeFSTimestamp :: UTCTime
801+ } deriving (Eq, Show)
802+
803+data NodeDataPathStats = NodeDataPathStats {
804+ nodeDataPathDiskServiceTime :: Maybe Double
805+ , nodeDataPathDiskQueue :: Maybe Double
806+ , nodeDataPathIOSize :: Maybe Bytes
807+ , nodeDataPathWriteSize :: Maybe Bytes
808+ , nodeDataPathReadSize :: Maybe Bytes
809+ , nodeDataPathIOOps :: Maybe Int
810+ , nodeDataPathWrites :: Maybe Int
811+ , nodeDataPathReads :: Maybe Int
812+ , nodeDataPathAvailable :: Bytes
813+ , nodeDataPathFree :: Bytes
814+ , nodeDataPathTotal :: Bytes
815+ , nodeDataPathType :: Maybe Text
816+ , nodeDataPathDevice :: Text
817+ , nodeDataPathMount :: Text
818+ , nodeDataPathPath :: Text
819+ } deriving (Eq, Show)
820+
821+data NodeFSTotalStats = NodeFSTotalStats {
822+ nodeFSTotalDiskServiceTime :: Maybe Double
823+ , nodeFSTotalDiskQueue :: Maybe Double
824+ , nodeFSTotalIOSize :: Maybe Bytes
825+ , nodeFSTotalWriteSize :: Maybe Bytes
826+ , nodeFSTotalReadSize :: Maybe Bytes
827+ , nodeFSTotalIOOps :: Maybe Int
828+ , nodeFSTotalWrites :: Maybe Int
829+ , nodeFSTotalReads :: Maybe Int
830+ , nodeFSTotalAvailable :: Bytes
831+ , nodeFSTotalFree :: Bytes
832+ , nodeFSTotalTotal :: Bytes
833+ } deriving (Eq, Show)
834+
835+data NodeNetworkStats = NodeNetworkStats {
836+ nodeNetTCPOutRSTs :: Int
837+ , nodeNetTCPInErrs :: Int
838+ , nodeNetTCPAttemptFails :: Int
839+ , nodeNetTCPEstabResets :: Int
840+ , nodeNetTCPRetransSegs :: Int
841+ , nodeNetTCPOutSegs :: Int
842+ , nodeNetTCPInSegs :: Int
843+ , nodeNetTCPCurrEstab :: Int
844+ , nodeNetTCPPassiveOpens :: Int
845+ , nodeNetTCPActiveOpens :: Int
846+ } deriving (Eq, Show)
847+
848+data NodeThreadPoolsStats = NodeThreadPoolsStats {
849+ nodeThreadPoolsStatsSnapshot :: NodeThreadPoolStats
850+ , nodeThreadPoolsStatsBulk :: NodeThreadPoolStats
851+ , nodeThreadPoolsStatsMerge :: NodeThreadPoolStats
852+ , nodeThreadPoolsStatsGet :: NodeThreadPoolStats
853+ , nodeThreadPoolsStatsManagement :: NodeThreadPoolStats
854+ , nodeThreadPoolsStatsFetchShardStore :: Maybe NodeThreadPoolStats
855+ , nodeThreadPoolsStatsOptimize :: NodeThreadPoolStats
856+ , nodeThreadPoolsStatsFlush :: NodeThreadPoolStats
857+ , nodeThreadPoolsStatsSearch :: NodeThreadPoolStats
858+ , nodeThreadPoolsStatsWarmer :: NodeThreadPoolStats
859+ , nodeThreadPoolsStatsGeneric :: NodeThreadPoolStats
860+ , nodeThreadPoolsStatsSuggest :: NodeThreadPoolStats
861+ , nodeThreadPoolsStatsRefresh :: NodeThreadPoolStats
862+ , nodeThreadPoolsStatsIndex :: NodeThreadPoolStats
863+ , nodeThreadPoolsStatsListener :: Maybe NodeThreadPoolStats
864+ , nodeThreadPoolsStatsFetchShardStarted :: Maybe NodeThreadPoolStats
865+ , nodeThreadPoolsStatsPercolate :: NodeThreadPoolStats
866+ } deriving (Eq, Show)
867+
868+data NodeThreadPoolStats = NodeThreadPoolStats {
869+ nodeThreadPoolCompleted :: Int
870+ , nodeThreadPoolLargest :: Int
871+ , nodeThreadPoolRejected :: Int
872+ , nodeThreadPoolActive :: Int
873+ , nodeThreadPoolQueue :: Int
874+ , nodeThreadPoolThreads :: Int
875+ } deriving (Eq, Show)
876+
877+data NodeJVMStats = NodeJVMStats {
878+ nodeJVMStatsMappedBufferPool :: JVMBufferPoolStats
879+ , nodeJVMStatsDirectBufferPool :: JVMBufferPoolStats
880+ , nodeJVMStatsGCOldCollector :: JVMGCStats
881+ , nodeJVMStatsGCYoungCollector :: JVMGCStats
882+ , nodeJVMStatsPeakThreadsCount :: Int
883+ , nodeJVMStatsThreadsCount :: Int
884+ , nodeJVMStatsOldPool :: JVMPoolStats
885+ , nodeJVMStatsSurvivorPool :: JVMPoolStats
886+ , nodeJVMStatsYoungPool :: JVMPoolStats
887+ , nodeJVMStatsNonHeapCommitted :: Bytes
888+ , nodeJVMStatsNonHeapUsed :: Bytes
889+ , nodeJVMStatsHeapMax :: Bytes
890+ , nodeJVMStatsHeapCommitted :: Bytes
891+ , nodeJVMStatsHeapUsedPercent :: Int
892+ , nodeJVMStatsHeapUsed :: Bytes
893+ , nodeJVMStatsUptime :: NominalDiffTime
894+ , nodeJVMStatsTimestamp :: UTCTime
895+ } deriving (Eq, Show)
896+
897+data JVMBufferPoolStats = JVMBufferPoolStats {
898+ jvmBufferPoolStatsTotalCapacity :: Bytes
899+ , jvmBufferPoolStatsUsed :: Bytes
900+ , jvmBufferPoolStatsCount :: Int
901+ } deriving (Eq, Show)
902+
903+data JVMGCStats = JVMGCStats {
904+ jvmGCStatsCollectionTime :: NominalDiffTime
905+ , jvmGCStatsCollectionCount :: Int
906+ } deriving (Eq, Show)
907+
908+data JVMPoolStats = JVMPoolStats {
909+ jvmPoolStatsPeakMax :: Bytes
910+ , jvmPoolStatsPeakUsed :: Bytes
911+ , jvmPoolStatsMax :: Bytes
912+ , jvmPoolStatsUsed :: Bytes
913+ } deriving (Eq, Show)
914+
915+data NodeProcessStats = NodeProcessStats {
916+ nodeProcessMemTotalVirtual :: Bytes
917+ , nodeProcessMemShare :: Bytes
918+ , nodeProcessMemResident :: Bytes
919+ , nodeProcessCPUTotal :: NominalDiffTime
920+ , nodeProcessCPUUser :: NominalDiffTime
921+ , nodeProcessCPUSys :: NominalDiffTime
922+ , nodeProcessCPUPercent :: Int
923+ , nodeProcessOpenFDs :: Int
924+ , nodeProcessTimestamp :: UTCTime
925+ } deriving (Eq, Show)
926+
927+data NodeOSStats = NodeOSStats {
928+ nodeOSSwapFree :: Bytes
929+ , nodeOSSwapUsed :: Bytes
930+ , nodeOSMemActualUsed :: Bytes
931+ , nodeOSMemActualFree :: Bytes
932+ , nodeOSMemUsedPercent :: Int
933+ , nodeOSMemFreePercent :: Int
934+ , nodeOSMemUsed :: Bytes
935+ , nodeOSMemFree :: Bytes
936+ , nodeOSCPUStolen :: Int
937+ , nodeOSCPUUsage :: Int
938+ , nodeOSCPUIdle :: Int
939+ , nodeOSCPUUser :: Int
940+ , nodeOSCPUSys :: Int
941+ , nodeOSLoad :: Maybe LoadAvgs
942+ , nodeOSUptime :: NominalDiffTime
943+ , nodeOSTimestamp :: UTCTime
944+ } deriving (Eq, Show)
945+
946+data LoadAvgs = LoadAvgs {
947+ loadAvg1Min :: Double
948+ , loadAvg5Min :: Double
949+ , loadAvg15Min :: Double
950+ } deriving (Eq, Show)
951+
952+data NodeIndicesStats = NodeIndicesStats {
953+ nodeIndicesStatsRecoveryThrottleTime :: Maybe NominalDiffTime
954+ , nodeIndicesStatsRecoveryCurrentAsTarget :: Maybe Int
955+ , nodeIndicesStatsRecoveryCurrentAsSource :: Maybe Int
956+ , nodeIndicesStatsQueryCacheMisses :: Maybe Int
957+ , nodeIndicesStatsQueryCacheHits :: Maybe Int
958+ , nodeIndicesStatsQueryCacheEvictions :: Maybe Int
959+ , nodeIndicesStatsQueryCacheSize :: Maybe Bytes
960+ , nodeIndicesStatsSuggestCurrent :: Int
961+ , nodeIndicesStatsSuggestTime :: NominalDiffTime
962+ , nodeIndicesStatsSuggestTotal :: Int
963+ , nodeIndicesStatsTranslogSize :: Bytes
964+ , nodeIndicesStatsTranslogOps :: Int
965+ , nodeIndicesStatsSegFixedBitSetMemory :: Maybe Bytes
966+ , nodeIndicesStatsSegVersionMapMemory :: Bytes
967+ , nodeIndicesStatsSegIndexWriterMaxMemory :: Maybe Bytes
968+ , nodeIndicesStatsSegIndexWriterMemory :: Bytes
969+ , nodeIndicesStatsSegMemory :: Bytes
970+ , nodeIndicesStatsSegCount :: Int
971+ , nodeIndicesStatsCompletionSize :: Bytes
972+ , nodeIndicesStatsPercolateQueries :: Int
973+ , nodeIndicesStatsPercolateMemory :: Bytes
974+ , nodeIndicesStatsPercolateCurrent :: Int
975+ , nodeIndicesStatsPercolateTime :: NominalDiffTime
976+ , nodeIndicesStatsPercolateTotal :: Int
977+ , nodeIndicesStatsFieldDataEvictions :: Int
978+ , nodeIndicesStatsFieldDataMemory :: Bytes
979+ , nodeIndicesStatsIDCacheMemory :: Bytes
980+ , nodeIndicesStatsFilterCacheEvictions :: Int
981+ , nodeIndicesStatsFilterCacheMemory :: Bytes
982+ , nodeIndicesStatsWarmerTotalTime :: NominalDiffTime
983+ , nodeIndicesStatsWarmerTotal :: Int
984+ , nodeIndicesStatsWarmerCurrent :: Int
985+ , nodeIndicesStatsFlushTotalTime :: NominalDiffTime
986+ , nodeIndicesStatsFlushTotal :: Int
987+ , nodeIndicesStatsRefreshTotalTime :: NominalDiffTime
988+ , nodeIndicesStatsRefreshTotal :: Int
989+ , nodeIndicesStatsMergesTotalSize :: Bytes
990+ , nodeIndicesStatsMergesTotalDocs :: Int
991+ , nodeIndicesStatsMergesTotalTime :: NominalDiffTime
992+ , nodeIndicesStatsMergesTotal :: Int
993+ , nodeIndicesStatsMergesCurrentSize :: Bytes
994+ , nodeIndicesStatsMergesCurrentDocs :: Int
995+ , nodeIndicesStatsMergesCurrent :: Int
996+ , nodeIndicesStatsSearchFetchCurrent :: Int
997+ , nodeIndicesStatsSearchFetchTime :: NominalDiffTime
998+ , nodeIndicesStatsSearchFetchTotal :: Int
999+ , nodeIndicesStatsSearchQueryCurrent :: Int
1000+ , nodeIndicesStatsSearchQueryTime :: NominalDiffTime
1001+ , nodeIndicesStatsSearchQueryTotal :: Int
1002+ , nodeIndicesStatsSearchOpenContexts :: Int
1003+ , nodeIndicesStatsGetCurrent :: Int
1004+ , nodeIndicesStatsGetMissingTime :: NominalDiffTime
1005+ , nodeIndicesStatsGetMissingTotal :: Int
1006+ , nodeIndicesStatsGetExistsTime :: NominalDiffTime
1007+ , nodeIndicesStatsGetExistsTotal :: Int
1008+ , nodeIndicesStatsGetTime :: NominalDiffTime
1009+ , nodeIndicesStatsGetTotal :: Int
1010+ , nodeIndicesStatsIndexingThrottleTime :: Maybe NominalDiffTime
1011+ , nodeIndicesStatsIndexingIsThrottled :: Maybe Bool
1012+ , nodeIndicesStatsIndexingNoopUpdateTotal :: Maybe Int
1013+ , nodeIndicesStatsIndexingDeleteCurrent :: Int
1014+ , nodeIndicesStatsIndexingDeleteTime :: NominalDiffTime
1015+ , nodeIndicesStatsIndexingDeleteTotal :: Int
1016+ , nodeIndicesStatsIndexingIndexCurrent :: Int
1017+ , nodeIndicesStatsIndexingIndexTime :: NominalDiffTime
1018+ , nodeIndicesStatsIndexingTotal :: Int
1019+ , nodeIndicesStatsStoreThrottleTime :: NominalDiffTime
1020+ , nodeIndicesStatsStoreSize :: Bytes
1021+ , nodeIndicesStatsDocsDeleted :: Int
1022+ , nodeIndicesStatsDocsCount :: Int
1023+ } deriving (Eq, Show)
1024+
1025+data NodeInfo = NodeInfo {
1026+ nodeInfoHTTPAddress :: EsAddress
1027+ , nodeInfoBuild :: BuildHash
1028+ , nodeInfoESVersion :: VersionNumber
1029+ , nodeInfoIP :: Server
1030+ , nodeInfoHost :: Server
1031+ , nodeInfoTransportAddress :: EsAddress
1032+ , nodeInfoName :: NodeName
1033+ , nodeInfoFullId :: FullNodeId
1034+ , nodeInfoPlugins :: [NodePluginInfo]
1035+ , nodeInfoHTTP :: NodeHTTPInfo
1036+ , nodeInfoTransport :: NodeTransportInfo
1037+ , nodeInfoNetwork :: NodeNetworkInfo
1038+ , nodeInfoThreadPool :: NodeThreadPoolsInfo
1039+ , nodeInfoJVM :: NodeJVMInfo
1040+ , nodeInfoProcess :: NodeProcessInfo
1041+ , nodeInfoOS :: NodeOSInfo
1042+ , nodeInfoSettings :: Object
1043+ -- ^ The members of the settings objects are not consistent,
1044+ -- dependent on plugins, etc.
1045+ } deriving (Eq, Show)
1046+
1047+data NodePluginInfo = NodePluginInfo {
1048+ nodePluginSite :: Bool
1049+ -- ^ Is this a site plugin?
1050+ , nodePluginJVM :: Bool
1051+ -- ^ Is this plugin running on the JVM
1052+ , nodePluginDescription :: Text
1053+ , nodePluginVersion :: MaybeNA VersionNumber
1054+ , nodePluginName :: PluginName
1055+ } deriving (Eq, Show)
1056+
1057+data NodeHTTPInfo = NodeHTTPInfo {
1058+ nodeHTTPMaxContentLength :: Bytes
1059+ , nodeHTTPTransportAddress :: BoundTransportAddress
1060+ } deriving (Eq, Show)
1061+
1062+data NodeTransportInfo = NodeTransportInfo {
1063+ nodeTransportProfiles :: [BoundTransportAddress]
1064+ , nodeTransportAddress :: BoundTransportAddress
1065+ } deriving (Eq, Show)
1066+
1067+data BoundTransportAddress = BoundTransportAddress {
1068+ publishAddress :: EsAddress
1069+ , boundAddress :: EsAddress
1070+ } deriving (Eq, Show)
1071+
1072+data NodeNetworkInfo = NodeNetworkInfo {
1073+ nodeNetworkPrimaryInterface :: NodeNetworkInterface
1074+ , nodeNetworkRefreshInterval :: NominalDiffTime
1075+ } deriving (Eq, Show)
1076+
1077+newtype MacAddress = MacAddress { macAddress :: Text }
1078+ deriving (Eq, Ord, Show, FromJSON)
1079+
1080+newtype NetworkInterfaceName = NetworkInterfaceName { networkInterfaceName :: Text }
1081+ deriving (Eq, Ord, Show, FromJSON)
1082+
1083+data NodeNetworkInterface = NodeNetworkInterface {
1084+ nodeNetIfaceMacAddress :: MacAddress
1085+ , nodeNetIfaceName :: NetworkInterfaceName
1086+ , nodeNetIfaceAddress :: Server
1087+ } deriving (Eq, Show)
1088+
1089+data NodeThreadPoolsInfo = NodeThreadPoolsInfo {
1090+ nodeThreadPoolsRefresh :: NodeThreadPoolInfo
1091+ , nodeThreadPoolsManagement :: NodeThreadPoolInfo
1092+ , nodeThreadPoolsPercolate :: NodeThreadPoolInfo
1093+ , nodeThreadPoolsListener :: Maybe NodeThreadPoolInfo
1094+ , nodeThreadPoolsFetchShardStarted :: Maybe NodeThreadPoolInfo
1095+ , nodeThreadPoolsSearch :: NodeThreadPoolInfo
1096+ , nodeThreadPoolsFlush :: NodeThreadPoolInfo
1097+ , nodeThreadPoolsWarmer :: NodeThreadPoolInfo
1098+ , nodeThreadPoolsOptimize :: NodeThreadPoolInfo
1099+ , nodeThreadPoolsBulk :: NodeThreadPoolInfo
1100+ , nodeThreadPoolsSuggest :: NodeThreadPoolInfo
1101+ , nodeThreadPoolsMerge :: NodeThreadPoolInfo
1102+ , nodeThreadPoolsSnapshot :: NodeThreadPoolInfo
1103+ , nodeThreadPoolsGet :: NodeThreadPoolInfo
1104+ , nodeThreadPoolsFetchShardStore :: Maybe NodeThreadPoolInfo
1105+ , nodeThreadPoolsIndex :: NodeThreadPoolInfo
1106+ , nodeThreadPoolsGeneric :: NodeThreadPoolInfo
1107+ } deriving (Eq, Show)
1108+
1109+data NodeThreadPoolInfo = NodeThreadPoolInfo {
1110+ nodeThreadPoolQueueSize :: ThreadPoolSize
1111+ , nodeThreadPoolKeepalive :: Maybe NominalDiffTime
1112+ , nodeThreadPoolMin :: Maybe Int
1113+ , nodeThreadPoolMax :: Maybe Int
1114+ , nodeThreadPoolType :: ThreadPoolType
1115+ } deriving (Eq, Show)
1116+
1117+data ThreadPoolSize = ThreadPoolBounded Int
1118+ | ThreadPoolUnbounded
1119+ deriving (Eq, Show)
1120+
1121+data ThreadPoolType = ThreadPoolScaling
1122+ | ThreadPoolFixed
1123+ | ThreadPoolCached
1124+ deriving (Eq, Show)
1125+
1126+data NodeJVMInfo = NodeJVMInfo {
1127+ nodeJVMInfoMemoryPools :: [JVMMemoryPool]
1128+ , nodeJVMInfoMemoryPoolsGCCollectors :: [JVMGCCollector]
1129+ , nodeJVMInfoMemoryInfo :: JVMMemoryInfo
1130+ , nodeJVMInfoStartTime :: UTCTime
1131+ , nodeJVMInfoVMVendor :: Text
1132+ , nodeJVMVMVersion :: VersionNumber
1133+ -- ^ JVM doesn't seme to follow normal version conventions
1134+ , nodeJVMVMName :: Text
1135+ , nodeJVMVersion :: VersionNumber
1136+ , nodeJVMPID :: PID
1137+ } deriving (Eq, Show)
1138+
1139+-- | Handles quirks in the way JVM versions are rendered (1.7.0_101 -> 1.7.0.101)
1140+newtype JVMVersion = JVMVersion { unJVMVersion :: VersionNumber }
1141+
1142+data JVMMemoryInfo = JVMMemoryInfo {
1143+ jvmMemoryInfoDirectMax :: Bytes
1144+ , jvmMemoryInfoNonHeapMax :: Bytes
1145+ , jvmMemoryInfoNonHeapInit :: Bytes
1146+ , jvmMemoryInfoHeapMax :: Bytes
1147+ , jvmMemoryInfoHeapInit :: Bytes
1148+ } deriving (Eq, Show)
1149+
1150+newtype JVMMemoryPool = JVMMemoryPool {
1151+ jvmMemoryPool :: Text
1152+ } deriving (Eq, Show, FromJSON)
1153+
1154+newtype JVMGCCollector = JVMGCCollector {
1155+ jvmGCCollector :: Text
1156+ } deriving (Eq, Show, FromJSON)
1157+
1158+newtype PID = PID {
1159+ pid :: Int
1160+ } deriving (Eq, Show, FromJSON)
1161+
1162+data NodeOSInfo = NodeOSInfo {
1163+ nodeOSSwap :: Bytes
1164+ , nodeOSMem :: Bytes
1165+ , nodeOSCPUInfo :: CPUInfo
1166+ , nodeOSAvailableProcessors :: Int
1167+ , nodeOSRefreshInterval :: NominalDiffTime
1168+ } deriving (Eq, Show)
1169+
1170+data CPUInfo = CPUInfo {
1171+ cpuCacheSize :: Bytes
1172+ , cpuCoresPerSocket :: Int
1173+ , cpuTotalSockets :: Int
1174+ , cpuTotalCores :: Int
1175+ , cpuMHZ :: Int
1176+ , cpuModel :: Text
1177+ , cpuVendor :: Text
1178+ } deriving (Eq, Show)
1179+
1180+data NodeProcessInfo = NodeProcessInfo {
1181+ nodeProcessMLockAll :: Bool
1182+ -- ^ See <https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html>
1183+ , nodeProcessMaxFileDescriptors :: Int
1184+ , nodeProcessId :: PID
1185+ , nodeProcessRefreshInterval :: NominalDiffTime
1186+ } deriving (Eq, Show)
1187+
1188+-- | A quirky address format used throughout ElasticSearch. An example
1189+-- would be inet[/1.1.1.1:9200]. inet may be a placeholder for a
1190+-- <https://en.wikipedia.org/wiki/Fully_qualified_domain_name FQDN>.
1191+newtype EsAddress = EsAddress { esAddress :: Text }
1192+ deriving (Eq, Ord, Show, FromJSON)
1193+
1194+newtype PluginName = PluginName { pluginName :: Text }
1195+ deriving (Eq, Ord, Show, FromJSON)
1196+
1197+data ShardResult =
1198+ ShardResult { shardTotal :: Int
1199+ , shardsSuccessful :: Int
1200+ , shardsFailed :: Int } deriving (Eq, Show)
1201+
1202+data SnapshotState = SnapshotInit
1203+ | SnapshotStarted
1204+ | SnapshotSuccess
1205+ | SnapshotFailed
1206+ | SnapshotAborted
1207+ | SnapshotMissing
1208+ | SnapshotWaiting
1209+ deriving (Show, Eq)
1210+
1211+instance FromJSON SnapshotState where
1212+ parseJSON = withText "SnapshotState" parse
1213+ where
1214+ parse "INIT" = return SnapshotInit
1215+ parse "STARTED" = return SnapshotStarted
1216+ parse "SUCCESS" = return SnapshotSuccess
1217+ parse "FAILED" = return SnapshotFailed
1218+ parse "ABORTED" = return SnapshotAborted
1219+ parse "MISSING" = return SnapshotMissing
1220+ parse "WAITING" = return SnapshotWaiting
1221+ parse t = fail ("Invalid snapshot state " <> T.unpack t)
1222+
1223+data SnapshotRestoreSettings = SnapshotRestoreSettings {
1224+ snapRestoreWaitForCompletion :: Bool
1225+ -- ^ Should the API call return immediately after initializing
1226+ -- the restore or wait until completed? Note that if this is
1227+ -- enabled, it could wait a long time, so you should adjust your
1228+ -- 'ManagerSettings' accordingly to set long timeouts or
1229+ -- explicitly handle timeouts.
1230+ , snapRestoreIndices :: Maybe IndexSelection
1231+ -- ^ Nothing will restore all indices in the snapshot. Just [] is
1232+ -- permissable and will essentially be a no-op restore.
1233+ , snapRestoreIgnoreUnavailable :: Bool
1234+ -- ^ If set to True, any indices that do not exist will be ignored
1235+ -- during snapshot rather than failing the restore.
1236+ , snapRestoreIncludeGlobalState :: Bool
1237+ -- ^ If set to false, will ignore any global state in the snapshot
1238+ -- and will not restore it.
1239+ , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
1240+ -- ^ A regex pattern for matching indices. Used with
1241+ -- 'snapRestoreRenameReplacement', the restore can reference the
1242+ -- matched index and create a new index name upon restore.
1243+ , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
1244+ -- ^ Expression of how index renames should be constructed.
1245+ , snapRestorePartial :: Bool
1246+ -- ^ If some indices fail to restore, should the process proceed?
1247+ , snapRestoreIncludeAliases :: Bool
1248+ -- ^ Should the restore also restore the aliases captured in the
1249+ -- snapshot.
1250+ , snapRestoreIndexSettingsOverrides :: Maybe RestoreIndexSettings
1251+ -- ^ Settings to apply during the restore process. __NOTE:__ This
1252+ -- option is not supported in ES < 1.5 and should be set to
1253+ -- Nothing in that case.
1254+ , snapRestoreIgnoreIndexSettings :: Maybe (NonEmpty Text)
1255+ -- ^ This type could be more rich but it isn't clear which
1256+ -- settings are allowed to be ignored during restore, so we're
1257+ -- going with including this feature in a basic form rather than
1258+ -- omitting it. One example here would be
1259+ -- "index.refresh_interval". Any setting specified here will
1260+ -- revert back to the server default during the restore process.
1261+ } deriving (Eq, Show)
1262+
1263+-- | Regex-stype pattern, e.g. "index_(.+)" to match index names
1264+newtype RestoreRenamePattern = RestoreRenamePattern { rrPattern :: Text }
1265+ deriving (Show, Eq, Ord, ToJSON)
1266+
1267+
1268+-- | A single token in a index renaming scheme for a restore. These
1269+-- are concatenated into a string before being sent to
1270+-- ElasticSearch. Check out these Java
1271+-- <https://docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html docs> to find out more if you're into that sort of thing.
1272+data RestoreRenameToken = RRTLit Text
1273+ -- ^ Just a literal string of characters
1274+ | RRSubWholeMatch
1275+ -- ^ Equivalent to $0. The entire matched pattern, not any subgroup
1276+ | RRSubGroup RRGroupRefNum
1277+ -- ^ A specific reference to a group number
1278+ deriving (Show, Eq)
1279+
1280+
1281+-- | A group number for regex matching. Only values from 1-9 are
1282+-- supported. Construct with 'mkRRGroupRefNum'
1283+newtype RRGroupRefNum = RRGroupRefNum { rrGroupRefNum :: Int }
1284+ deriving (Show, Eq, Ord)
1285+
1286+instance Bounded RRGroupRefNum where
1287+ minBound = RRGroupRefNum 1
1288+ maxBound = RRGroupRefNum 9
1289+
1290+
1291+-- | Only allows valid group number references (1-9).
1292+mkRRGroupRefNum :: Int -> Maybe RRGroupRefNum
1293+mkRRGroupRefNum i
1294+ | i >= (rrGroupRefNum minBound) && i <= (rrGroupRefNum maxBound) =
1295+ Just $ RRGroupRefNum i
1296+ | otherwise = Nothing
1297+
1298+-- | Index settings that can be overridden. The docs only mention you
1299+-- can update number of replicas, but there may be more. You
1300+-- definitely cannot override shard count.
1301+data RestoreIndexSettings = RestoreIndexSettings {
1302+ restoreOverrideReplicas :: Maybe ReplicaCount
1303+ } deriving (Show, Eq)
1304+
1305+instance ToJSON RestoreIndexSettings where
1306+ toJSON RestoreIndexSettings {..} = object prs
1307+ where
1308+ prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]
1309+
1310+data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
1311+ repoUpdateVerify :: Bool
1312+ -- ^ After creation/update, synchronously check that nodes can
1313+ -- write to this repo. Defaults to True. You may use False if you
1314+ -- need a faster response and plan on verifying manually later
1315+ -- with 'verifySnapshotRepo'.
1316+ } deriving (Eq, Show)
1317+
1318+-- | Reasonable defaults for repo creation/update
1319+--
1320+-- * repoUpdateVerify True
1321+defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
1322+defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
1323+
1324+-- | A filesystem-based snapshot repo that ships with
1325+-- ElasticSearch. This is an instance of 'SnapshotRepo' so it can be
1326+-- used with 'updateSnapshotRepo'
1327+data FsSnapshotRepo = FsSnapshotRepo {
1328+ fsrName :: SnapshotRepoName
1329+ , fsrLocation :: FilePath
1330+ , fsrCompressMetadata :: Bool
1331+ , fsrChunkSize :: Maybe Bytes
1332+ -- ^ Size by which to split large files during snapshotting.
1333+ , fsrMaxRestoreBytesPerSec :: Maybe Bytes
1334+ -- ^ Throttle node restore rate. If not supplied, defaults to 40mb/sec
1335+ , fsrMaxSnapshotBytesPerSec :: Maybe Bytes
1336+ -- ^ Throttle node snapshot rate. If not supplied, defaults to 40mb/sec
1337+ } deriving (Eq, Show)
1338+
1339+instance SnapshotRepo FsSnapshotRepo where
1340+ toGSnapshotRepo FsSnapshotRepo {..} =
1341+ GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
1342+ where
1343+ Object settings = object $ [ "location" .= fsrLocation
1344+ , "compress" .= fsrCompressMetadata
1345+ ] ++ optionalPairs
1346+ optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
1347+ , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
1348+ , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
1349+ ]
1350+ fromGSnapshotRepo GenericSnapshotRepo {..}
1351+ | gSnapshotRepoType == fsRepoType = do
1352+ let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
1353+ parseRepo $ do
1354+ FsSnapshotRepo gSnapshotRepoName <$> o .: "location"
1355+ <*> o .:? "compress" .!= False
1356+ <*> o .:? "chunk_size"
1357+ <*> o .:? "max_restore_bytes_per_sec"
1358+ <*> o .:? "max_snapshot_bytes_per_sec"
1359+ | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
1360+
1361+data SnapshotCreateSettings = SnapshotCreateSettings {
1362+ snapWaitForCompletion :: Bool
1363+ -- ^ Should the API call return immediately after initializing
1364+ -- the snapshot or wait until completed? Note that if this is
1365+ -- enabled it could wait a long time, so you should adjust your
1366+ -- 'ManagerSettings' accordingly to set long timeouts or
1367+ -- explicitly handle timeouts.
1368+ , snapIndices :: Maybe IndexSelection
1369+ -- ^ Nothing will snapshot all indices. Just [] is permissable and
1370+ -- will essentially be a no-op snapshot.
1371+ , snapIgnoreUnavailable :: Bool
1372+ -- ^ If set to True, any matched indices that don't exist will be
1373+ -- ignored. Otherwise it will be an error and fail.
1374+ , snapIncludeGlobalState :: Bool
1375+ , snapPartial :: Bool
1376+ -- ^ If some indices failed to snapshot (e.g. if not all primary
1377+ -- shards are available), should the process proceed?
1378+ } deriving (Eq, Show)
1379+
1380+-- | Reasonable defaults for snapshot creation
1381+--
1382+-- * snapWaitForCompletion False
1383+-- * snapIndices Nothing
1384+-- * snapIgnoreUnavailable False
1385+-- * snapIncludeGlobalState True
1386+-- * snapPartial False
1387+defaultSnapshotCreateSettings :: SnapshotCreateSettings
1388+defaultSnapshotCreateSettings = SnapshotCreateSettings {
1389+ snapWaitForCompletion = False
1390+ , snapIndices = Nothing
1391+ , snapIgnoreUnavailable = False
1392+ , snapIncludeGlobalState = True
1393+ , snapPartial = False
1394+ }
1395+
1396+
1397+data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
1398+ | AllSnapshots deriving (Eq, Show)
1399+
1400+
1401+-- | Either specifies an exact snapshot name or one with globs in it,
1402+-- e.g. @SnapPattern "foo*"@ __NOTE__: Patterns are not supported on
1403+-- ES < 1.7
1404+data SnapshotPattern = ExactSnap SnapshotName
1405+ | SnapPattern Text
1406+ deriving (Eq, Show)
1407+
1408+
1409+-- | General information about the state of a snapshot. Has some
1410+-- redundancies with 'SnapshotStatus'
1411+data SnapshotInfo = SnapshotInfo {
1412+ snapInfoShards :: ShardResult
1413+ , snapInfoFailures :: [SnapshotShardFailure]
1414+ , snapInfoDuration :: NominalDiffTime
1415+ , snapInfoEndTime :: UTCTime
1416+ , snapInfoStartTime :: UTCTime
1417+ , snapInfoState :: SnapshotState
1418+ , snapInfoIndices :: [IndexName]
1419+ , snapInfoName :: SnapshotName
1420+ } deriving (Eq, Show)
1421+
1422+
1423+instance FromJSON SnapshotInfo where
1424+ parseJSON = withObject "SnapshotInfo" parse
1425+ where
1426+ parse o = SnapshotInfo <$> o .: "shards"
1427+ <*> o .: "failures"
1428+ <*> (unMS <$> o .: "duration_in_millis")
1429+ <*> (posixMS <$> o .: "end_time_in_millis")
1430+ <*> (posixMS <$> o .: "start_time_in_millis")
1431+ <*> o .: "state"
1432+ <*> o .: "indices"
1433+ <*> o .: "snapshot"
1434+
1435+data SnapshotShardFailure = SnapshotShardFailure {
1436+ snapShardFailureIndex :: IndexName
1437+ , snapShardFailureNodeId :: Maybe NodeName -- I'm not 100% sure this isn't actually 'FullNodeId'
1438+ , snapShardFailureReason :: Text
1439+ , snapShardFailureShardId :: ShardId
1440+ } deriving (Eq, Show)
1441+
1442+
1443+instance FromJSON SnapshotShardFailure where
1444+ parseJSON = withObject "SnapshotShardFailure" parse
1445+ where
1446+ parse o = SnapshotShardFailure <$> o .: "index"
1447+ <*> o .:? "node_id"
1448+ <*> o .: "reason"
1449+ <*> o .: "shard_id"
1450+
1451+parseRepo :: Parser a -> Either SnapshotRepoConversionError a
1452+parseRepo parser = case parseEither (const parser) () of
1453+ Left e -> Left (OtherRepoConversionError (T.pack e))
1454+ Right a -> Right a
1455+
1456+parseNodeStats :: FullNodeId -> Object -> Parser NodeStats
1457+parseNodeStats fnid o = do
1458+ NodeStats <$> o .: "name"
1459+ <*> pure fnid
1460+ <*> o .:? "breakers"
1461+ <*> o .: "http"
1462+ <*> o .: "transport"
1463+ <*> o .: "fs"
1464+ <*> o .: "network"
1465+ <*> o .: "thread_pool"
1466+ <*> o .: "jvm"
1467+ <*> o .: "process"
1468+ <*> o .: "os"
1469+ <*> o .: "indices"
1470+
1471+parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
1472+parseNodeInfo nid o =
1473+ NodeInfo <$> o .: "http_address"
1474+ <*> o .: "build"
1475+ <*> o .: "version"
1476+ <*> o .: "ip"
1477+ <*> o .: "host"
1478+ <*> o .: "transport_address"
1479+ <*> o .: "name"
1480+ <*> pure nid
1481+ <*> o .: "plugins"
1482+ <*> o .: "http"
1483+ <*> o .: "transport"
1484+ <*> o .: "network"
1485+ <*> o .: "thread_pool"
1486+ <*> o .: "jvm"
1487+ <*> o .: "process"
1488+ <*> o .: "os"
1489+ <*> o .: "settings"
1490+
1491+-- | Reasonable defaults for snapshot restores
1492+--
1493+-- * snapRestoreWaitForCompletion False
1494+-- * snapRestoreIndices Nothing
1495+-- * snapRestoreIgnoreUnavailable False
1496+-- * snapRestoreIncludeGlobalState True
1497+-- * snapRestoreRenamePattern Nothing
1498+-- * snapRestoreRenameReplacement Nothing
1499+-- * snapRestorePartial False
1500+-- * snapRestoreIncludeAliases True
1501+-- * snapRestoreIndexSettingsOverrides Nothing
1502+-- * snapRestoreIgnoreIndexSettings Nothing
1503+defaultSnapshotRestoreSettings :: SnapshotRestoreSettings
1504+defaultSnapshotRestoreSettings = SnapshotRestoreSettings {
1505+ snapRestoreWaitForCompletion = False
1506+ , snapRestoreIndices = Nothing
1507+ , snapRestoreIgnoreUnavailable = False
1508+ , snapRestoreIncludeGlobalState = True
1509+ , snapRestoreRenamePattern = Nothing
1510+ , snapRestoreRenameReplacement = Nothing
1511+ , snapRestorePartial = False
1512+ , snapRestoreIncludeAliases = True
1513+ , snapRestoreIndexSettingsOverrides = Nothing
1514+ , snapRestoreIgnoreIndexSettings = Nothing
1515+ }
1516+
1517+fsRepoType :: SnapshotRepoType
1518+fsRepoType = SnapshotRepoType "fs"
1519+
1520+{-| 'Reply' and 'Method' are type synonyms from 'Network.HTTP.Types.Method.Method' -}
1521+type Reply = Network.HTTP.Client.Response LByteString
1522+
1523+instance FromJSON IndexSettingsSummary where
1524+ parseJSON = withObject "IndexSettingsSummary" parse
1525+ where parse o = case HM.toList o of
1526+ [(ixn, v@(Object o'))] -> IndexSettingsSummary (IndexName ixn)
1527+ <$> parseJSON v
1528+ <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings")
1529+ _ -> fail "Expected single-key object with index name"
1530+ redundant (NumberOfReplicas _) = True
1531+ redundant _ = False
1532+
1533+instance ToJSON VersionNumber where
1534+ toJSON = toJSON . Vers.showVersion . versionNumber
1535+
1536+instance FromJSON VersionNumber where
1537+ parseJSON = withText "VersionNumber" (parse . T.unpack)
1538+ where
1539+ parse s = case filter (null . snd)(RP.readP_to_S Vers.parseVersion s) of
1540+ [(v, _)] -> pure (VersionNumber v)
1541+ [] -> fail ("Invalid version string " ++ s)
1542+ xs -> fail ("Ambiguous version string " ++ s ++ " (" ++ intercalate ", " (Vers.showVersion . fst <$> xs) ++ ")")
1543+
1544+instance ToJSON Interval where
1545+ toJSON Year = "year"
1546+ toJSON Quarter = "quarter"
1547+ toJSON Month = "month"
1548+ toJSON Week = "week"
1549+ toJSON Day = "day"
1550+ toJSON Hour = "hour"
1551+ toJSON Minute = "minute"
1552+ toJSON Second = "second"
1553+ toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1554+
1555+parseStringInterval :: (Monad m) => String -> m NominalDiffTime
1556+parseStringInterval s = case span isNumber s of
1557+ ("", _) -> fail "Invalid interval"
1558+ (nS, unitS) -> case (readMay nS, readMay unitS) of
1559+ (Just n, Just unit) -> return (fromInteger (n * unitNDT unit))
1560+ (Nothing, _) -> fail "Invalid interval number"
1561+ (_, Nothing) -> fail "Invalid interval unit"
1562+ where
1563+ unitNDT Seconds = 1
1564+ unitNDT Minutes = 60
1565+ unitNDT Hours = 60 * 60
1566+ unitNDT Days = 24 * 60 * 60
1567+ unitNDT Weeks = 7 * 24 * 60 * 60
1568+
1569+instance ToJSON IndexSettings where
1570+ toJSON (IndexSettings s r) = object ["settings" .=
1571+ object ["index" .=
1572+ object ["number_of_shards" .= s, "number_of_replicas" .= r]
1573+ ]
1574+ ]
1575+
1576+instance FromJSON IndexSettings where
1577+ parseJSON = withObject "IndexSettings" parse
1578+ where parse o = do s <- o .: "settings"
1579+ i <- s .: "index"
1580+ IndexSettings <$> i .: "number_of_shards"
1581+ <*> i .: "number_of_replicas"
1582+
1583+instance Bounded DocVersion where
1584+ minBound = DocVersion 1
1585+ maxBound = DocVersion 9200000000000000000 -- 9.2e+18
1586+
1587+instance Enum DocVersion where
1588+ succ x
1589+ | x /= maxBound = DocVersion (succ $ docVersionNumber x)
1590+ | otherwise = succError "DocVersion"
1591+ pred x
1592+ | x /= minBound = DocVersion (pred $ docVersionNumber x)
1593+ | otherwise = predError "DocVersion"
1594+ toEnum i =
1595+ fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
1596+ fromEnum = docVersionNumber
1597+ enumFrom = boundedEnumFrom
1598+ enumFromThen = boundedEnumFromThen
1599+
1600+instance FromJSON ShardResult where
1601+ parseJSON (Object v) = ShardResult <$>
1602+ v .: "total" <*>
1603+ v .: "successful" <*>
1604+ v .: "failed"
1605+ parseJSON _ = empty
1606+
1607+instance FromJSON NodeBreakerStats where
1608+ parseJSON = withObject "NodeBreakerStats" parse
1609+ where
1610+ parse o = NodeBreakerStats <$> o .: "tripped"
1611+ <*> o .: "overhead"
1612+ <*> o .: "estimated_size_in_bytes"
1613+ <*> o .: "limit_size_in_bytes"
1614+
1615+instance FromJSON NodeHTTPStats where
1616+ parseJSON = withObject "NodeHTTPStats" parse
1617+ where
1618+ parse o = NodeHTTPStats <$> o .: "total_opened"
1619+ <*> o .: "current_open"
1620+
1621+instance FromJSON NodeTransportStats where
1622+ parseJSON = withObject "NodeTransportStats" parse
1623+ where
1624+ parse o = NodeTransportStats <$> o .: "tx_size_in_bytes"
1625+ <*> o .: "tx_count"
1626+ <*> o .: "rx_size_in_bytes"
1627+ <*> o .: "rx_count"
1628+ <*> o .: "server_open"
1629+
1630+instance FromJSON NodeFSStats where
1631+ parseJSON = withObject "NodeFSStats" parse
1632+ where
1633+ parse o = NodeFSStats <$> o .: "data"
1634+ <*> o .: "total"
1635+ <*> (posixMS <$> o .: "timestamp")
1636+
1637+instance FromJSON NodeDataPathStats where
1638+ parseJSON = withObject "NodeDataPathStats" parse
1639+ where
1640+ parse o =
1641+ NodeDataPathStats <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
1642+ <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
1643+ <*> o .:? "disk_io_size_in_bytes"
1644+ <*> o .:? "disk_write_size_in_bytes"
1645+ <*> o .:? "disk_read_size_in_bytes"
1646+ <*> o .:? "disk_io_op"
1647+ <*> o .:? "disk_writes"
1648+ <*> o .:? "disk_reads"
1649+ <*> o .: "available_in_bytes"
1650+ <*> o .: "free_in_bytes"
1651+ <*> o .: "total_in_bytes"
1652+ <*> o .:? "type"
1653+ <*> o .: "dev"
1654+ <*> o .: "mount"
1655+ <*> o .: "path"
1656+
1657+instance FromJSON NodeNetworkStats where
1658+ parseJSON = withObject "NodeNetworkStats" parse
1659+ where
1660+ parse o = do
1661+ tcp <- o .: "tcp"
1662+ NodeNetworkStats <$> tcp .: "out_rsts"
1663+ <*> tcp .: "in_errs"
1664+ <*> tcp .: "attempt_fails"
1665+ <*> tcp .: "estab_resets"
1666+ <*> tcp .: "retrans_segs"
1667+ <*> tcp .: "out_segs"
1668+ <*> tcp .: "in_segs"
1669+ <*> tcp .: "curr_estab"
1670+ <*> tcp .: "passive_opens"
1671+ <*> tcp .: "active_opens"
1672+
1673+instance FromJSON NodeThreadPoolsStats where
1674+ parseJSON = withObject "NodeThreadPoolsStats" parse
1675+ where
1676+ parse o = NodeThreadPoolsStats <$> o .: "snapshot"
1677+ <*> o .: "bulk"
1678+ <*> o .: "merge"
1679+ <*> o .: "get"
1680+ <*> o .: "management"
1681+ <*> o .:? "fetch_shard_store"
1682+ <*> o .: "optimize"
1683+ <*> o .: "flush"
1684+ <*> o .: "search"
1685+ <*> o .: "warmer"
1686+ <*> o .: "generic"
1687+ <*> o .: "suggest"
1688+ <*> o .: "refresh"
1689+ <*> o .: "index"
1690+ <*> o .:? "listener"
1691+ <*> o .:? "fetch_shard_started"
1692+ <*> o .: "percolate"
1693+instance FromJSON NodeThreadPoolStats where
1694+ parseJSON = withObject "NodeThreadPoolStats" parse
1695+ where
1696+ parse o = NodeThreadPoolStats <$> o .: "completed"
1697+ <*> o .: "largest"
1698+ <*> o .: "rejected"
1699+ <*> o .: "active"
1700+ <*> o .: "queue"
1701+ <*> o .: "threads"
1702+
1703+instance FromJSON NodeJVMStats where
1704+ parseJSON = withObject "NodeJVMStats" parse
1705+ where
1706+ parse o = do
1707+ bufferPools <- o .: "buffer_pools"
1708+ mapped <- bufferPools .: "mapped"
1709+ direct <- bufferPools .: "direct"
1710+ gc <- o .: "gc"
1711+ collectors <- gc .: "collectors"
1712+ oldC <- collectors .: "old"
1713+ youngC <- collectors .: "young"
1714+ threads <- o .: "threads"
1715+ mem <- o .: "mem"
1716+ pools <- mem .: "pools"
1717+ oldM <- pools .: "old"
1718+ survivorM <- pools .: "survivor"
1719+ youngM <- pools .: "young"
1720+ NodeJVMStats <$> pure mapped
1721+ <*> pure direct
1722+ <*> pure oldC
1723+ <*> pure youngC
1724+ <*> threads .: "peak_count"
1725+ <*> threads .: "count"
1726+ <*> pure oldM
1727+ <*> pure survivorM
1728+ <*> pure youngM
1729+ <*> mem .: "non_heap_committed_in_bytes"
1730+ <*> mem .: "non_heap_used_in_bytes"
1731+ <*> mem .: "heap_max_in_bytes"
1732+ <*> mem .: "heap_committed_in_bytes"
1733+ <*> mem .: "heap_used_percent"
1734+ <*> mem .: "heap_used_in_bytes"
1735+ <*> (unMS <$> o .: "uptime_in_millis")
1736+ <*> (posixMS <$> o .: "timestamp")
1737+
1738+instance FromJSON JVMBufferPoolStats where
1739+ parseJSON = withObject "JVMBufferPoolStats" parse
1740+ where
1741+ parse o = JVMBufferPoolStats <$> o .: "total_capacity_in_bytes"
1742+ <*> o .: "used_in_bytes"
1743+ <*> o .: "count"
1744+
1745+instance FromJSON JVMGCStats where
1746+ parseJSON = withObject "JVMGCStats" parse
1747+ where
1748+ parse o = JVMGCStats <$> (unMS <$> o .: "collection_time_in_millis")
1749+ <*> o .: "collection_count"
1750+
1751+instance FromJSON JVMPoolStats where
1752+ parseJSON = withObject "JVMPoolStats" parse
1753+ where
1754+ parse o = JVMPoolStats <$> o .: "peak_max_in_bytes"
1755+ <*> o .: "peak_used_in_bytes"
1756+ <*> o .: "max_in_bytes"
1757+ <*> o .: "used_in_bytes"
1758+
1759+instance FromJSON NodeProcessStats where
1760+ parseJSON = withObject "NodeProcessStats" parse
1761+ where
1762+ parse o = do
1763+ mem <- o .: "mem"
1764+ cpu <- o .: "cpu"
1765+ NodeProcessStats <$> mem .: "total_virtual_in_bytes"
1766+ <*> mem .: "share_in_bytes"
1767+ <*> mem .: "resident_in_bytes"
1768+ <*> (unMS <$> cpu .: "total_in_millis")
1769+ <*> (unMS <$> cpu .: "user_in_millis")
1770+ <*> (unMS <$> cpu .: "sys_in_millis")
1771+ <*> cpu .: "percent"
1772+ <*> o .: "open_file_descriptors"
1773+ <*> (posixMS <$> o .: "timestamp")
1774+
1775+instance FromJSON NodeOSStats where
1776+ parseJSON = withObject "NodeOSStats" parse
1777+ where
1778+ parse o = do
1779+ swap <- o .: "swap"
1780+ mem <- o .: "mem"
1781+ cpu <- o .: "cpu"
1782+ load <- o .:? "load_average"
1783+ NodeOSStats <$> swap .: "free_in_bytes"
1784+ <*> swap .: "used_in_bytes"
1785+ <*> mem .: "actual_used_in_bytes"
1786+ <*> mem .: "actual_free_in_bytes"
1787+ <*> mem .: "used_percent"
1788+ <*> mem .: "free_percent"
1789+ <*> mem .: "used_in_bytes"
1790+ <*> mem .: "free_in_bytes"
1791+ <*> cpu .: "stolen"
1792+ <*> cpu .: "usage"
1793+ <*> cpu .: "idle"
1794+ <*> cpu .: "user"
1795+ <*> cpu .: "sys"
1796+ <*> pure load
1797+ <*> (unMS <$> o .: "uptime_in_millis")
1798+ <*> (posixMS <$> o .: "timestamp")
1799+
1800+instance FromJSON LoadAvgs where
1801+ parseJSON = withArray "LoadAvgs" parse
1802+ where
1803+ parse v = case V.toList v of
1804+ [one, five, fifteen] -> LoadAvgs <$> parseJSON one
1805+ <*> parseJSON five
1806+ <*> parseJSON fifteen
1807+ _ -> fail "Expecting a triple of Doubles"
1808+
1809+instance FromJSON NodeIndicesStats where
1810+ parseJSON = withObject "NodeIndicesStats" parse
1811+ where
1812+ parse o = do
1813+ let (.::) mv k = case mv of
1814+ Just v -> Just <$> v .: k
1815+ Nothing -> pure Nothing
1816+ mRecovery <- o .:? "recovery"
1817+ mQueryCache <- o .:? "query_cache"
1818+ suggest <- o .: "suggest"
1819+ translog <- o .: "translog"
1820+ segments <- o .: "segments"
1821+ completion <- o .: "completion"
1822+ percolate <- o .: "percolate"
1823+ fielddata <- o .: "fielddata"
1824+ idCache <- o .: "id_cache"
1825+ filterCache <- o .: "filter_cache"
1826+ warmer <- o .: "warmer"
1827+ flush <- o .: "flush"
1828+ refresh <- o .: "refresh"
1829+ merges <- o .: "merges"
1830+ search <- o .: "search"
1831+ getStats <- o .: "get"
1832+ indexing <- o .: "indexing"
1833+ store <- o .: "store"
1834+ docs <- o .: "docs"
1835+ NodeIndicesStats <$> (fmap unMS <$> mRecovery .:: "throttle_time_in_millis")
1836+ <*> mRecovery .:: "current_as_target"
1837+ <*> mRecovery .:: "current_as_source"
1838+ <*> mQueryCache .:: "miss_count"
1839+ <*> mQueryCache .:: "hit_count"
1840+ <*> mQueryCache .:: "evictions"
1841+ <*> mQueryCache .:: "memory_size_in_bytes"
1842+ <*> suggest .: "current"
1843+ <*> (unMS <$> suggest .: "time_in_millis")
1844+ <*> suggest .: "total"
1845+ <*> translog .: "size_in_bytes"
1846+ <*> translog .: "operations"
1847+ <*> segments .:? "fixed_bit_set_memory_in_bytes"
1848+ <*> segments .: "version_map_memory_in_bytes"
1849+ <*> segments .:? "index_writer_max_memory_in_bytes"
1850+ <*> segments .: "index_writer_memory_in_bytes"
1851+ <*> segments .: "memory_in_bytes"
1852+ <*> segments .: "count"
1853+ <*> completion .: "size_in_bytes"
1854+ <*> percolate .: "queries"
1855+ <*> percolate .: "memory_size_in_bytes"
1856+ <*> percolate .: "current"
1857+ <*> (unMS <$> percolate .: "time_in_millis")
1858+ <*> percolate .: "total"
1859+ <*> fielddata .: "evictions"
1860+ <*> fielddata .: "memory_size_in_bytes"
1861+ <*> idCache .: "memory_size_in_bytes"
1862+ <*> filterCache .: "evictions"
1863+ <*> filterCache .: "memory_size_in_bytes"
1864+ <*> (unMS <$> warmer .: "total_time_in_millis")
1865+ <*> warmer .: "total"
1866+ <*> warmer .: "current"
1867+ <*> (unMS <$> flush .: "total_time_in_millis")
1868+ <*> flush .: "total"
1869+ <*> (unMS <$> refresh .: "total_time_in_millis")
1870+ <*> refresh .: "total"
1871+ <*> merges .: "total_size_in_bytes"
1872+ <*> merges .: "total_docs"
1873+ <*> (unMS <$> merges .: "total_time_in_millis")
1874+ <*> merges .: "total"
1875+ <*> merges .: "current_size_in_bytes"
1876+ <*> merges .: "current_docs"
1877+ <*> merges .: "current"
1878+ <*> search .: "fetch_current"
1879+ <*> (unMS <$> search .: "fetch_time_in_millis")
1880+ <*> search .: "fetch_total"
1881+ <*> search .: "query_current"
1882+ <*> (unMS <$> search .: "query_time_in_millis")
1883+ <*> search .: "query_total"
1884+ <*> search .: "open_contexts"
1885+ <*> getStats .: "current"
1886+ <*> (unMS <$> getStats .: "missing_time_in_millis")
1887+ <*> getStats .: "missing_total"
1888+ <*> (unMS <$> getStats .: "exists_time_in_millis")
1889+ <*> getStats .: "exists_total"
1890+ <*> (unMS <$> getStats .: "time_in_millis")
1891+ <*> getStats .: "total"
1892+ <*> (fmap unMS <$> indexing .:? "throttle_time_in_millis")
1893+ <*> indexing .:? "is_throttled"
1894+ <*> indexing .:? "noop_update_total"
1895+ <*> indexing .: "delete_current"
1896+ <*> (unMS <$> indexing .: "delete_time_in_millis")
1897+ <*> indexing .: "delete_total"
1898+ <*> indexing .: "index_current"
1899+ <*> (unMS <$> indexing .: "index_time_in_millis")
1900+ <*> indexing .: "index_total"
1901+ <*> (unMS <$> store .: "throttle_time_in_millis")
1902+ <*> store .: "size_in_bytes"
1903+ <*> docs .: "deleted"
1904+ <*> docs .: "count"
1905+
1906+instance FromJSON NodeBreakersStats where
1907+ parseJSON = withObject "NodeBreakersStats" parse
1908+ where
1909+ parse o = NodeBreakersStats <$> o .: "parent"
1910+ <*> o .: "request"
1911+ <*> o .: "fielddata"
1912+
1913+instance FromJSON NodePluginInfo where
1914+ parseJSON = withObject "NodePluginInfo" parse
1915+ where
1916+ parse o = NodePluginInfo <$> o .: "site"
1917+ <*> o .: "jvm"
1918+ <*> o .: "description"
1919+ <*> o .: "version"
1920+ <*> o .: "name"
1921+
1922+instance FromJSON NodeHTTPInfo where
1923+ parseJSON = withObject "NodeHTTPInfo" parse
1924+ where
1925+ parse o = NodeHTTPInfo <$> o .: "max_content_length_in_bytes"
1926+ <*> parseJSON (Object o)
1927+
1928+instance FromJSON NodeTransportInfo where
1929+ parseJSON = withObject "NodeTransportInfo" parse
1930+ where
1931+ parse o = NodeTransportInfo <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
1932+ <*> parseJSON (Object o)
1933+ parseProfiles (Object o) | HM.null o = return []
1934+ parseProfiles v@(Array _) = parseJSON v
1935+ parseProfiles Null = return []
1936+ parseProfiles _ = fail "Could not parse profiles"
1937+
1938+instance FromJSON NodeNetworkInfo where
1939+ parseJSON = withObject "NodeNetworkInfo" parse
1940+ where
1941+ parse o = NodeNetworkInfo <$> o .: "primary_interface"
1942+ <*> (unMS <$> o .: "refresh_interval_in_millis")
1943+
1944+instance FromJSON NodeNetworkInterface where
1945+ parseJSON = withObject "NodeNetworkInterface" parse
1946+ where
1947+ parse o = NodeNetworkInterface <$> o .: "mac_address"
1948+ <*> o .: "name"
1949+ <*> o .: "address"
1950+
1951+instance FromJSON NodeJVMInfo where
1952+ parseJSON = withObject "NodeJVMInfo" parse
1953+ where
1954+ parse o = NodeJVMInfo <$> o .: "memory_pools"
1955+ <*> o .: "gc_collectors"
1956+ <*> o .: "mem"
1957+ <*> (posixMS <$> o .: "start_time_in_millis")
1958+ <*> o .: "vm_vendor"
1959+ <*> o .: "vm_version"
1960+ <*> o .: "vm_name"
1961+ <*> (unJVMVersion <$> o .: "version")
1962+ <*> o .: "pid"
1963+
1964+instance FromJSON NodeThreadPoolsInfo where
1965+ parseJSON = withObject "NodeThreadPoolsInfo" parse
1966+ where
1967+ parse o = NodeThreadPoolsInfo <$> o .: "refresh"
1968+ <*> o .: "management"
1969+ <*> o .: "percolate"
1970+ <*> o .:? "listener"
1971+ <*> o .:? "fetch_shard_started"
1972+ <*> o .: "search"
1973+ <*> o .: "flush"
1974+ <*> o .: "warmer"
1975+ <*> o .: "optimize"
1976+ <*> o .: "bulk"
1977+ <*> o .: "suggest"
1978+ <*> o .: "merge"
1979+ <*> o .: "snapshot"
1980+ <*> o .: "get"
1981+ <*> o .:? "fetch_shard_store"
1982+ <*> o .: "index"
1983+ <*> o .: "generic"
1984+
1985+instance FromJSON NodeProcessInfo where
1986+ parseJSON = withObject "NodeProcessInfo" parse
1987+ where
1988+ parse o = NodeProcessInfo <$> o .: "mlockall"
1989+ <*> o .: "max_file_descriptors"
1990+ <*> o .: "id"
1991+ <*> (unMS <$> o .: "refresh_interval_in_millis")
1992+
1993+instance FromJSON NodeOSInfo where
1994+ parseJSON = withObject "NodeOSInfo" parse
1995+ where
1996+ parse o = do
1997+ swap <- o .: "swap"
1998+ mem <- o .: "mem"
1999+ NodeOSInfo <$> swap .: "total_in_bytes"
2000+ <*> mem .: "total_in_bytes"
2001+ <*> o .: "cpu"
2002+ <*> o .: "available_processors"
2003+ <*> (unMS <$> o .: "refresh_interval_in_millis")
2004+
2005+instance FromJSON ReplicaBounds where
2006+ parseJSON v = withText "ReplicaBounds" parseText v
2007+ <|> withBool "ReplicaBounds" parseBool v
2008+ where parseText t = case T.splitOn "-" t of
2009+ [a, "all"] -> ReplicasLowerBounded <$> parseReadText a
2010+ [a, b] -> ReplicasBounded <$> parseReadText a
2011+ <*> parseReadText b
2012+ _ -> fail ("Could not parse ReplicaBounds: " <> show t)
2013+ parseBool False = pure ReplicasUnbounded
2014+ parseBool _ = fail "ReplicasUnbounded cannot be represented with True"
2015+
2016+instance FromJSON NominalDiffTimeJSON where
2017+ parseJSON = withText "NominalDiffTime" parse
2018+ where parse t = case T.takeEnd 1 t of
2019+ "s" -> NominalDiffTimeJSON . fromInteger <$> parseReadText (T.dropEnd 1 t)
2020+ _ -> fail "Invalid or missing NominalDiffTime unit (expected s)"
2021+
2022+instance FromJSON AllocationPolicy where
2023+ parseJSON = withText "AllocationPolicy" parse
2024+ where parse "all" = pure AllocAll
2025+ parse "primaries" = pure AllocPrimaries
2026+ parse "new_primaries" = pure AllocNewPrimaries
2027+ parse "none" = pure AllocNone
2028+ parse t = fail ("Invlaid AllocationPolicy: " <> show t)
2029+
2030+instance ToJSON CompoundFormat where
2031+ toJSON (CompoundFileFormat x) = Bool x
2032+ toJSON (MergeSegmentVsTotalIndex x) = toJSON x
2033+
2034+instance FromJSON CompoundFormat where
2035+ parseJSON v = CompoundFileFormat <$> parseJSON v
2036+ <|> MergeSegmentVsTotalIndex <$> parseJSON v
2037+
2038+instance FromJSON NodeFSTotalStats where
2039+ parseJSON = withObject "NodeFSTotalStats" parse
2040+ where
2041+ parse o = NodeFSTotalStats <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
2042+ <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
2043+ <*> o .:? "disk_io_size_in_bytes"
2044+ <*> o .:? "disk_write_size_in_bytes"
2045+ <*> o .:? "disk_read_size_in_bytes"
2046+ <*> o .:? "disk_io_op"
2047+ <*> o .:? "disk_writes"
2048+ <*> o .:? "disk_reads"
2049+ <*> o .: "available_in_bytes"
2050+ <*> o .: "free_in_bytes"
2051+ <*> o .: "total_in_bytes"
2052+
2053+instance FromJSON BoundTransportAddress where
2054+ parseJSON = withObject "BoundTransportAddress" parse
2055+ where
2056+ parse o = BoundTransportAddress <$> o .: "publish_address"
2057+ <*> o .: "bound_address"
2058+
2059+instance FromJSON JVMMemoryInfo where
2060+ parseJSON = withObject "JVMMemoryInfo" parse
2061+ where
2062+ parse o = JVMMemoryInfo <$> o .: "direct_max_in_bytes"
2063+ <*> o .: "non_heap_max_in_bytes"
2064+ <*> o .: "non_heap_init_in_bytes"
2065+ <*> o .: "heap_max_in_bytes"
2066+ <*> o .: "heap_init_in_bytes"
2067+
2068+instance FromJSON JVMVersion where
2069+ parseJSON (String t) =
2070+ JVMVersion <$> parseJSON (String (T.replace "_" "." t))
2071+ parseJSON v = JVMVersion <$> parseJSON v
2072+
2073+instance FromJSON NodeThreadPoolInfo where
2074+ parseJSON = withObject "NodeThreadPoolInfo" parse
2075+ where
2076+ parse o = do
2077+ ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
2078+ NodeThreadPoolInfo <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
2079+ <*> pure ka
2080+ <*> o .:? "min"
2081+ <*> o .:? "max"
2082+ <*> o .: "type"
2083+
2084+instance FromJSON CPUInfo where
2085+ parseJSON = withObject "CPUInfo" parse
2086+ where
2087+ parse o = CPUInfo <$> o .: "cache_size_in_bytes"
2088+ <*> o .: "cores_per_socket"
2089+ <*> o .: "total_sockets"
2090+ <*> o .: "total_cores"
2091+ <*> o .: "mhz"
2092+ <*> o .: "model"
2093+ <*> o .: "vendor"
2094+
2095+instance FromJSON ThreadPoolSize where
2096+ parseJSON v = parseAsNumber v <|> parseAsString v
2097+ where
2098+ parseAsNumber = parseAsInt <=< parseJSON
2099+ parseAsInt (-1) = return ThreadPoolUnbounded
2100+ parseAsInt n
2101+ | n >= 0 = return (ThreadPoolBounded n)
2102+ | otherwise = fail "Thread pool size must be >= -1."
2103+ parseAsString = withText "ThreadPoolSize" $ \t ->
2104+ case first (readMay . T.unpack) (T.span isNumber t) of
2105+ (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
2106+ (Just n, "") -> return (ThreadPoolBounded n)
2107+ _ -> fail ("Invalid thread pool size " <> T.unpack t)
2108+
2109+instance FromJSON ThreadPoolType where
2110+ parseJSON = withText "ThreadPoolType" parse
2111+ where
2112+ parse "scaling" = return ThreadPoolScaling
2113+ parse "fixed" = return ThreadPoolFixed
2114+ parse "cached" = return ThreadPoolCached
2115+ parse e = fail ("Unexpected thread pool type" <> T.unpack e)
2116+
2117+data Source =
2118+ NoSource
2119+ | SourcePatterns PatternOrPatterns
2120+ | SourceIncludeExclude Include Exclude
2121+ deriving (Show, Eq)
2122+
2123+instance ToJSON Source where
2124+ toJSON NoSource = toJSON False
2125+ toJSON (SourcePatterns patterns) = toJSON patterns
2126+ toJSON (SourceIncludeExclude incl excl) = object [ "include" .= incl, "exclude" .= excl ]
2127+
2128+data PatternOrPatterns =
2129+ PopPattern Pattern
2130+ | PopPatterns [Pattern]
2131+ deriving (Eq, Show)
2132+
2133+data Include = Include [Pattern] deriving (Eq, Show)
2134+data Exclude = Exclude [Pattern] deriving (Eq, Show)
2135+
2136+newtype Pattern = Pattern Text deriving (Eq, Show)
2137+
2138+newtype ScrollId = ScrollId Text deriving (Eq, Show, Ord, ToJSON, FromJSON)
2139+
2140+instance ToJSON PatternOrPatterns where
2141+ toJSON (PopPattern pattern) = toJSON pattern
2142+ toJSON (PopPatterns patterns) = toJSON patterns
2143+
2144+instance ToJSON Include where
2145+ toJSON (Include patterns) = toJSON patterns
2146+
2147+instance ToJSON Exclude where
2148+ toJSON (Exclude patterns) = toJSON patterns
2149+
2150+instance ToJSON Pattern where
2151+ toJSON (Pattern pattern) = toJSON pattern
2152+
2153+instance FromJSON NodesStats where
2154+ parseJSON = withObject "NodesStats" parse
2155+ where
2156+ parse o = do
2157+ nodes <- o .: "nodes"
2158+ stats <- forM (HM.toList nodes) $ \(fullNID, v) -> do
2159+ node <- parseJSON v
2160+ parseNodeStats (FullNodeId fullNID) node
2161+ cn <- o .: "cluster_name"
2162+ return (NodesStats stats cn)
2163+
2164+instance ToJSON UpdatableIndexSetting where
2165+ toJSON (NumberOfReplicas x) = oPath ("index" :| ["number_of_replicas"]) x
2166+ toJSON (AutoExpandReplicas x) = oPath ("index" :| ["auto_expand_replicas"]) x
2167+ toJSON (RefreshInterval x) = oPath ("index" :| ["refresh_interval"]) (NominalDiffTimeJSON x)
2168+ toJSON (IndexConcurrency x) = oPath ("index" :| ["concurrency"]) x
2169+ toJSON (FailOnMergeFailure x) = oPath ("index" :| ["fail_on_merge_failure"]) x
2170+ toJSON (TranslogFlushThresholdOps x) = oPath ("index" :| ["translog", "flush_threshold_ops"]) x
2171+ toJSON (TranslogFlushThresholdSize x) = oPath ("index" :| ["translog", "flush_threshold_size"]) x
2172+ toJSON (TranslogFlushThresholdPeriod x) = oPath ("index" :| ["translog", "flush_threshold_period"]) (NominalDiffTimeJSON x)
2173+ toJSON (TranslogDisableFlush x) = oPath ("index" :| ["translog", "disable_flush"]) x
2174+ toJSON (CacheFilterMaxSize x) = oPath ("index" :| ["cache", "filter", "max_size"]) x
2175+ toJSON (CacheFilterExpire x) = oPath ("index" :| ["cache", "filter", "expire"]) (NominalDiffTimeJSON <$> x)
2176+ toJSON (GatewaySnapshotInterval x) = oPath ("index" :| ["gateway", "snapshot_interval"]) (NominalDiffTimeJSON x)
2177+ toJSON (RoutingAllocationInclude fs) = oPath ("index" :| ["routing", "allocation", "include"]) (attrFilterJSON fs)
2178+ toJSON (RoutingAllocationExclude fs) = oPath ("index" :| ["routing", "allocation", "exclude"]) (attrFilterJSON fs)
2179+ toJSON (RoutingAllocationRequire fs) = oPath ("index" :| ["routing", "allocation", "require"]) (attrFilterJSON fs)
2180+ toJSON (RoutingAllocationEnable x) = oPath ("index" :| ["routing", "allocation", "enable"]) x
2181+ toJSON (RoutingAllocationShardsPerNode x) = oPath ("index" :| ["routing", "allocation", "total_shards_per_node"]) x
2182+ toJSON (RecoveryInitialShards x) = oPath ("index" :| ["recovery", "initial_shards"]) x
2183+ toJSON (GCDeletes x) = oPath ("index" :| ["gc_deletes"]) (NominalDiffTimeJSON x)
2184+ toJSON (TTLDisablePurge x) = oPath ("index" :| ["ttl", "disable_purge"]) x
2185+ toJSON (TranslogFSType x) = oPath ("index" :| ["translog", "fs", "type"]) x
2186+ toJSON (IndexCompoundFormat x) = oPath ("index" :| ["compound_format"]) x
2187+ toJSON (IndexCompoundOnFlush x) = oPath ("index" :| ["compound_on_flush"]) x
2188+ toJSON (WarmerEnabled x) = oPath ("index" :| ["warmer", "enabled"]) x
2189+ toJSON (BlocksReadOnly x) = oPath ("blocks" :| ["read_only"]) x
2190+ toJSON (BlocksRead x) = oPath ("blocks" :| ["read"]) x
2191+ toJSON (BlocksWrite x) = oPath ("blocks" :| ["write"]) x
2192+ toJSON (BlocksMetaData x) = oPath ("blocks" :| ["metadata"]) x
2193+
2194+instance FromJSON UpdatableIndexSetting where
2195+ parseJSON = withObject "UpdatableIndexSetting" parse
2196+ where parse o = numberOfReplicas `taggedAt` ["index", "number_of_replicas"]
2197+ <|> autoExpandReplicas `taggedAt` ["index", "auto_expand_replicas"]
2198+ <|> refreshInterval `taggedAt` ["index", "refresh_interval"]
2199+ <|> indexConcurrency `taggedAt` ["index", "concurrency"]
2200+ <|> failOnMergeFailure `taggedAt` ["index", "fail_on_merge_failure"]
2201+ <|> translogFlushThresholdOps `taggedAt` ["index", "translog", "flush_threshold_ops"]
2202+ <|> translogFlushThresholdSize `taggedAt` ["index", "translog", "flush_threshold_size"]
2203+ <|> translogFlushThresholdPeriod `taggedAt` ["index", "translog", "flush_threshold_period"]
2204+ <|> translogDisableFlush `taggedAt` ["index", "translog", "disable_flush"]
2205+ <|> cacheFilterMaxSize `taggedAt` ["index", "cache", "filter", "max_size"]
2206+ <|> cacheFilterExpire `taggedAt` ["index", "cache", "filter", "expire"]
2207+ <|> gatewaySnapshotInterval `taggedAt` ["index", "gateway", "snapshot_interval"]
2208+ <|> routingAllocationInclude `taggedAt` ["index", "routing", "allocation", "include"]
2209+ <|> routingAllocationExclude `taggedAt` ["index", "routing", "allocation", "exclude"]
2210+ <|> routingAllocationRequire `taggedAt` ["index", "routing", "allocation", "require"]
2211+ <|> routingAllocationEnable `taggedAt` ["index", "routing", "allocation", "enable"]
2212+ <|> routingAllocationShardsPerNode `taggedAt` ["index", "routing", "allocation", "total_shards_per_node"]
2213+ <|> recoveryInitialShards `taggedAt` ["index", "recovery", "initial_shards"]
2214+ <|> gcDeletes `taggedAt` ["index", "gc_deletes"]
2215+ <|> ttlDisablePurge `taggedAt` ["index", "ttl", "disable_purge"]
2216+ <|> translogFSType `taggedAt` ["index", "translog", "fs", "type"]
2217+ <|> compoundFormat `taggedAt` ["index", "compound_format"]
2218+ <|> compoundOnFlush `taggedAt` ["index", "compound_on_flush"]
2219+ <|> warmerEnabled `taggedAt` ["index", "warmer", "enabled"]
2220+ <|> blocksReadOnly `taggedAt` ["blocks", "read_only"]
2221+ <|> blocksRead `taggedAt` ["blocks", "read"]
2222+ <|> blocksWrite `taggedAt` ["blocks", "write"]
2223+ <|> blocksMetaData `taggedAt` ["blocks", "metadata"]
2224+ where taggedAt f ks = taggedAt' f (Object o) ks
2225+ taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON (unStringlyTypeJSON v)))
2226+ taggedAt' f v (k:ks) = withObject "Object" (\o -> do v' <- o .: k
2227+ taggedAt' f v' ks) v
2228+ numberOfReplicas = pure . NumberOfReplicas
2229+ autoExpandReplicas = pure . AutoExpandReplicas
2230+ refreshInterval = pure . RefreshInterval . ndtJSON
2231+ indexConcurrency = pure . IndexConcurrency
2232+ failOnMergeFailure = pure . FailOnMergeFailure
2233+ translogFlushThresholdOps = pure . TranslogFlushThresholdOps
2234+ translogFlushThresholdSize = pure . TranslogFlushThresholdSize
2235+ translogFlushThresholdPeriod = pure . TranslogFlushThresholdPeriod . ndtJSON
2236+ translogDisableFlush = pure . TranslogDisableFlush
2237+ cacheFilterMaxSize = pure . CacheFilterMaxSize
2238+ cacheFilterExpire = pure . CacheFilterExpire . fmap ndtJSON
2239+ gatewaySnapshotInterval = pure . GatewaySnapshotInterval . ndtJSON
2240+ routingAllocationInclude = fmap RoutingAllocationInclude . parseAttrFilter
2241+ routingAllocationExclude = fmap RoutingAllocationExclude . parseAttrFilter
2242+ routingAllocationRequire = fmap RoutingAllocationRequire . parseAttrFilter
2243+ routingAllocationEnable = pure . RoutingAllocationEnable
2244+ routingAllocationShardsPerNode = pure . RoutingAllocationShardsPerNode
2245+ recoveryInitialShards = pure . RecoveryInitialShards
2246+ gcDeletes = pure . GCDeletes . ndtJSON
2247+ ttlDisablePurge = pure . TTLDisablePurge
2248+ translogFSType = pure . TranslogFSType
2249+ compoundFormat = pure . IndexCompoundFormat
2250+ compoundOnFlush = pure . IndexCompoundOnFlush
2251+ warmerEnabled = pure . WarmerEnabled
2252+ blocksReadOnly = pure . BlocksReadOnly
2253+ blocksRead = pure . BlocksRead
2254+ blocksWrite = pure . BlocksWrite
2255+ blocksMetaData = pure . BlocksMetaData
2256+
2257+instance ToJSON ReplicaBounds where
2258+ toJSON (ReplicasBounded a b) = String (showText a <> "-" <> showText b)
2259+ toJSON (ReplicasLowerBounded a) = String (showText a <> "-all")
2260+ toJSON ReplicasUnbounded = Bool False
2261+
2262+instance ToJSON NominalDiffTimeJSON where
2263+ toJSON (NominalDiffTimeJSON t) = String (showText (round t :: Integer) <> "s")
2264+
2265+instance ToJSON AllocationPolicy where
2266+ toJSON AllocAll = String "all"
2267+ toJSON AllocPrimaries = String "primaries"
2268+ toJSON AllocNewPrimaries = String "new_primaries"
2269+ toJSON AllocNone = String "none"
2270+
2271+instance ToJSON IndexTemplate where
2272+ toJSON (IndexTemplate p s m) = merge
2273+ (object [ "template" .= p
2274+ , "mappings" .= foldl' merge (object []) m
2275+ ])
2276+ (toJSON s)
2277+ where
2278+ merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
2279+ merge o Null = o
2280+ merge _ _ = undefined
2281+
2282+instance FromJSON IndexAliasesSummary where
2283+ parseJSON = withObject "IndexAliasesSummary" parse
2284+ where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)
2285+ go ixn = withObject "index aliases" $ \ia -> do
2286+ aliases <- ia .:? "aliases" .!= mempty
2287+ forM (HM.toList aliases) $ \(aName, v) -> do
2288+ let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))
2289+ IndexAliasSummary indexAlias <$> parseJSON v
2290+
2291+instance ToJSON IndexAliasAction where
2292+ toJSON (AddAlias ia opts) = object ["add" .= (iaObj <> optsObj)]
2293+ where Object iaObj = toJSON ia
2294+ Object optsObj = toJSON opts
2295+ toJSON (RemoveAlias ia) = object ["remove" .= iaObj]
2296+ where Object iaObj = toJSON ia
2297+
2298+instance ToJSON IndexAlias where
2299+ toJSON IndexAlias {..} = object ["index" .= srcIndex
2300+ , "alias" .= indexAlias
2301+ ]
2302+
2303+instance FromJSON AliasRouting where
2304+ parseJSON = withObject "AliasRouting" parse
2305+ where parse o = parseAll o <|> parseGranular o
2306+ parseAll o = AllAliasRouting <$> o .: "routing"
2307+ parseGranular o = do
2308+ sr <- o .:? "search_routing"
2309+ ir <- o .:? "index_routing"
2310+ if isNothing sr && isNothing ir
2311+ then fail "Both search_routing and index_routing can't be blank"
2312+ else return (GranularAliasRouting sr ir)
2313+
2314+instance FromJSON IndexAliasCreate where
2315+ parseJSON v = withObject "IndexAliasCreate" parse v
2316+ where parse o = IndexAliasCreate <$> optional (parseJSON v)
2317+ <*> o .:? "filter"
2318+
2319+instance ToJSON IndexAliasCreate where
2320+ toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)
2321+ where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter
2322+ Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting
2323+
2324+instance ToJSON AliasRouting where
2325+ toJSON (AllAliasRouting v) = object ["routing" .= v]
2326+ toJSON (GranularAliasRouting srch idx) = object (catMaybes prs)
2327+ where prs = [("search_routing" .=) <$> srch
2328+ ,("index_routing" .=) <$> idx]
2329+
2330+instance ToJSON SearchAliasRouting where
2331+ toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
2332+
2333+instance FromJSON SearchAliasRouting where
2334+ parseJSON = withText "SearchAliasRouting" parse
2335+ where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
2336+
2337+instance FromJSON EsError where
2338+ parseJSON (Object v) = EsError <$>
2339+ v .: "status" <*>
2340+ (v .: "error" <|> (v .: "error" >>= (.: "reason")))
2341+ parseJSON _ = empty
src/Database/V1/Bloodhound/Internal/Highlight.hsnew file+144
@@ -0,0 +1,144 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Database.V1.Bloodhound.Internal.Highlight where
4+
5+
6+import Bloodhound.Import
7+
8+import qualified Data.Map as M
9+
10+import Database.V1.Bloodhound.Internal.Newtypes
11+import Database.V1.Bloodhound.Internal.Query
12+
13+type HitHighlight = M.Map Text [Text]
14+
15+data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
16+ , highlightFields :: [FieldHighlight]
17+ } deriving (Show, Eq)
18+
19+instance ToJSON Highlights where
20+ toJSON (Highlights global fields) =
21+ omitNulls (("fields" .= fields)
22+ : highlightSettingsPairs global)
23+
24+data HighlightSettings = Plain PlainHighlight
25+ | Postings PostingsHighlight
26+ | FastVector FastVectorHighlight
27+ deriving (Show, Eq)
28+
29+data FieldHighlight = FieldHighlight FieldName (Maybe HighlightSettings)
30+ deriving (Show, Eq)
31+
32+data PlainHighlight =
33+ PlainHighlight { plainCommon :: Maybe CommonHighlight
34+ , plainNonPost :: Maybe NonPostings } deriving (Show, Eq)
35+
36+ -- This requires that index_options are set to 'offset' in the mapping.
37+data PostingsHighlight = PostingsHighlight (Maybe CommonHighlight) deriving (Show, Eq)
38+
39+-- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
40+data FastVectorHighlight =
41+ FastVectorHighlight { fvCommon :: Maybe CommonHighlight
42+ , fvNonPostSettings :: Maybe NonPostings
43+ , boundaryChars :: Maybe Text
44+ , boundaryMaxScan :: Maybe Int
45+ , fragmentOffset :: Maybe Int
46+ , matchedFields :: [Text]
47+ , phraseLimit :: Maybe Int
48+ } deriving (Show, Eq)
49+
50+data CommonHighlight =
51+ CommonHighlight { order :: Maybe Text
52+ , forceSource :: Maybe Bool
53+ , tag :: Maybe HighlightTag
54+ , encoder :: Maybe HighlightEncoder
55+ , noMatchSize :: Maybe Int
56+ , highlightQuery :: Maybe Query
57+ , requireFieldMatch :: Maybe Bool
58+ } deriving (Show, Eq)
59+
60+-- Settings that are only applicable to FastVector and Plain highlighters.
61+data NonPostings =
62+ NonPostings { fragmentSize :: Maybe Int
63+ , numberOfFragments :: Maybe Int} deriving (Show, Eq)
64+
65+data HighlightEncoder = DefaultEncoder
66+ | HTMLEncoder
67+ deriving (Show, Eq)
68+
69+-- NOTE: Should the tags use some kind of HTML type, rather than Text?
70+data HighlightTag = TagSchema Text
71+ | CustomTags ([Text], [Text]) -- Only uses more than the first value in the lists if fvh
72+ deriving (Show, Eq)
73+
74+highlightSettingsPairs :: Maybe HighlightSettings -> [Pair]
75+highlightSettingsPairs Nothing = []
76+highlightSettingsPairs (Just (Plain plh)) = plainHighPairs (Just plh)
77+highlightSettingsPairs (Just (Postings ph)) = postHighPairs (Just ph)
78+highlightSettingsPairs (Just (FastVector fvh)) = fastVectorHighPairs (Just fvh)
79+
80+plainHighPairs :: Maybe PlainHighlight -> [Pair]
81+plainHighPairs Nothing = []
82+plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
83+ [ "type" .= String "plain"]
84+ ++ commonHighlightPairs plCom
85+ ++ nonPostingsToPairs plNonPost
86+
87+postHighPairs :: Maybe PostingsHighlight -> [Pair]
88+postHighPairs Nothing = []
89+postHighPairs (Just (PostingsHighlight pCom)) =
90+ ("type" .= String "postings")
91+ : commonHighlightPairs pCom
92+
93+fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
94+fastVectorHighPairs Nothing = []
95+fastVectorHighPairs (Just
96+ (FastVectorHighlight fvCom fvNonPostSettings' fvBoundChars
97+ fvBoundMaxScan fvFragOff fvMatchedFields
98+ fvPhraseLim)) =
99+ [ "type" .= String "fvh"
100+ , "boundary_chars" .= fvBoundChars
101+ , "boundary_max_scan" .= fvBoundMaxScan
102+ , "fragment_offset" .= fvFragOff
103+ , "matched_fields" .= fvMatchedFields
104+ , "phraseLimit" .= fvPhraseLim]
105+ ++ commonHighlightPairs fvCom
106+ ++ nonPostingsToPairs fvNonPostSettings'
107+
108+commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
109+commonHighlightPairs Nothing = []
110+commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
111+ chNoMatchSize chHighlightQuery
112+ chRequireFieldMatch)) =
113+ [ "order" .= chScore
114+ , "force_source" .= chForceSource
115+ , "encoder" .= chEncoder
116+ , "no_match_size" .= chNoMatchSize
117+ , "highlight_query" .= chHighlightQuery
118+ , "require_fieldMatch" .= chRequireFieldMatch]
119+ ++ highlightTagToPairs chTag
120+
121+nonPostingsToPairs :: Maybe NonPostings -> [Pair]
122+nonPostingsToPairs Nothing = []
123+nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
124+ [ "fragment_size" .= npFragSize
125+ , "number_of_fragments" .= npNumOfFrags]
126+
127+highlightTagToPairs :: Maybe HighlightTag -> [Pair]
128+highlightTagToPairs (Just (TagSchema _)) = [ "scheme" .= String "default"]
129+highlightTagToPairs (Just (CustomTags (pre, post))) = [ "pre_tags" .= pre
130+ , "post_tags" .= post]
131+highlightTagToPairs Nothing = []
132+
133+instance ToJSON FieldHighlight where
134+ toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
135+ object [ fName .= fSettings ]
136+ toJSON (FieldHighlight (FieldName fName) Nothing) =
137+ object [ fName .= emptyObject ]
138+
139+instance ToJSON HighlightSettings where
140+ toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
141+
142+instance ToJSON HighlightEncoder where
143+ toJSON DefaultEncoder = String "default"
144+ toJSON HTMLEncoder = String "html"
src/Database/V1/Bloodhound/Internal/Newtypes.hs+53−3
@@ -3,10 +3,8 @@
3
3
4module Database.V1.Bloodhound.Internal.Newtypes where
4module Database.V1.Bloodhound.Internal.Newtypes where
5
5
6−
7import Bloodhound.Import
6import Bloodhound.Import
8
7
9−
10newtype From = From Int deriving (Eq, Show, ToJSON)
8newtype From = From Int deriving (Eq, Show, ToJSON)
11newtype Size = Size Int deriving (Eq, Show, ToJSON, FromJSON)
9newtype Size = Size Int deriving (Eq, Show, ToJSON, FromJSON)
12
10
@@ -16,7 +14,7 @@ newtype Size = Size Int deriving (Eq, Show, ToJSON, FromJSON)
16-}
14-}
17newtype FieldName =
15newtype FieldName =
18 FieldName Text
16 FieldName Text
19− deriving (Eq, Read, Show, ToJSON, FromJSON)
17+ deriving (Eq, Show, ToJSON, FromJSON)
20
18
21newtype Boost =
19newtype Boost =
22 Boost Double
20 Boost Double
@@ -159,3 +157,55 @@ newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Show, ToJSON, FromJS
159
157
160-- | Newtype wrapper to parse ES's concerning tendency to in some APIs return a floating point number of milliseconds since epoch ಠ_ಠ
158-- | Newtype wrapper to parse ES's concerning tendency to in some APIs return a floating point number of milliseconds since epoch ಠ_ಠ
161newtype POSIXMS = POSIXMS { posixMS :: UTCTime }
159newtype POSIXMS = POSIXMS { posixMS :: UTCTime }
160+
161+instance FromJSON POSIXMS where
162+ parseJSON = withScientific "POSIXMS" (return . parse)
163+ where parse n = let n' = truncate n :: Integer
164+ in POSIXMS (posixSecondsToUTCTime (fromInteger (n' `div` 1000)))
165+
166+{-| 'IndexName' is used to describe which index to query/create/delete
167+-}
168+newtype IndexName = IndexName Text deriving (Eq, Show, ToJSON, FromJSON)
169+
170+newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Show, ToJSON)
171+
172+type Score = Maybe Double
173+
174+newtype ShardId = ShardId { shardId :: Int }
175+ deriving (Eq, Show, FromJSON)
176+
177+-- | Milliseconds
178+newtype MS = MS NominalDiffTime
179+
180+
181+-- keeps the unexported constructor warnings at bay
182+unMS :: MS -> NominalDiffTime
183+unMS (MS t) = t
184+
185+instance FromJSON MS where
186+ parseJSON = withScientific "MS" (return . MS . parse)
187+ where
188+ parse n = fromInteger ((truncate n) * 1000)
189+
190+newtype MaybeNA a = MaybeNA { unMaybeNA :: Maybe a }
191+ deriving (Show, Eq)
192+
193+instance FromJSON a => FromJSON (MaybeNA a) where
194+ parseJSON (String "NA") = pure $ MaybeNA Nothing
195+ parseJSON o = MaybeNA . Just <$> parseJSON o
196+
197+newtype SnapshotName = SnapshotName { snapshotName :: Text }
198+ deriving (Show, Eq, Ord, ToJSON, FromJSON)
199+
200+instance FromJSON ShardCount where
201+ parseJSON v = parseAsInt v
202+ <|> parseAsString v
203+ where parseAsInt = fmap ShardCount . parseJSON
204+ parseAsString = withText "ShardCount" (fmap ShardCount . parseReadText)
205+
206+
207+instance FromJSON ReplicaCount where
208+ parseJSON v = parseAsInt v
209+ <|> parseAsString v
210+ where parseAsInt = fmap ReplicaCount . parseJSON
211+ parseAsString = withText "ReplicaCount" (fmap ReplicaCount . parseReadText)
src/Database/V1/Bloodhound/Internal/Query.hs+12−6
@@ -2,10 +2,7 @@
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE RecordWildCards #-}
3{-# LANGUAGE RecordWildCards #-}
4
4
5−module Database.V1.Bloodhound.Internal.Query
5+module Database.V1.Bloodhound.Internal.Query where
6− ( module X
7− , module Database.V1.Bloodhound.Internal.Query
8− ) where
9
6
10
7
11import Bloodhound.Import
8import Bloodhound.Import
@@ -13,8 +10,8 @@ import Bloodhound.Import
13import qualified Data.HashMap.Strict as HM
10import qualified Data.HashMap.Strict as HM
14import qualified Data.Text as T
11import qualified Data.Text as T
15
12
16−import Database.Bloodhound.Common.Script as X
17−import Database.V5.Bloodhound.Internal.Newtypes
13+import Database.V1.Bloodhound.Internal.Newtypes
14+import Database.V1.Bloodhound.Types.Class
18
15
19
16
20data GeoPoint =
17data GeoPoint =
@@ -99,6 +96,15 @@ data Filter = AndFilter [Filter] Cache
99 | TermFilter Term Cache
96 | TermFilter Term Cache
100 deriving (Eq, Show)
97 deriving (Eq, Show)
101
98
99+instance Semigroup Filter where
100+ a <> b = AndFilter [a, b] defaultCache
101+
102+instance Monoid Filter where
103+ mempty = IdentityFilter
104+ mappend = (<>)
105+
106+instance Seminearring Filter where
107+ a <||> b = OrFilter [a, b] defaultCache
102
108
103data BoolMatch = MustMatch Term Cache
109data BoolMatch = MustMatch Term Cache
104 | MustNotMatch Term Cache
110 | MustNotMatch Term Cache
src/Database/V1/Bloodhound/Internal/Sort.hs+27
@@ -25,6 +25,22 @@ type Sort = [SortSpec]
25data SortSpec = DefaultSortSpec DefaultSort
25data SortSpec = DefaultSortSpec DefaultSort
26 | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Show)
26 | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Show)
27
27
28+instance ToJSON SortSpec where
29+ toJSON (DefaultSortSpec
30+ (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped
31+ dsSortMode dsMissingSort dsNestedFilter)) =
32+ object [dsSortFieldName .= omitNulls base] where
33+ base = [ "order" .= dsSortOrder
34+ , "ignore_unmapped" .= dsIgnoreUnmapped
35+ , "mode" .= dsSortMode
36+ , "missing" .= dsMissingSort
37+ , "nested_filter" .= dsNestedFilter ]
38+
39+ toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
40+ object [ "unit" .= units
41+ , field .= gdsLatLon
42+ , "order" .= gdsSortOrder ]
43+
28{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
44{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
29 'mkSort' convenience function for when you want to specify only the most
45 'mkSort' convenience function for when you want to specify only the most
30 common parameters.
46 common parameters.
@@ -49,6 +65,10 @@ data SortOrder = Ascending
49 | Descending deriving (Eq, Show)
65 | Descending deriving (Eq, Show)
50
66
51
67
68+instance ToJSON SortOrder where
69+ toJSON Ascending = String "asc"
70+ toJSON Descending = String "desc"
71+
52{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
72{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
53
73
54http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
74http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
@@ -77,3 +97,10 @@ instance ToJSON Missing where
77 toJSON LastMissing = String "_last"
97 toJSON LastMissing = String "_last"
78 toJSON FirstMissing = String "_first"
98 toJSON FirstMissing = String "_first"
79 toJSON (CustomMissing txt) = String txt
99 toJSON (CustomMissing txt) = String txt
100+
101+-- {-| 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so
102+-- that you can concisely describe the usual kind of 'SortSpec's you want.
103+-- -}
104+mkSort :: FieldName -> SortOrder -> DefaultSort
105+mkSort fieldName sOrder = DefaultSort fieldName sOrder False Nothing Nothing Nothing
106+
src/Database/V1/Bloodhound/Internal/Suggest.hs+5−5
@@ -8,8 +8,8 @@ import Bloodhound.Import
8
8
9import qualified Data.HashMap.Strict as HM
9import qualified Data.HashMap.Strict as HM
10
10
11−import Database.V5.Bloodhound.Internal.Newtypes
11+import Database.V1.Bloodhound.Internal.Newtypes
12−import Database.V5.Bloodhound.Internal.Query
12+import Database.V1.Bloodhound.Internal.Query
13
13
14data Suggest = Suggest { suggestText :: Text
14data Suggest = Suggest { suggestText :: Text
15 , suggestName :: Text
15 , suggestName :: Text
@@ -209,7 +209,7 @@ data SuggestOptions =
209 , suggestOptionsFreq :: Maybe Int
209 , suggestOptionsFreq :: Maybe Int
210 , suggestOptionsHighlighted :: Maybe Text
210 , suggestOptionsHighlighted :: Maybe Text
211 }
211 }
212− deriving (Eq, Read, Show)
212+ deriving (Eq, Show)
213
213
214instance FromJSON SuggestOptions where
214instance FromJSON SuggestOptions where
215 parseJSON = withObject "SuggestOptions" parse
215 parseJSON = withObject "SuggestOptions" parse
@@ -225,7 +225,7 @@ data SuggestResponse =
225 , suggestResponseLength :: Int
225 , suggestResponseLength :: Int
226 , suggestResponseOptions :: [SuggestOptions]
226 , suggestResponseOptions :: [SuggestOptions]
227 }
227 }
228− deriving (Eq, Read, Show)
228+ deriving (Eq, Show)
229
229
230instance FromJSON SuggestResponse where
230instance FromJSON SuggestResponse where
231 parseJSON = withObject "SuggestResponse" parse
231 parseJSON = withObject "SuggestResponse" parse
@@ -239,7 +239,7 @@ data NamedSuggestionResponse =
239 NamedSuggestionResponse { nsrName :: Text
239 NamedSuggestionResponse { nsrName :: Text
240 , nsrResponses :: [SuggestResponse]
240 , nsrResponses :: [SuggestResponse]
241 }
241 }
242− deriving (Eq, Read, Show)
242+ deriving (Eq, Show)
243
243
244instance FromJSON NamedSuggestionResponse where
244instance FromJSON NamedSuggestionResponse where
245 parseJSON (Object o) = do
245 parseJSON (Object o) = do
src/Database/V1/Bloodhound/Types.hs+33−4830
@@ -378,535 +378,30 @@ module Database.V1.Bloodhound.Types
378 , EsPassword(..)
378 , EsPassword(..)
379 ) where
379 ) where
380
380
381−import Control.Applicative as A
381+import Bloodhound.Import
382−import Control.Arrow (first)
383−import Control.Monad.Catch
384−import Control.Monad.Except
385−import Control.Monad.Reader (MonadReader (..),
386− ReaderT (..))
387−import Control.Monad.State (MonadState)
388−import Control.Monad.Writer (MonadWriter)
389−import Data.Aeson
390−import Data.Aeson.Types (Pair, Parser,
391− emptyObject,
392− parseEither,
393− parseMaybe,
394− typeMismatch)
395−import qualified Data.ByteString.Lazy.Char8 as L
396−import Data.Char
397−import Data.Hashable (Hashable)
398−import qualified Data.HashMap.Strict as HM
399−import Data.List (foldl', intercalate,
400− nub)
401−import Data.List.NonEmpty (NonEmpty (..), toList)
402−import qualified Data.Map.Strict as M
403−import Data.Maybe
404−import Data.Scientific (Scientific)
405−import Data.Semigroup
406−import Data.Text (Text)
407−import qualified Data.Text as T
408−import Data.Time.Calendar
409−import Data.Time.Clock (NominalDiffTime,
410− UTCTime)
411−import Data.Time.Clock.POSIX
412−import qualified Data.Traversable as DT
413−import Data.Typeable (Typeable)
414−import qualified Data.Vector as V
415−import qualified Data.Version as Vers
416−import GHC.Enum
417−import GHC.Generics (Generic)
418−import Network.HTTP.Client
419−import qualified Network.HTTP.Types.Method as NHTM
420−import qualified Text.ParserCombinators.ReadP as RP
421−import qualified Text.Read as TR
422
382
423−import Database.V1.Bloodhound.Internal.Client
424import Database.V1.Bloodhound.Types.Class
383import Database.V1.Bloodhound.Types.Class
384+import Database.V1.Bloodhound.Internal.Aggregation
385+import Database.V1.Bloodhound.Internal.Client
386+import Database.V1.Bloodhound.Internal.Highlight
387+import Database.V1.Bloodhound.Internal.Newtypes
388+import Database.V1.Bloodhound.Internal.Query
389+import Database.V1.Bloodhound.Internal.Sort
390+import Database.V1.Bloodhound.Internal.Suggest
425
391
392+data SearchResult a =
393+ SearchResult { took :: Int
394+ , timedOut :: Bool
395+ , shards :: ShardResult
396+ , searchHits :: SearchHits a
397+ , aggregations :: Maybe AggregationResults
398+ , scrollId :: Maybe ScrollId
399+ , suggest :: Maybe NamedSuggestionResponse -- ^ Only one Suggestion request / response per Search is supported.
400+ }
401+ deriving (Eq, Show)
426
402
427
403
428−data FSType = FSSimple
429− | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
430−
431−data InitialShardCount = QuorumShards
432− | QuorumMinus1Shards
433− | FullShards
434− | FullMinus1Shards
435− | ExplicitShards Int
436− deriving (Eq, Read, Show, Generic, Typeable)
437−
438−data NodeAttrFilter = NodeAttrFilter { nodeAttrFilterName :: NodeAttrName
439− , nodeAttrFilterValues :: NonEmpty Text}
440− deriving (Eq, Read, Show, Generic, Ord, Typeable)
441−
442−newtype NodeAttrName = NodeAttrName Text deriving (Eq, Read, Show, Ord, Generic, Typeable)
443−
444−data CompoundFormat = CompoundFileFormat Bool
445− | MergeSegmentVsTotalIndex Double
446− -- ^ percentage between 0 and 1 where 0 is false, 1 is true
447− deriving (Eq, Read, Show, Generic, Typeable)
448−
449−newtype NominalDiffTimeJSON = NominalDiffTimeJSON { ndtJSON :: NominalDiffTime }
450−
451−data IndexSettingsSummary = IndexSettingsSummary { sSummaryIndexName :: IndexName
452− , sSummaryFixedSettings :: IndexSettings
453− , sSummaryUpdateable :: [UpdatableIndexSetting]}
454− deriving (Eq, Show, Generic, Typeable)
455−
456−{-| 'Reply' and 'Method' are type synonyms from 'Network.HTTP.Types.Method.Method' -}
457−type Reply = Network.HTTP.Client.Response L.ByteString
458−type Method = NHTM.Method
459−
460−{-| 'OpenCloseIndex' is a sum type for opening and closing indices.
461−
462− <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html>
463−-}
464−data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Read, Show, Generic, Typeable)
465−
466−data FieldType = GeoPointType
467− | GeoShapeType
468− | FloatType
469− | IntegerType
470− | LongType
471− | ShortType
472− | ByteType deriving (Eq, Read, Show, Generic, Typeable)
473−
474−data FieldDefinition =
475− FieldDefinition { fieldType :: FieldType } deriving (Eq, Read, Show, Generic, Typeable)
476−
477−{-| An 'IndexTemplate' defines a template that will automatically be
478− applied to new indices created. The templates include both
479− 'IndexSettings' and mappings, and a simple 'TemplatePattern' that
480− controls if the template will be applied to the index created.
481− Specify mappings as follows: @[toJSON TweetMapping, ...]@
482−
483− https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
484−-}
485−data IndexTemplate =
486− IndexTemplate { templatePattern :: TemplatePattern
487− , templateSettings :: Maybe IndexSettings
488− , templateMappings :: [Value]
489− }
490−
491−data MappingField =
492− MappingField { mappingFieldName :: FieldName
493− , fieldDefinition :: FieldDefinition } deriving (Eq, Read, Show, Generic, Typeable)
494−
495−{-| Support for type reification of 'Mapping's is currently incomplete, for
496− now the mapping API verbiage expects a 'ToJSON'able blob.
497−
498− Indexes have mappings, mappings are schemas for the documents contained in the
499− index. I'd recommend having only one mapping per index, always having a mapping,
500− and keeping different kinds of documents separated if possible.
501−-}
502−data Mapping = Mapping { typeName :: TypeName
503− , mappingFields :: [MappingField] } deriving (Eq, Read, Show, Generic, Typeable)
504−
505−{-| 'BulkOperation' is a sum type for expressing the four kinds of bulk
506− operation index, create, delete, and update. 'BulkIndex' behaves like an
507− "upsert", 'BulkCreate' will fail if a document already exists at the DocId.
508−
509− <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk>
510−-}
511−data BulkOperation =
512− BulkIndex IndexName MappingName DocId Value
513− | BulkCreate IndexName MappingName DocId Value
514− | BulkDelete IndexName MappingName DocId
515− | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Read, Show, Generic, Typeable)
516−
517−{-| 'EsResult' describes the standard wrapper JSON document that you see in
518− successful Elasticsearch lookups or lookups that couldn't find the document.
519−-}
520−data EsResult a = EsResult { _index :: Text
521− , _type :: Text
522− , _id :: Text
523− , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Read, Show, Generic, Typeable)
524−
525−{-| 'EsResultFound' contains the document and its metadata inside of an
526− 'EsResult' when the document was successfully found.
527−-}
528−data EsResultFound a = EsResultFound { _version :: DocVersion
529− , _source :: a } deriving (Eq, Read, Show, Generic, Typeable)
530−
531−{-| 'EsError' is the generic type that will be returned when there was a
532− problem. If you can't parse the expected response, its a good idea to
533− try parsing this.
534−-}
535−data EsError = EsError { errorStatus :: Int
536− , errorMessage :: Text } deriving (Eq, Read, Show, Generic, Typeable)
537−
538−{-| 'EsProtocolException' will be thrown if Bloodhound cannot parse a response
539−returned by the ElasticSearch server. If you encounter this error, please
540−verify that your domain data types and FromJSON instances are working properly
541−(for example, the 'a' of '[Hit a]' in 'SearchResult.searchHits.hits'). If you're
542−sure that your mappings are correct, then this error may be an indication of an
543−incompatibility between Bloodhound and ElasticSearch. Please open a bug report
544−and be sure to include the exception body.
545−-}
546−data EsProtocolException = EsProtocolException { esProtoExBody :: L.ByteString }
547− deriving (Eq, Read, Show, Generic, Typeable)
548−
549−instance Exception EsProtocolException
550−
551−data IndexAlias = IndexAlias { srcIndex :: IndexName
552− , indexAlias :: IndexAliasName } deriving (Eq, Read, Show, Generic, Typeable)
553−
554−newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Read, Show, Generic, ToJSON)
555−
556−data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
557− | RemoveAlias IndexAlias deriving (Read, Show, Eq, Generic, Typeable)
558−
559−data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
560− , aliasCreateFilter :: Maybe Filter}
561− deriving (Read, Show, Eq, Generic, Typeable)
562−
563−data AliasRouting = AllAliasRouting RoutingValue
564− | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
565− deriving (Read, Show, Eq, Generic, Typeable)
566−
567−newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Read, Show, Eq, Generic, Typeable)
568−
569−newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
570−
571−newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
572−
573−newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Read, Show, Eq, Generic, Typeable)
574−
575−{-| 'IndexAliasSummary' is a summary of an index alias configured for a server. -}
576−data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
577− , indexAliasSummaryCreate :: IndexAliasCreate} deriving (Read, Show, Eq, Generic, Typeable)
578−
579−{-| 'DocVersion' is an integer version number for a document between 1
580−and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
581−-}
582−newtype DocVersion = DocVersion {
583− docVersionNumber :: Int
584− } deriving (Eq, Read, Show, Generic, Ord, ToJSON)
585−
586−-- | Smart constructor for in-range doc version
587−mkDocVersion :: Int -> Maybe DocVersion
588−mkDocVersion i
589− | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
590− Just $ DocVersion i
591− | otherwise = Nothing
592−
593−
594−{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
595−own version numbers instead of ones from ES.
596−-}
597−newtype ExternalDocVersion = ExternalDocVersion DocVersion
598− deriving (Eq, Read, Show, Generic, Ord, Bounded, Enum, ToJSON)
599−
600−{-| 'VersionControl' is specified when indexing documents as a
601−optimistic concurrency control.
602−-}
603−data VersionControl = NoVersionControl
604− -- ^ Don't send a version. This is a pure overwrite.
605− | InternalVersion DocVersion
606− -- ^ Use the default ES versioning scheme. Only
607− -- index the document if the version is the same
608− -- as the one specified. Only applicable to
609− -- updates, as you should be getting Version from
610− -- a search result.
611− | ExternalGT ExternalDocVersion
612− -- ^ Use your own version numbering. Only index
613− -- the document if the version is strictly higher
614− -- OR the document doesn't exist. The given
615− -- version will be used as the new version number
616− -- for the stored document. N.B. All updates must
617− -- increment this number, meaning there is some
618− -- global, external ordering of updates.
619− | ExternalGTE ExternalDocVersion
620− -- ^ Use your own version numbering. Only index
621− -- the document if the version is equal or higher
622− -- than the stored version. Will succeed if there
623− -- is no existing document. The given version will
624− -- be used as the new version number for the
625− -- stored document. Use with care, as this could
626− -- result in data loss.
627− | ForceVersion ExternalDocVersion
628− -- ^ The document will always be indexed and the
629− -- given version will be the new version. This is
630− -- typically used for correcting errors. Use with
631− -- care, as this could result in data loss.
632− deriving (Read, Show, Eq, Generic, Ord)
633−
634−{-| 'DocumentParent' is used to specify a parent document.
635−-}
636−newtype DocumentParent = DocumentParent DocId
637− deriving (Eq, Read, Show, Generic, Typeable)
638−
639−{-| 'IndexDocumentSettings' are special settings supplied when indexing
640−a document. For the best backwards compatiblity when new fields are
641−added, you should probably prefer to start with 'defaultIndexDocumentSettings'
642−-}
643−data IndexDocumentSettings =
644− IndexDocumentSettings { idsVersionControl :: VersionControl
645− , idsParent :: Maybe DocumentParent
646− } deriving (Eq, Read, Show, Generic, Typeable)
647−
648−{-| Reasonable default settings. Chooses no version control and no parent.
649−-}
650−defaultIndexDocumentSettings :: IndexDocumentSettings
651−defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl Nothing
652−
653−{-| 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order
654− dependent with later sorts acting as tie-breakers for earlier sorts.
655−-}
656−type Sort = [SortSpec]
657−
658−{-| The two main kinds of 'SortSpec' are 'DefaultSortSpec' and
659− 'GeoDistanceSortSpec'. The latter takes a 'SortOrder', 'GeoPoint', and
660− 'DistanceUnit' to express "nearness" to a single geographical point as a
661− sort specification.
662−
663−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
664−-}
665−data SortSpec = DefaultSortSpec DefaultSort
666− | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Read, Show, Generic, Typeable)
667−
668−{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
669− 'mkSort' convenience function for when you want to specify only the most
670− common parameters.
671−
672−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
673−-}
674−data DefaultSort =
675− DefaultSort { sortFieldName :: FieldName
676− , sortOrder :: SortOrder
677− -- default False
678− , ignoreUnmapped :: Bool
679− , sortMode :: Maybe SortMode
680− , missingSort :: Maybe Missing
681− , nestedFilter :: Maybe Filter } deriving (Eq, Read, Show, Generic, Typeable)
682−
683−{-| 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
684− encoded into "asc" or "desc" when turned into JSON.
685−
686−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
687−-}
688−data SortOrder = Ascending
689− | Descending deriving (Eq, Read, Show, Generic, Typeable)
690−
691−{-| 'Missing' prescribes how to handle missing fields. A missing field can be
692− sorted last, first, or using a custom value as a substitute.
693−
694−<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_missing_values>
695−-}
696−data Missing = LastMissing
697− | FirstMissing
698− | CustomMissing Text deriving (Eq, Read, Show, Generic, Typeable)
699−
700−{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
701−
702−http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
703−-}
704−data SortMode = SortMin
705− | SortMax
706− | SortSum
707− | SortAvg deriving (Eq, Read, Show, Generic, Typeable)
708−
709−{-| 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so
710− that you can concisely describe the usual kind of 'SortSpec's you want.
711−-}
712−mkSort :: FieldName -> SortOrder -> DefaultSort
713−mkSort fieldName sOrder = DefaultSort fieldName sOrder False Nothing Nothing Nothing
714−
715−{-| 'Cache' is for telling ES whether it should cache a 'Filter' not.
716− 'Query's cannot be cached.
717−-}
718−type Cache = Bool -- caching on/off
719−defaultCache :: Cache
720−defaultCache = False
721−
722−{-| 'PrefixValue' is used in 'PrefixQuery' as the main query component.
723−-}
724−type PrefixValue = Text
725−
726−{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
727− JSON encoding baked in. Used all over the place.
728−-}
729−data BooleanOperator = And | Or deriving (Eq, Read, Show, Generic, Typeable)
730−
731−{-| 'ShardCount' is part of 'IndexSettings'
732−-}
733−newtype ShardCount = ShardCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
734−
735−{-| 'ReplicaCount' is part of 'IndexSettings'
736−-}
737−newtype ReplicaCount = ReplicaCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
738−
739−{-| 'IndexName' is used to describe which index to query/create/delete
740−-}
741−newtype IndexName = IndexName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
742−
743−{-| 'IndexSelection' is used for APIs which take a single index, a list of
744− indexes, or the special @_all@ index.
745−-}
746−--TODO: this does not fully support <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/multi-index.html multi-index syntax>. It wouldn't be too hard to implement but you'd have to add the optional parameters (ignore_unavailable, allow_no_indices, expand_wildcards) to any APIs using it. Also would be a breaking API.
747−data IndexSelection = IndexList (NonEmpty IndexName)
748− | AllIndexes deriving (Eq, Generic, Show, Typeable)
749−
750−{-| 'NodeSelection' is used for most cluster APIs. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes here> for more details.
751−-}
752−data NodeSelection = LocalNode
753− -- ^ Whatever node receives this request
754− | NodeList (NonEmpty NodeSelector)
755− | AllNodes deriving (Eq, Generic, Show, Typeable)
756−
757−
758−-- | An exact match or pattern to identify a node. Note that All of
759−-- these options support wildcarding, so your node name, server, attr
760−-- name can all contain * characters to be a fuzzy match.
761−data NodeSelector = NodeByName NodeName
762− | NodeByFullNodeId FullNodeId
763− | NodeByHost Server
764− -- ^ e.g. 10.0.0.1 or even 10.0.0.*
765− | NodeByAttribute NodeAttrName Text
766− -- ^ NodeAttrName can be a pattern, e.g. rack*. The value can too.
767− deriving (Eq, Generic, Show, Typeable)
768−
769−{-| 'TemplateName' is used to describe which template to query/create/delete
770−-}
771−newtype TemplateName = TemplateName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
772−
773−{-| 'TemplatePattern' represents a pattern which is matched against index names
774−-}
775−newtype TemplatePattern = TemplatePattern Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
776−
777−{-| 'MappingName' is part of mappings which are how ES describes and schematizes
778− the data in the indices.
779−-}
780−newtype MappingName = MappingName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
781−
782−{-| 'DocId' is a generic wrapper value for expressing unique Document IDs.
783− Can be set by the user or created by ES itself. Often used in client
784− functions for poking at specific documents.
785−-}
786−newtype DocId = DocId Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
787−
788−{-| 'QueryString' is used to wrap query text bodies, be they human written or not.
789−-}
790−newtype QueryString = QueryString Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
791−
792−{-| 'FieldName' is used all over the place wherever a specific field within
793− a document needs to be specified, usually in 'Query's or 'Filter's.
794−-}
795−newtype FieldName = FieldName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
796−
797−
798−{-| 'Script' is often used in place of 'FieldName' to specify more
799−complex ways of extracting a value from a document.
800−-}
801−newtype Script = Script { scriptText :: Text } deriving (Eq, Read, Show, Generic, Typeable)
802−
803−{-| 'CacheName' is used in 'RegexpFilter' for describing the
804− 'CacheKey' keyed caching behavior.
805−-}
806−newtype CacheName = CacheName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
807−
808−{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
809−-}
810−newtype CacheKey =
811− CacheKey Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
812−newtype Existence =
813− Existence Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
814−newtype NullValue =
815− NullValue Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
816−newtype CutoffFrequency =
817− CutoffFrequency Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
818−newtype Analyzer =
819− Analyzer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
820−newtype MaxExpansions =
821− MaxExpansions Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
822−
823−{-| 'Lenient', if set to true, will cause format based failures to be
824− ignored. I don't know what the bloody default is, Elasticsearch
825− documentation didn't say what it was. Let me know if you figure it out.
826−-}
827−newtype Lenient =
828− Lenient Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
829−newtype Tiebreaker =
830− Tiebreaker Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
831−newtype Boost =
832− Boost Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
833−newtype BoostTerms =
834− BoostTerms Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
835−
836−{-| 'MinimumMatch' controls how many should clauses in the bool query should
837− match. Can be an absolute value (2) or a percentage (30%) or a
838− combination of both.
839−-}
840−newtype MinimumMatch =
841− MinimumMatch Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
842−newtype DisableCoord =
843− DisableCoord Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
844−newtype IgnoreTermFrequency =
845− IgnoreTermFrequency Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
846−newtype MinimumTermFrequency =
847− MinimumTermFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
848−newtype MaxQueryTerms =
849− MaxQueryTerms Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
850−newtype Fuzziness =
851− Fuzziness Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
852−
853−{-| 'PrefixLength' is the prefix length used in queries, defaults to 0. -}
854−newtype PrefixLength =
855− PrefixLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
856−newtype TypeName =
857− TypeName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
858−newtype PercentMatch =
859− PercentMatch Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
860−newtype StopWord =
861− StopWord Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
862−newtype QueryPath =
863− QueryPath Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
864−
865−{-| Allowing a wildcard at the beginning of a word (eg "*ing") is particularly
866− heavy, because all terms in the index need to be examined, just in case
867− they match. Leading wildcards can be disabled by setting
868− 'AllowLeadingWildcard' to false. -}
869−newtype AllowLeadingWildcard =
870− AllowLeadingWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
871−newtype LowercaseExpanded =
872− LowercaseExpanded Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
873−newtype EnablePositionIncrements =
874− EnablePositionIncrements Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
875−
876−{-| By default, wildcard terms in a query are not analyzed.
877− Setting 'AnalyzeWildcard' to true enables best-effort analysis.
878−-}
879−newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
880−
881−{-| 'GeneratePhraseQueries' defaults to false.
882−-}
883−newtype GeneratePhraseQueries =
884− GeneratePhraseQueries Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
885−
886−{-| 'Locale' is used for string conversions - defaults to ROOT.
887−-}
888−newtype Locale = Locale Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
889−newtype MaxWordLength = MaxWordLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
890−newtype MinWordLength = MinWordLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
891−
892−{-| 'PhraseSlop' sets the default slop for phrases, 0 means exact
893− phrase matches. Default is 0.
894−-}
895−newtype PhraseSlop = PhraseSlop Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
896−newtype MinDocFrequency = MinDocFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
897−newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
898−
899−-- | Newtype wrapper to parse ES's concerning tendency to in some APIs return a floating point number of milliseconds since epoch ಠ_ಠ
900−newtype POSIXMS = POSIXMS { posixMS :: UTCTime }
901−
902−{-| 'unpackId' is a silly convenience function that gets used once.
903−-}
904−unpackId :: DocId -> Text
905−unpackId (DocId docId) = docId
906−
907type TrackSortScores = Bool
404type TrackSortScores = Bool
908−newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
909−newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
910
405
911data Search = Search { queryBody :: Maybe Query
406data Search = Search { queryBody :: Maybe Query
912 , filterBody :: Maybe Filter
407 , filterBody :: Maybe Filter
@@ -921,7 +416,7 @@ data Search = Search { queryBody :: Maybe Query
921 , fields :: Maybe [FieldName]
416 , fields :: Maybe [FieldName]
922 , source :: Maybe Source
417 , source :: Maybe Source
923 , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
418 , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
924− } deriving (Eq, Read, Show, Generic, Typeable)
419+ } deriving (Eq, Show)
925
420
926data SearchType = SearchTypeQueryThenFetch
421data SearchType = SearchTypeQueryThenFetch
927 | SearchTypeDfsQueryThenFetch
422 | SearchTypeDfsQueryThenFetch
@@ -929,2570 +424,22 @@ data SearchType = SearchTypeQueryThenFetch
929 | SearchTypeScan
424 | SearchTypeScan
930 | SearchTypeQueryAndFetch
425 | SearchTypeQueryAndFetch
931 | SearchTypeDfsQueryAndFetch
426 | SearchTypeDfsQueryAndFetch
932− deriving (Eq, Read, Show, Generic, Typeable)
427+ deriving (Eq, Show)
933−
934−data Source =
935− NoSource
936− | SourcePatterns PatternOrPatterns
937− | SourceIncludeExclude Include Exclude
938− deriving (Read, Show, Eq, Generic, Typeable)
939−
940−data PatternOrPatterns =
941− PopPattern Pattern
942− | PopPatterns [Pattern]
943− deriving (Eq, Read, Show, Generic, Typeable)
944−
945−data Include = Include [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
946−data Exclude = Exclude [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
947−
948−newtype Pattern = Pattern Text deriving (Eq, Read, Show, Generic, Typeable)
949−
950−data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
951− , highlightFields :: [FieldHighlight]
952− } deriving (Read, Show, Eq, Generic, Typeable)
953−
954−data FieldHighlight = FieldHighlight FieldName (Maybe HighlightSettings)
955− deriving (Read, Show, Eq, Generic, Typeable)
956−
957−
958−data HighlightSettings = Plain PlainHighlight
959− | Postings PostingsHighlight
960− | FastVector FastVectorHighlight
961− deriving (Read, Show, Eq, Generic, Typeable)
962−data PlainHighlight =
963− PlainHighlight { plainCommon :: Maybe CommonHighlight
964− , plainNonPost :: Maybe NonPostings } deriving (Read, Show, Eq, Generic, Typeable)
965−
966− -- This requires that index_options are set to 'offset' in the mapping.
967−data PostingsHighlight = PostingsHighlight (Maybe CommonHighlight) deriving (Read, Show, Eq, Generic, Typeable)
968−
969−-- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
970−data FastVectorHighlight =
971− FastVectorHighlight { fvCommon :: Maybe CommonHighlight
972− , fvNonPostSettings :: Maybe NonPostings
973− , boundaryChars :: Maybe Text
974− , boundaryMaxScan :: Maybe Int
975− , fragmentOffset :: Maybe Int
976− , matchedFields :: [Text]
977− , phraseLimit :: Maybe Int
978− } deriving (Read, Show, Eq, Generic, Typeable)
979−
980−data CommonHighlight =
981− CommonHighlight { order :: Maybe Text
982− , forceSource :: Maybe Bool
983− , tag :: Maybe HighlightTag
984− , encoder :: Maybe HighlightEncoder
985− , noMatchSize :: Maybe Int
986− , highlightQuery :: Maybe Query
987− , requireFieldMatch :: Maybe Bool
988− } deriving (Read, Show, Eq, Generic, Typeable)
989−
990−-- Settings that are only applicable to FastVector and Plain highlighters.
991−data NonPostings =
992− NonPostings { fragmentSize :: Maybe Int
993− , numberOfFragments :: Maybe Int} deriving (Read, Show, Eq, Generic, Typeable)
994−
995−data HighlightEncoder = DefaultEncoder
996− | HTMLEncoder
997− deriving (Read, Show, Eq, Generic, Typeable)
998−
999−-- NOTE: Should the tags use some kind of HTML type, rather than Text?
1000−data HighlightTag = TagSchema Text
1001− | CustomTags ([Text], [Text]) -- Only uses more than the first value in the lists if fvh
1002− deriving (Read, Show, Eq, Generic, Typeable)
1003−
1004−
1005−data Query =
1006− TermQuery Term (Maybe Boost)
1007− | TermsQuery Text (NonEmpty Text)
1008− | QueryMatchQuery MatchQuery
1009− | QueryMultiMatchQuery MultiMatchQuery
1010− | QueryBoolQuery BoolQuery
1011− | QueryBoostingQuery BoostingQuery
1012− | QueryCommonTermsQuery CommonTermsQuery
1013− | ConstantScoreFilter Filter Boost
1014− | ConstantScoreQuery Query Boost
1015− | QueryDisMaxQuery DisMaxQuery
1016− | QueryFilteredQuery FilteredQuery
1017− | QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
1018− | QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
1019− | QueryFuzzyQuery FuzzyQuery
1020− | QueryHasChildQuery HasChildQuery
1021− | QueryHasParentQuery HasParentQuery
1022− | IdsQuery MappingName [DocId]
1023− | QueryIndicesQuery IndicesQuery
1024− | MatchAllQuery (Maybe Boost)
1025− | QueryMoreLikeThisQuery MoreLikeThisQuery
1026− | QueryMoreLikeThisFieldQuery MoreLikeThisFieldQuery
1027− | QueryNestedQuery NestedQuery
1028− | QueryPrefixQuery PrefixQuery
1029− | QueryQueryStringQuery QueryStringQuery
1030− | QuerySimpleQueryStringQuery SimpleQueryStringQuery
1031− | QueryRangeQuery RangeQuery
1032− | QueryRegexpQuery RegexpQuery
1033− | QueryTemplateQueryInline TemplateQueryInline
1034− deriving (Eq, Read, Show, Generic, Typeable)
1035−
1036−data RegexpQuery =
1037− RegexpQuery { regexpQueryField :: FieldName
1038− , regexpQuery :: Regexp
1039− , regexpQueryFlags :: RegexpFlags
1040− , regexpQueryBoost :: Maybe Boost
1041− } deriving (Eq, Read, Show, Generic, Typeable)
1042−
1043−data RangeQuery =
1044− RangeQuery { rangeQueryField :: FieldName
1045− , rangeQueryRange :: RangeValue
1046− , rangeQueryBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1047−
1048−mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
1049−mkRangeQuery f r = RangeQuery f r (Boost 1.0)
1050−
1051−data SimpleQueryStringQuery =
1052− SimpleQueryStringQuery
1053− { simpleQueryStringQuery :: QueryString
1054− , simpleQueryStringField :: Maybe FieldOrFields
1055− , simpleQueryStringOperator :: Maybe BooleanOperator
1056− , simpleQueryStringAnalyzer :: Maybe Analyzer
1057− , simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag)
1058− , simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded
1059− , simpleQueryStringLocale :: Maybe Locale
1060− } deriving (Eq, Read, Show, Generic, Typeable)
1061−
1062−data SimpleQueryFlag =
1063− SimpleQueryAll
1064− | SimpleQueryNone
1065− | SimpleQueryAnd
1066− | SimpleQueryOr
1067− | SimpleQueryPrefix
1068− | SimpleQueryPhrase
1069− | SimpleQueryPrecedence
1070− | SimpleQueryEscape
1071− | SimpleQueryWhitespace
1072− | SimpleQueryFuzzy
1073− | SimpleQueryNear
1074− | SimpleQuerySlop deriving (Eq, Read, Show, Generic, Typeable)
1075−
1076−-- use_dis_max and tie_breaker when fields are plural?
1077−data QueryStringQuery =
1078− QueryStringQuery
1079− { queryStringQuery :: QueryString
1080− , queryStringDefaultField :: Maybe FieldName
1081− , queryStringOperator :: Maybe BooleanOperator
1082− , queryStringAnalyzer :: Maybe Analyzer
1083− , queryStringAllowLeadingWildcard :: Maybe AllowLeadingWildcard
1084− , queryStringLowercaseExpanded :: Maybe LowercaseExpanded
1085− , queryStringEnablePositionIncrements :: Maybe EnablePositionIncrements
1086− , queryStringFuzzyMaxExpansions :: Maybe MaxExpansions
1087− , queryStringFuzziness :: Maybe Fuzziness
1088− , queryStringFuzzyPrefixLength :: Maybe PrefixLength
1089− , queryStringPhraseSlop :: Maybe PhraseSlop
1090− , queryStringBoost :: Maybe Boost
1091− , queryStringAnalyzeWildcard :: Maybe AnalyzeWildcard
1092− , queryStringGeneratePhraseQueries :: Maybe GeneratePhraseQueries
1093− , queryStringMinimumShouldMatch :: Maybe MinimumMatch
1094− , queryStringLenient :: Maybe Lenient
1095− , queryStringLocale :: Maybe Locale
1096− } deriving (Eq, Read, Show, Generic, Typeable)
1097−
1098−mkQueryStringQuery :: QueryString -> QueryStringQuery
1099−mkQueryStringQuery qs =
1100− QueryStringQuery qs Nothing Nothing
1101− Nothing Nothing Nothing Nothing
1102− Nothing Nothing Nothing Nothing
1103− Nothing Nothing Nothing Nothing
1104− Nothing Nothing
1105−
1106−data FieldOrFields = FofField FieldName
1107− | FofFields (NonEmpty FieldName) deriving (Eq, Read, Show, Generic, Typeable)
1108−
1109−data PrefixQuery =
1110− PrefixQuery
1111− { prefixQueryField :: FieldName
1112− , prefixQueryPrefixValue :: Text
1113− , prefixQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1114−
1115−data NestedQuery =
1116− NestedQuery
1117− { nestedQueryPath :: QueryPath
1118− , nestedQueryScoreType :: ScoreType
1119− , nestedQuery :: Query } deriving (Eq, Read, Show, Generic, Typeable)
1120−
1121−data MoreLikeThisFieldQuery =
1122− MoreLikeThisFieldQuery
1123− { moreLikeThisFieldText :: Text
1124− , moreLikeThisFieldFields :: FieldName
1125− -- default 0.3 (30%)
1126− , moreLikeThisFieldPercentMatch :: Maybe PercentMatch
1127− , moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency
1128− , moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms
1129− , moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord)
1130− , moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency
1131− , moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency
1132− , moreLikeThisFieldMinWordLength :: Maybe MinWordLength
1133− , moreLikeThisFieldMaxWordLength :: Maybe MaxWordLength
1134− , moreLikeThisFieldBoostTerms :: Maybe BoostTerms
1135− , moreLikeThisFieldBoost :: Maybe Boost
1136− , moreLikeThisFieldAnalyzer :: Maybe Analyzer
1137− } deriving (Eq, Read, Show, Generic, Typeable)
1138−
1139−data MoreLikeThisQuery =
1140− MoreLikeThisQuery
1141− { moreLikeThisText :: Text
1142− , moreLikeThisFields :: Maybe (NonEmpty FieldName)
1143− -- default 0.3 (30%)
1144− , moreLikeThisPercentMatch :: Maybe PercentMatch
1145− , moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency
1146− , moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms
1147− , moreLikeThisStopWords :: Maybe (NonEmpty StopWord)
1148− , moreLikeThisMinDocFrequency :: Maybe MinDocFrequency
1149− , moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency
1150− , moreLikeThisMinWordLength :: Maybe MinWordLength
1151− , moreLikeThisMaxWordLength :: Maybe MaxWordLength
1152− , moreLikeThisBoostTerms :: Maybe BoostTerms
1153− , moreLikeThisBoost :: Maybe Boost
1154− , moreLikeThisAnalyzer :: Maybe Analyzer
1155− } deriving (Eq, Read, Show, Generic, Typeable)
1156−
1157−data IndicesQuery =
1158− IndicesQuery
1159− { indicesQueryIndices :: [IndexName]
1160− , indicesQuery :: Query
1161− -- default "all"
1162− , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Read, Show, Generic, Typeable)
1163−
1164−data HasParentQuery =
1165− HasParentQuery
1166− { hasParentQueryType :: TypeName
1167− , hasParentQuery :: Query
1168− , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1169−
1170−data HasChildQuery =
1171− HasChildQuery
1172− { hasChildQueryType :: TypeName
1173− , hasChildQuery :: Query
1174− , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1175−
1176−data ScoreType =
1177− ScoreTypeMax
1178− | ScoreTypeSum
1179− | ScoreTypeAvg
1180− | ScoreTypeNone deriving (Eq, Read, Show, Generic, Typeable)
1181−
1182−data FuzzyQuery =
1183− FuzzyQuery { fuzzyQueryField :: FieldName
1184− , fuzzyQueryValue :: Text
1185− , fuzzyQueryPrefixLength :: PrefixLength
1186− , fuzzyQueryMaxExpansions :: MaxExpansions
1187− , fuzzyQueryFuzziness :: Fuzziness
1188− , fuzzyQueryBoost :: Maybe Boost
1189− } deriving (Eq, Read, Show, Generic, Typeable)
1190
428
1191−data FuzzyLikeFieldQuery =
429+instance ToJSON Search where
1192− FuzzyLikeFieldQuery
430+ toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource sSuggest) =
1193− { fuzzyLikeField :: FieldName
431+ omitNulls [ "query" .= query
1194− -- anaphora is good for the soul.
432+ , "filter" .= sFilter
1195− , fuzzyLikeFieldText :: Text
433+ , "sort" .= sort
1196− , fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms
434+ , "aggregations" .= searchAggs
1197− , fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency
435+ , "highlight" .= highlight
1198− , fuzzyLikeFieldFuzziness :: Fuzziness
436+ , "from" .= sFrom
1199− , fuzzyLikeFieldPrefixLength :: PrefixLength
437+ , "size" .= sSize
1200− , fuzzyLikeFieldBoost :: Boost
438+ , "track_scores" .= sTrackSortScores
1201− , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
439+ , "fields" .= sFields
1202− } deriving (Eq, Read, Show, Generic, Typeable)
440+ , "_source" .= sSource
1203−
441+ , "suggest" .= sSuggest]
1204−data FuzzyLikeThisQuery =
1205− FuzzyLikeThisQuery
1206− { fuzzyLikeFields :: [FieldName]
1207− , fuzzyLikeText :: Text
1208− , fuzzyLikeMaxQueryTerms :: MaxQueryTerms
1209− , fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency
1210− , fuzzyLikeFuzziness :: Fuzziness
1211− , fuzzyLikePrefixLength :: PrefixLength
1212− , fuzzyLikeBoost :: Boost
1213− , fuzzyLikeAnalyzer :: Maybe Analyzer
1214− } deriving (Eq, Read, Show, Generic, Typeable)
1215−
1216−data FilteredQuery =
1217− FilteredQuery
1218− { filteredQuery :: Query
1219− , filteredFilter :: Filter } deriving (Eq, Read, Show, Generic, Typeable)
1220−
1221−data DisMaxQuery =
1222− DisMaxQuery { disMaxQueries :: [Query]
1223− -- default 0.0
1224− , disMaxTiebreaker :: Tiebreaker
1225− , disMaxBoost :: Maybe Boost
1226− } deriving (Eq, Read, Show, Generic, Typeable)
1227−
1228−data MatchQuery =
1229− MatchQuery { matchQueryField :: FieldName
1230− , matchQueryQueryString :: QueryString
1231− , matchQueryOperator :: BooleanOperator
1232− , matchQueryZeroTerms :: ZeroTermsQuery
1233− , matchQueryCutoffFrequency :: Maybe CutoffFrequency
1234− , matchQueryMatchType :: Maybe MatchQueryType
1235− , matchQueryAnalyzer :: Maybe Analyzer
1236− , matchQueryMaxExpansions :: Maybe MaxExpansions
1237− , matchQueryLenient :: Maybe Lenient
1238− , matchQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1239−
1240−{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
1241− enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
1242−-}
1243−mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1244−mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1245−
1246−data MatchQueryType =
1247− MatchPhrase
1248− | MatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
1249−
1250−data MultiMatchQuery =
1251− MultiMatchQuery { multiMatchQueryFields :: [FieldName]
1252− , multiMatchQueryString :: QueryString
1253− , multiMatchQueryOperator :: BooleanOperator
1254− , multiMatchQueryZeroTerms :: ZeroTermsQuery
1255− , multiMatchQueryTiebreaker :: Maybe Tiebreaker
1256− , multiMatchQueryType :: Maybe MultiMatchQueryType
1257− , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
1258− , multiMatchQueryAnalyzer :: Maybe Analyzer
1259− , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
1260− , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Read, Show, Generic, Typeable)
1261−
1262−{-| 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
1263− enabling you to provide only the list of 'FieldName's and 'QueryString' to
1264− make a 'MultiMatchQuery'.
1265−-}
1266−
1267−mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
1268−mkMultiMatchQuery matchFields query =
1269− MultiMatchQuery matchFields query
1270− Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1271−
1272−data MultiMatchQueryType =
1273− MultiMatchBestFields
1274− | MultiMatchMostFields
1275− | MultiMatchCrossFields
1276− | MultiMatchPhrase
1277− | MultiMatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
1278−
1279−data BoolQuery =
1280− BoolQuery { boolQueryMustMatch :: [Query]
1281− , boolQueryMustNotMatch :: [Query]
1282− , boolQueryShouldMatch :: [Query]
1283− , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
1284− , boolQueryBoost :: Maybe Boost
1285− , boolQueryDisableCoord :: Maybe DisableCoord
1286− } deriving (Eq, Read, Show, Generic, Typeable)
1287−
1288−mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
1289−mkBoolQuery must mustNot should =
1290− BoolQuery must mustNot should Nothing Nothing Nothing
1291−
1292−data BoostingQuery =
1293− BoostingQuery { positiveQuery :: Query
1294− , negativeQuery :: Query
1295− , negativeBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1296−
1297−data CommonTermsQuery =
1298− CommonTermsQuery { commonField :: FieldName
1299− , commonQuery :: QueryString
1300− , commonCutoffFrequency :: CutoffFrequency
1301− , commonLowFreqOperator :: BooleanOperator
1302− , commonHighFreqOperator :: BooleanOperator
1303− , commonMinimumShouldMatch :: Maybe CommonMinimumMatch
1304− , commonBoost :: Maybe Boost
1305− , commonAnalyzer :: Maybe Analyzer
1306− , commonDisableCoord :: Maybe DisableCoord
1307− } deriving (Eq, Read, Show, Generic, Typeable)
1308−
1309−data CommonMinimumMatch =
1310− CommonMinimumMatchHighLow MinimumMatchHighLow
1311− | CommonMinimumMatch MinimumMatch
1312− deriving (Eq, Read, Show, Generic, Typeable)
1313−
1314−data MinimumMatchHighLow =
1315− MinimumMatchHighLow { lowFreq :: MinimumMatch
1316− , highFreq :: MinimumMatch } deriving (Eq, Read, Show, Generic, Typeable)
1317−
1318−data Filter = AndFilter [Filter] Cache
1319− | OrFilter [Filter] Cache
1320− | NotFilter Filter Cache
1321− | IdentityFilter
1322− | BoolFilter BoolMatch
1323− | ExistsFilter FieldName -- always cached
1324− | GeoBoundingBoxFilter GeoBoundingBoxConstraint
1325− | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
1326− | GeoDistanceRangeFilter GeoPoint DistanceRange
1327− | GeoPolygonFilter FieldName [LatLon]
1328− | IdsFilter MappingName [DocId]
1329− | LimitFilter Int
1330− | MissingFilter FieldName Existence NullValue
1331− | PrefixFilter FieldName PrefixValue Cache
1332− | QueryFilter Query Cache
1333− | RangeFilter FieldName RangeValue RangeExecution Cache
1334− | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
1335− | TermFilter Term Cache
1336− deriving (Eq, Read, Show, Generic, Typeable)
1337−
1338−data ZeroTermsQuery = ZeroTermsNone
1339− | ZeroTermsAll deriving (Eq, Read, Show, Generic, Typeable)
1340−
1341−data RangeExecution = RangeExecutionIndex
1342− | RangeExecutionFielddata deriving (Eq, Read, Show, Generic, Typeable)
1343−
1344−newtype Regexp = Regexp Text deriving (Eq, Read, Show, Generic, Typeable, FromJSON)
1345−
1346−data RegexpFlags = AllRegexpFlags
1347− | NoRegexpFlags
1348− | SomeRegexpFlags (NonEmpty RegexpFlag) deriving (Eq, Read, Show, Generic, Typeable)
1349−
1350−data RegexpFlag = AnyString
1351− | Automaton
1352− | Complement
1353− | Empty
1354− | Intersection
1355− | Interval deriving (Eq, Read, Show, Generic, Typeable)
1356−
1357−newtype LessThan = LessThan Double deriving (Eq, Read, Show, Generic, Typeable)
1358−newtype LessThanEq = LessThanEq Double deriving (Eq, Read, Show, Generic, Typeable)
1359−newtype GreaterThan = GreaterThan Double deriving (Eq, Read, Show, Generic, Typeable)
1360−newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Read, Show, Generic, Typeable)
1361−
1362−newtype LessThanD = LessThanD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1363−newtype LessThanEqD = LessThanEqD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1364−newtype GreaterThanD = GreaterThanD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1365−newtype GreaterThanEqD = GreaterThanEqD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1366−
1367−data RangeValue = RangeDateLte LessThanEqD
1368− | RangeDateLt LessThanD
1369− | RangeDateGte GreaterThanEqD
1370− | RangeDateGt GreaterThanD
1371− | RangeDateGtLt GreaterThanD LessThanD
1372− | RangeDateGteLte GreaterThanEqD LessThanEqD
1373− | RangeDateGteLt GreaterThanEqD LessThanD
1374− | RangeDateGtLte GreaterThanD LessThanEqD
1375− | RangeDoubleLte LessThanEq
1376− | RangeDoubleLt LessThan
1377− | RangeDoubleGte GreaterThanEq
1378− | RangeDoubleGt GreaterThan
1379− | RangeDoubleGtLt GreaterThan LessThan
1380− | RangeDoubleGteLte GreaterThanEq LessThanEq
1381− | RangeDoubleGteLt GreaterThanEq LessThan
1382− | RangeDoubleGtLte GreaterThan LessThanEq
1383− deriving (Eq, Read, Show, Generic, Typeable)
1384−
1385−rangeValueToPair :: RangeValue -> [Pair]
1386−rangeValueToPair rv = case rv of
1387− RangeDateLte (LessThanEqD t) -> ["lte" .= t]
1388− RangeDateGte (GreaterThanEqD t) -> ["gte" .= t]
1389− RangeDateLt (LessThanD t) -> ["lt" .= t]
1390− RangeDateGt (GreaterThanD t) -> ["gt" .= t]
1391− RangeDateGteLte (GreaterThanEqD l) (LessThanEqD g) -> ["gte" .= l, "lte" .= g]
1392− RangeDateGtLte (GreaterThanD l) (LessThanEqD g) -> ["gt" .= l, "lte" .= g]
1393− RangeDateGteLt (GreaterThanEqD l) (LessThanD g) -> ["gte" .= l, "lt" .= g]
1394− RangeDateGtLt (GreaterThanD l) (LessThanD g) -> ["gt" .= l, "lt" .= g]
1395− RangeDoubleLte (LessThanEq t) -> ["lte" .= t]
1396− RangeDoubleGte (GreaterThanEq t) -> ["gte" .= t]
1397− RangeDoubleLt (LessThan t) -> ["lt" .= t]
1398− RangeDoubleGt (GreaterThan t) -> ["gt" .= t]
1399− RangeDoubleGteLte (GreaterThanEq l) (LessThanEq g) -> ["gte" .= l, "lte" .= g]
1400− RangeDoubleGtLte (GreaterThan l) (LessThanEq g) -> ["gt" .= l, "lte" .= g]
1401− RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g]
1402− RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
1403−
1404−data Term = Term { termField :: Text
1405− , termValue :: Text } deriving (Eq, Read, Show, Generic, Typeable)
1406−
1407−data BoolMatch = MustMatch Term Cache
1408− | MustNotMatch Term Cache
1409− | ShouldMatch [Term] Cache deriving (Eq, Read, Show, Generic, Typeable)
1410−
1411−-- "memory" or "indexed"
1412−data GeoFilterType = GeoFilterMemory
1413− | GeoFilterIndexed deriving (Eq, Read, Show, Generic, Typeable)
1414−
1415−data LatLon = LatLon { lat :: Double
1416− , lon :: Double } deriving (Eq, Read, Show, Generic, Typeable)
1417−
1418−data GeoBoundingBox =
1419− GeoBoundingBox { topLeft :: LatLon
1420− , bottomRight :: LatLon } deriving (Eq, Read, Show, Generic, Typeable)
1421−
1422−data GeoBoundingBoxConstraint =
1423− GeoBoundingBoxConstraint { geoBBField :: FieldName
1424− , constraintBox :: GeoBoundingBox
1425− , bbConstraintcache :: Cache
1426− , geoType :: GeoFilterType
1427− } deriving (Eq, Read, Show, Generic, Typeable)
1428−
1429−data GeoPoint =
1430− GeoPoint { geoField :: FieldName
1431− , latLon :: LatLon} deriving (Eq, Read, Show, Generic, Typeable)
1432−
1433−data DistanceUnit = Miles
1434− | Yards
1435− | Feet
1436− | Inches
1437− | Kilometers
1438− | Meters
1439− | Centimeters
1440− | Millimeters
1441− | NauticalMiles deriving (Eq, Read, Show, Generic, Typeable)
1442−
1443−data DistanceType = Arc
1444− | SloppyArc -- doesn't exist <1.0
1445− | Plane deriving (Eq, Read, Show, Generic, Typeable)
1446−
1447−data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
1448− | NoOptimizeBbox deriving (Eq, Read, Show, Generic, Typeable)
1449−
1450−data Distance =
1451− Distance { coefficient :: Double
1452− , unit :: DistanceUnit } deriving (Eq, Read, Show, Generic, Typeable)
1453−
1454−data DistanceRange =
1455− DistanceRange { distanceFrom :: Distance
1456− , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
1457−
1458−type TemplateQueryKey = Text
1459−type TemplateQueryValue = Text
1460−
1461−newtype TemplateQueryKeyValuePairs = TemplateQueryKeyValuePairs (HM.HashMap TemplateQueryKey TemplateQueryValue)
1462− deriving (Eq, Read, Show, Generic, Typeable)
1463−
1464−instance ToJSON TemplateQueryKeyValuePairs where
1465− toJSON (TemplateQueryKeyValuePairs x) = Object $ HM.map toJSON x
1466−
1467−instance FromJSON TemplateQueryKeyValuePairs where
1468− parseJSON (Object o) = pure . TemplateQueryKeyValuePairs $ HM.mapMaybe getValue o
1469− where getValue (String x) = Just x
1470− getValue _ = Nothing
1471− parseJSON _ = fail "error parsing TemplateQueryKeyValuePairs"
1472−
1473−data TemplateQueryInline =
1474− TemplateQueryInline { inline :: Query
1475− , params :: TemplateQueryKeyValuePairs
1476− }
1477− deriving (Eq, Read, Show, Generic, Typeable)
1478−
1479−instance ToJSON TemplateQueryInline where
1480− toJSON TemplateQueryInline{..} = object [ "query" .= inline
1481− , "params" .= params
1482− ]
1483−
1484−instance FromJSON TemplateQueryInline where
1485− parseJSON = withObject "TemplateQueryInline" parse
1486− where parse o = TemplateQueryInline
1487− <$> o .: "query"
1488− <*> o .: "params"
1489−
1490−data SearchResult a =
1491− SearchResult { took :: Int
1492− , timedOut :: Bool
1493− , shards :: ShardResult
1494− , searchHits :: SearchHits a
1495− , aggregations :: Maybe AggregationResults
1496− , scrollId :: Maybe ScrollId
1497− , suggest :: Maybe NamedSuggestionResponse -- ^ Only one Suggestion request / response per Search is supported.
1498− }
1499− deriving (Eq, Read, Show, Generic, Typeable)
1500−
1501−newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
1502−
1503−type Score = Maybe Double
1504−
1505−data SearchHits a =
1506− SearchHits { hitsTotal :: Int
1507− , maxScore :: Score
1508− , hits :: [Hit a] } deriving (Eq, Read, Show, Generic, Typeable)
1509−
1510−instance Semigroup (SearchHits a) where
1511− (SearchHits ta ma ha) <> (SearchHits tb mb hb) = SearchHits (ta + tb) (max ma mb) (ha <> hb)
1512−
1513−instance Monoid (SearchHits a) where
1514− mempty = SearchHits 0 Nothing mempty
1515− mappend = (<>)
1516−
1517−data Hit a =
1518− Hit { hitIndex :: IndexName
1519− , hitType :: MappingName
1520− , hitDocId :: DocId
1521− , hitScore :: Score
1522− , hitSource :: Maybe a
1523− , hitHighlight :: Maybe HitHighlight } deriving (Eq, Read, Show, Generic, Typeable)
1524−
1525−data ShardResult =
1526− ShardResult { shardTotal :: Int
1527− , shardsSuccessful :: Int
1528− , shardsFailed :: Int } deriving (Eq, Read, Show, Generic, Typeable)
1529−
1530−type HitHighlight = M.Map Text [Text]
1531−
1532−showText :: Show a => a -> Text
1533−showText = T.pack . show
1534−
1535−readMay :: Read a => String -> Maybe a
1536−readMay s = case reads s of
1537− (a, ""):_ -> Just a
1538− _ -> Nothing
1539−
1540−parseReadText :: Read a => Text -> Parser a
1541−parseReadText = maybe mzero return . readMay . T.unpack
1542−
1543−
1544−data TermOrder = TermOrder{ termSortField :: Text
1545− , termSortOrder :: SortOrder } deriving (Eq, Read, Show, Generic, Typeable)
1546−
1547−data TermInclusion = TermInclusion Text
1548− | TermPattern Text Text deriving (Eq, Read, Show, Generic, Typeable)
1549−
1550−data CollectionMode = BreadthFirst
1551− | DepthFirst deriving (Eq, Read, Show, Generic, Typeable)
1552−
1553−data ExecutionHint = Ordinals
1554− | GlobalOrdinals
1555− | GlobalOrdinalsHash
1556− | GlobalOrdinalsLowCardinality
1557− | Map deriving (Eq, Read, Show, Generic, Typeable)
1558−
1559−data TimeInterval = Weeks
1560− | Days
1561− | Hours
1562− | Minutes
1563− | Seconds deriving Eq
1564−
1565−data Interval = Year
1566− | Quarter
1567− | Month
1568− | Week
1569− | Day
1570− | Hour
1571− | Minute
1572− | Second
1573− | FractionalInterval Float TimeInterval deriving (Eq, Read, Show, Generic, Typeable)
1574−
1575−
1576−-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math> for more information.
1577−data DateMathExpr = DateMathExpr DateMathAnchor [DateMathModifier] deriving (Eq, Read, Show, Generic, Typeable)
1578−
1579−
1580−-- | Starting point for a date range. This along with the 'DateMathModifiers' gets you the date ES will start from.
1581−data DateMathAnchor = DMNow
1582− | DMDate Day deriving (Eq, Read, Show, Generic, Typeable)
1583−
1584−data DateMathModifier = AddTime Int DateMathUnit
1585− | SubtractTime Int DateMathUnit
1586− | RoundDownTo DateMathUnit deriving (Eq, Read, Show, Generic, Typeable)
1587−
1588−data DateMathUnit = DMYear
1589− | DMMonth
1590− | DMWeek
1591− | DMDay
1592− | DMHour
1593− | DMMinute
1594− | DMSecond deriving (Eq, Read, Show, Generic, Typeable)
1595−
1596−instance ToJSON Version where
1597− toJSON Version {..} = object ["number" .= number
1598− ,"build_hash" .= build_hash
1599− ,"build_timestamp" .= build_timestamp
1600− ,"build_snapshot" .= build_snapshot
1601− ,"lucene_version" .= lucene_version]
1602−
1603−instance FromJSON Version where
1604− parseJSON = withObject "Version" parse
1605− where parse o = Version
1606− <$> o .: "number"
1607− <*> o .: "build_hash"
1608− <*> o .: "build_timestamp"
1609− <*> o .: "build_snapshot"
1610− <*> o .: "lucene_version"
1611−
1612−instance ToJSON VersionNumber where
1613− toJSON = toJSON . Vers.showVersion . versionNumber
1614−
1615−instance FromJSON VersionNumber where
1616− parseJSON = withText "VersionNumber" (parse . T.unpack)
1617− where
1618− parse s = case filter (null . snd)(RP.readP_to_S Vers.parseVersion s) of
1619− [(v, _)] -> pure (VersionNumber v)
1620− [] -> fail ("Invalid version string " ++ s)
1621− xs -> fail ("Ambiguous version string " ++ s ++ " (" ++ intercalate ", " (Vers.showVersion . fst <$> xs) ++ ")")
1622−
1623−instance ToJSON TermOrder where
1624− toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
1625−
1626−instance ToJSON TermInclusion where
1627− toJSON (TermInclusion x) = toJSON x
1628− toJSON (TermPattern pattern flags) =
1629− omitNulls [ "pattern" .= pattern
1630− , "flags" .= flags]
1631−
1632−instance ToJSON CollectionMode where
1633− toJSON BreadthFirst = "breadth_first"
1634− toJSON DepthFirst = "depth_first"
1635−
1636−instance ToJSON ExecutionHint where
1637− toJSON Ordinals = "ordinals"
1638− toJSON GlobalOrdinals = "global_ordinals"
1639− toJSON GlobalOrdinalsHash = "global_ordinals_hash"
1640− toJSON GlobalOrdinalsLowCardinality = "global_ordinals_low_cardinality"
1641− toJSON Map = "map"
1642−
1643−instance ToJSON Interval where
1644− toJSON Year = "year"
1645− toJSON Quarter = "quarter"
1646− toJSON Month = "month"
1647− toJSON Week = "week"
1648− toJSON Day = "day"
1649− toJSON Hour = "hour"
1650− toJSON Minute = "minute"
1651− toJSON Second = "second"
1652− toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1653−
1654−instance Show TimeInterval where
1655− show Weeks = "w"
1656− show Days = "d"
1657− show Hours = "h"
1658− show Minutes = "m"
1659− show Seconds = "s"
1660−
1661−instance Read TimeInterval where
1662− readPrec = f =<< TR.get
1663− where
1664− f 'w' = return Weeks
1665− f 'd' = return Days
1666− f 'h' = return Hours
1667− f 'm' = return Minutes
1668− f 's' = return Seconds
1669− f _ = fail "TimeInterval expected one of w, d, h, m, s"
1670−
1671−
1672−instance ToJSON DateRangeAggregation where
1673− toJSON DateRangeAggregation {..} =
1674− omitNulls [ "field" .= draField
1675− , "format" .= draFormat
1676− , "ranges" .= toList draRanges
1677− ]
1678−
1679−instance ToJSON DateRangeAggRange where
1680− toJSON (DateRangeFrom e) = object [ "from" .= e ]
1681− toJSON (DateRangeTo e) = object [ "to" .= e ]
1682− toJSON (DateRangeFromAndTo f t) = object [ "from" .= f, "to" .= t ]
1683−
1684−instance ToJSON DateMathExpr where
1685− toJSON (DateMathExpr a mods) = String (fmtA a <> mconcat (fmtMod <$> mods))
1686− where fmtA DMNow = "now"
1687− fmtA (DMDate date) = (T.pack $ showGregorian date) <> "||"
1688− fmtMod (AddTime n u) = "+" <> showText n <> fmtU u
1689− fmtMod (SubtractTime n u) = "-" <> showText n <> fmtU u
1690− fmtMod (RoundDownTo u) = "/" <> fmtU u
1691− fmtU DMYear = "y"
1692− fmtU DMMonth = "M"
1693− fmtU DMWeek = "w"
1694− fmtU DMDay = "d"
1695− fmtU DMHour = "h"
1696− fmtU DMMinute = "m"
1697− fmtU DMSecond = "s"
1698−
1699−
1700−type AggregationResults = M.Map Text Value
1701−
1702−class BucketAggregation a where
1703− key :: a -> BucketValue
1704− docCount :: a -> Int
1705− aggs :: a -> Maybe AggregationResults
1706−
1707−
1708−data Bucket a = Bucket { buckets :: [a]} deriving (Read, Show)
1709−
1710−data BucketValue = TextValue Text
1711− | ScientificValue Scientific
1712− | BoolValue Bool deriving (Read, Show)
1713−
1714−data MissingResult = MissingResult { missingDocCount :: Int } deriving (Show)
1715−
1716−data TopHitResult a = TopHitResult { tarHits :: (SearchHits a)
1717− } deriving Show
1718−
1719−data TermsResult = TermsResult { termKey :: BucketValue
1720− , termsDocCount :: Int
1721− , termsAggs :: Maybe AggregationResults } deriving (Read, Show)
1722−
1723−data DateHistogramResult = DateHistogramResult { dateKey :: Int
1724− , dateKeyStr :: Maybe Text
1725− , dateDocCount :: Int
1726− , dateHistogramAggs :: Maybe AggregationResults } deriving (Read, Show)
1727−
1728−data DateRangeResult = DateRangeResult { dateRangeKey :: Text
1729− , dateRangeFrom :: Maybe UTCTime
1730− , dateRangeFromAsString :: Maybe Text
1731− , dateRangeTo :: Maybe UTCTime
1732− , dateRangeToAsString :: Maybe Text
1733− , dateRangeDocCount :: Int
1734− , dateRangeAggs :: Maybe AggregationResults } deriving (Read, Show, Eq, Generic, Typeable)
1735−
1736−toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
1737−toTerms = toAggResult
1738−
1739−toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
1740−toDateHistogram = toAggResult
1741−
1742−toMissing :: Text -> AggregationResults -> Maybe MissingResult
1743−toMissing = toAggResult
1744−
1745−toTopHits :: (FromJSON a) => Text -> AggregationResults -> Maybe (TopHitResult a)
1746−toTopHits = toAggResult
1747−
1748−toAggResult :: (FromJSON a) => Text -> AggregationResults -> Maybe a
1749−toAggResult t a = M.lookup t a >>= deserialize
1750− where deserialize = parseMaybe parseJSON
1751−
1752−instance BucketAggregation TermsResult where
1753− key = termKey
1754− docCount = termsDocCount
1755− aggs = termsAggs
1756−
1757−instance BucketAggregation DateHistogramResult where
1758− key = TextValue . showText . dateKey
1759− docCount = dateDocCount
1760− aggs = dateHistogramAggs
1761−
1762−instance BucketAggregation DateRangeResult where
1763− key = TextValue . dateRangeKey
1764− docCount = dateRangeDocCount
1765− aggs = dateRangeAggs
1766−
1767−instance (FromJSON a) => FromJSON (Bucket a) where
1768− parseJSON (Object v) = Bucket <$>
1769− v .: "buckets"
1770− parseJSON _ = mempty
1771−
1772−instance FromJSON BucketValue where
1773− parseJSON (String t) = return $ TextValue t
1774− parseJSON (Number s) = return $ ScientificValue s
1775− parseJSON (Bool b) = return $ BoolValue b
1776− parseJSON _ = mempty
1777
442
1778−instance FromJSON MissingResult where
1779− parseJSON = withObject "MissingResult" parse
1780− where parse v = MissingResult <$> v .: "doc_count"
1781−
1782−instance FromJSON TermsResult where
1783− parseJSON (Object v) = TermsResult <$>
1784− v .: "key" <*>
1785− v .: "doc_count" <*>
1786− (pure $ getNamedSubAgg v ["key", "doc_count"])
1787− parseJSON _ = mempty
1788−
1789−instance FromJSON DateHistogramResult where
1790− parseJSON (Object v) = DateHistogramResult <$>
1791− v .: "key" <*>
1792− v .:? "key_as_string" <*>
1793− v .: "doc_count" <*>
1794− (pure $ getNamedSubAgg v [ "key"
1795− , "doc_count"
1796− , "key_as_string"
1797− ]
1798− )
1799− parseJSON _ = mempty
1800−
1801−instance FromJSON DateRangeResult where
1802− parseJSON = withObject "DateRangeResult" parse
1803− where parse v = DateRangeResult <$>
1804− v .: "key" <*>
1805− (fmap posixMS <$> v .:? "from") <*>
1806− v .:? "from_as_string" <*>
1807− (fmap posixMS <$> v .:? "to") <*>
1808− v .:? "to_as_string" <*>
1809− v .: "doc_count" <*>
1810− (pure $ getNamedSubAgg v [ "key"
1811− , "from"
1812− , "from_as_string"
1813− , "to"
1814− , "to_as_string"
1815− , "doc_count"
1816− ]
1817− )
1818−
1819−instance FromJSON POSIXMS where
1820− parseJSON = withScientific "POSIXMS" (return . parse)
1821− where parse n = let n' = truncate n :: Integer
1822− in POSIXMS (posixSecondsToUTCTime (fromInteger (n' `div` 1000)))
1823−
1824−instance (FromJSON a) => FromJSON (TopHitResult a) where
1825− parseJSON (Object v) = TopHitResult <$>
1826− v .: "hits"
1827− parseJSON _ = fail "Failure in FromJSON (TopHitResult a)"
1828−
1829−instance Semigroup Filter where
1830− a <> b = AndFilter [a, b] defaultCache
1831−
1832−instance Monoid Filter where
1833− mempty = IdentityFilter
1834− mappend = (<>)
1835−
1836−instance Seminearring Filter where
1837− a <||> b = OrFilter [a, b] defaultCache
1838−
1839−instance ToJSON Filter where
1840− toJSON (AndFilter filters cache) =
1841− object ["and" .=
1842− object [ "filters" .= fmap toJSON filters
1843− , "_cache" .= cache]]
1844−
1845− toJSON (OrFilter filters cache) =
1846− object ["or" .=
1847− object [ "filters" .= fmap toJSON filters
1848− , "_cache" .= cache]]
1849−
1850− toJSON (NotFilter notFilter cache) =
1851− object ["not" .=
1852− object ["filter" .= notFilter
1853− , "_cache" .= cache]]
1854−
1855− toJSON (IdentityFilter) =
1856− object ["match_all" .= object []]
1857−
1858− toJSON (TermFilter (Term termFilterField termFilterValue) cache) =
1859− object ["term" .= object base]
1860− where base = [termFilterField .= termFilterValue,
1861− "_cache" .= cache]
1862−
1863− toJSON (ExistsFilter (FieldName fieldName)) =
1864− object ["exists" .= object
1865− ["field" .= fieldName]]
1866−
1867− toJSON (BoolFilter boolMatch) =
1868− object ["bool" .= boolMatch]
1869−
1870− toJSON (GeoBoundingBoxFilter bbConstraint) =
1871− object ["geo_bounding_box" .= bbConstraint]
1872−
1873− toJSON (GeoDistanceFilter (GeoPoint (FieldName distanceGeoField) geoDistLatLon)
1874− distance distanceType optimizeBbox cache) =
1875− object ["geo_distance" .=
1876− object ["distance" .= distance
1877− , "distance_type" .= distanceType
1878− , "optimize_bbox" .= optimizeBbox
1879− , distanceGeoField .= geoDistLatLon
1880− , "_cache" .= cache]]
1881−
1882− toJSON (GeoDistanceRangeFilter (GeoPoint (FieldName gddrField) drLatLon)
1883− (DistanceRange geoDistRangeDistFrom drDistanceTo)) =
1884− object ["geo_distance_range" .=
1885− object ["from" .= geoDistRangeDistFrom
1886− , "to" .= drDistanceTo
1887− , gddrField .= drLatLon]]
1888−
1889− toJSON (GeoPolygonFilter (FieldName geoPolygonFilterField) latLons) =
1890− object ["geo_polygon" .=
1891− object [geoPolygonFilterField .=
1892− object ["points" .= fmap toJSON latLons]]]
1893−
1894− toJSON (IdsFilter (MappingName mappingName) values) =
1895− object ["ids" .=
1896− object ["type" .= mappingName
1897− , "values" .= fmap unpackId values]]
1898−
1899− toJSON (LimitFilter limit) =
1900− object ["limit" .= object ["value" .= limit]]
1901−
1902− toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
1903− object ["missing" .=
1904− object [ "field" .= fieldName
1905− , "existence" .= existence
1906− , "null_value" .= nullValue]]
1907−
1908− toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
1909− object ["prefix" .=
1910− object [fieldName .= fieldValue
1911− , "_cache" .= cache]]
1912−
1913− toJSON (QueryFilter query False) =
1914− object ["query" .= toJSON query ]
1915− toJSON (QueryFilter query True) =
1916− object ["fquery" .=
1917− object [ "query" .= toJSON query
1918− , "_cache" .= True ]]
1919−
1920− toJSON (RangeFilter (FieldName fieldName) rangeValue rangeExecution cache) =
1921− object ["range" .=
1922− object [ fieldName .= object (rangeValueToPair rangeValue)
1923− , "execution" .= rangeExecution
1924− , "_cache" .= cache]]
1925−
1926− toJSON (RegexpFilter (FieldName fieldName)
1927− (Regexp regexText) flags (CacheName cacheName) cache (CacheKey cacheKey)) =
1928− object ["regexp" .=
1929− object [fieldName .=
1930− object ["value" .= regexText
1931− , "flags" .= flags]
1932− , "_name" .= cacheName
1933− , "_cache" .= cache
1934− , "_cache_key" .= cacheKey]]
1935−
1936−instance FromJSON Filter where
1937− parseJSON = withObject "Filter" parse
1938− where parse o = andFilter `taggedWith` "and"
1939− <|> orFilter `taggedWith` "or"
1940− <|> notFilter `taggedWith` "not"
1941− <|> identityFilter `taggedWith` "match_all"
1942− <|> boolFilter `taggedWith` "bool"
1943− <|> existsFilter `taggedWith` "exists"
1944− <|> geoBoundingBoxFilter `taggedWith` "geo_bounding_box"
1945− <|> geoDistanceFilter `taggedWith` "geo_distance"
1946− <|> geoDistanceRangeFilter `taggedWith` "geo_distance_range"
1947− <|> geoPolygonFilter `taggedWith` "geo_polygon"
1948− <|> idsFilter `taggedWith` "ids"
1949− <|> limitFilter `taggedWith` "limit"
1950− <|> missingFilter `taggedWith` "missing"
1951− <|> prefixFilter `taggedWith` "prefix"
1952− <|> queryFilter `taggedWith` "query"
1953− <|> fqueryFilter `taggedWith` "fquery"
1954− <|> rangeFilter `taggedWith` "range"
1955− <|> regexpFilter `taggedWith` "regexp"
1956− <|> termFilter `taggedWith` "term"
1957− where taggedWith parser k = parser =<< o .: k
1958− andFilter o = AndFilter <$> o .: "filters"
1959− <*> o .:? "_cache" .!= defaultCache
1960− orFilter o = OrFilter <$> o .: "filters"
1961− <*> o .:? "_cache" .!= defaultCache
1962− notFilter o = NotFilter <$> o .: "filter"
1963− <*> o .: "_cache" .!= defaultCache
1964− identityFilter :: Object -> Parser Filter
1965− identityFilter m
1966− | HM.null m = pure IdentityFilter
1967− | otherwise = fail ("Identityfilter expected empty object but got " <> show m)
1968− boolFilter = pure . BoolFilter
1969− existsFilter o = ExistsFilter <$> o .: "field"
1970− geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
1971− geoDistanceFilter o = do
1972− case HM.toList (deleteSeveral ["distance", "distance_type", "optimize_bbox", "_cache"] o) of
1973− [(fn, v)] -> do
1974− gp <- GeoPoint (FieldName fn) <$> parseJSON v
1975− GeoDistanceFilter gp <$> o .: "distance"
1976− <*> o .: "distance_type"
1977− <*> o .: "optimize_bbox"
1978− <*> o .:? "_cache" .!= defaultCache
1979− _ -> fail "Could not find GeoDistanceFilter field name"
1980− geoDistanceRangeFilter o = do
1981− case HM.toList (deleteSeveral ["from", "to"] o) of
1982− [(fn, v)] -> do
1983− gp <- GeoPoint (FieldName fn) <$> parseJSON v
1984− rng <- DistanceRange <$> o .: "from" <*> o .: "to"
1985− return (GeoDistanceRangeFilter gp rng)
1986− _ -> fail "Could not find GeoDistanceRangeFilter field name"
1987− geoPolygonFilter = fieldTagged $ \fn o -> GeoPolygonFilter fn <$> o .: "points"
1988− idsFilter o = IdsFilter <$> o .: "type"
1989− <*> o .: "values"
1990− limitFilter o = LimitFilter <$> o .: "value"
1991− missingFilter o = MissingFilter <$> o .: "field"
1992− <*> o .: "existence"
1993− <*> o .: "null_value"
1994− prefixFilter o = case HM.toList (HM.delete "_cache" o) of
1995− [(fn, String v)] -> PrefixFilter (FieldName fn) v <$> o .:? "_cache" .!= defaultCache
1996− _ -> fail "Could not parse PrefixFilter"
1997−
1998− queryFilter q = pure (QueryFilter q False)
1999− fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
2000− rangeFilter o = case HM.toList (deleteSeveral ["execution", "_cache"] o) of
2001− [(fn, v)] -> RangeFilter (FieldName fn)
2002− <$> parseJSON v
2003− <*> o .: "execution"
2004− <*> o .:? "_cache" .!= defaultCache
2005− _ -> fail "Could not find field name for RangeFilter"
2006− regexpFilter o = case HM.toList (deleteSeveral ["_name", "_cache", "_cache_key"] o) of
2007− [(fn, Object o')] -> RegexpFilter (FieldName fn)
2008− <$> o' .: "value"
2009− <*> o' .: "flags"
2010− <*> o .: "_name"
2011− <*> o .:? "_cache" .!= defaultCache
2012− <*> o .: "_cache_key"
2013− _ -> fail "Could not find field name for RegexpFilter"
2014− termFilter o = case HM.toList (HM.delete "_cache" o) of
2015− [(termField, String termVal)] -> TermFilter (Term termField termVal)
2016− <$> o .:? "_cache" .!= defaultCache
2017− _ -> fail "Could not find term field for TermFilter"
2018−
2019−fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
2020−fieldTagged f o = case HM.toList o of
2021− [(k, Object o')] -> f (FieldName k) o'
2022− _ -> fail "Expected object with 1 field-named key"
2023−
2024−-- Try to get an AggregationResults when we don't know the
2025−-- field name. We filter out the known keys to try to minimize the noise.
2026−getNamedSubAgg :: Object -> [Text] -> Maybe AggregationResults
2027−getNamedSubAgg o knownKeys = maggRes
2028− where unknownKeys = HM.filterWithKey (\k _ -> k `notElem` knownKeys) o
2029− maggRes
2030− | HM.null unknownKeys = Nothing
2031− | otherwise = Just . M.fromList $ HM.toList unknownKeys
2032−
2033−instance ToJSON GeoPoint where
2034− toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
2035− object [ geoPointField .= geoPointLatLon ]
2036−
2037−
2038−instance ToJSON Query where
2039− toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
2040− object [ "term" .=
2041− object [termQueryField .= object merged]]
2042− where
2043− base = [ "value" .= termQueryValue ]
2044− boosted = maybe [] (return . ("boost" .=)) boost
2045− merged = mappend base boosted
2046−
2047− toJSON (TermsQuery fieldName terms) =
2048− object [ "terms" .= object conjoined ]
2049− where conjoined = [fieldName .= terms]
2050−
2051− toJSON (IdsQuery idsQueryMappingName docIds) =
2052− object [ "ids" .= object conjoined ]
2053− where conjoined = [ "type" .= idsQueryMappingName
2054− , "values" .= fmap toJSON docIds ]
2055−
2056− toJSON (QueryQueryStringQuery qQueryStringQuery) =
2057− object [ "query_string" .= qQueryStringQuery ]
2058−
2059− toJSON (QueryMatchQuery matchQuery) =
2060− object [ "match" .= matchQuery ]
2061−
2062− toJSON (QueryMultiMatchQuery multiMatchQuery) =
2063− toJSON multiMatchQuery
2064−
2065− toJSON (QueryBoolQuery boolQuery) =
2066− object [ "bool" .= boolQuery ]
2067−
2068− toJSON (QueryBoostingQuery boostingQuery) =
2069− object [ "boosting" .= boostingQuery ]
2070−
2071− toJSON (QueryCommonTermsQuery commonTermsQuery) =
2072− object [ "common" .= commonTermsQuery ]
2073−
2074− toJSON (ConstantScoreFilter csFilter boost) =
2075− object ["constant_score" .= object ["filter" .= csFilter
2076− , "boost" .= boost]]
2077−
2078− toJSON (ConstantScoreQuery query boost) =
2079− object ["constant_score" .= object ["query" .= query
2080− , "boost" .= boost]]
2081−
2082− toJSON (QueryDisMaxQuery disMaxQuery) =
2083− object [ "dis_max" .= disMaxQuery ]
2084−
2085− toJSON (QueryFilteredQuery qFilteredQuery) =
2086− object [ "filtered" .= qFilteredQuery ]
2087−
2088− toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
2089− object [ "fuzzy_like_this" .= fuzzyQuery ]
2090−
2091− toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
2092− object [ "fuzzy_like_this_field" .= fuzzyFieldQuery ]
2093−
2094− toJSON (QueryFuzzyQuery fuzzyQuery) =
2095− object [ "fuzzy" .= fuzzyQuery ]
2096−
2097− toJSON (QueryHasChildQuery childQuery) =
2098− object [ "has_child" .= childQuery ]
2099−
2100− toJSON (QueryHasParentQuery parentQuery) =
2101− object [ "has_parent" .= parentQuery ]
2102−
2103− toJSON (QueryIndicesQuery qIndicesQuery) =
2104− object [ "indices" .= qIndicesQuery ]
2105−
2106− toJSON (MatchAllQuery boost) =
2107− object [ "match_all" .= omitNulls [ "boost" .= boost ] ]
2108−
2109− toJSON (QueryMoreLikeThisQuery query) =
2110− object [ "more_like_this" .= query ]
2111−
2112− toJSON (QueryMoreLikeThisFieldQuery query) =
2113− object [ "more_like_this_field" .= query ]
2114−
2115− toJSON (QueryNestedQuery query) =
2116− object [ "nested" .= query ]
2117−
2118− toJSON (QueryPrefixQuery query) =
2119− object [ "prefix" .= query ]
2120−
2121− toJSON (QueryRangeQuery query) =
2122− object [ "range" .= query ]
2123−
2124− toJSON (QueryRegexpQuery query) =
2125− object [ "regexp" .= query ]
2126−
2127− toJSON (QuerySimpleQueryStringQuery query) =
2128− object [ "simple_query_string" .= query ]
2129−
2130− toJSON (QueryTemplateQueryInline templateQuery) =
2131− object [ "template" .= templateQuery ]
2132−
2133−instance FromJSON Query where
2134− parseJSON v = withObject "Query" parse v
2135− where parse o = termQuery `taggedWith` "term"
2136− <|> termsQuery `taggedWith` "terms"
2137− <|> idsQuery `taggedWith` "ids"
2138− <|> queryQueryStringQuery `taggedWith` "query_string"
2139− <|> queryMatchQuery `taggedWith` "match"
2140− <|> queryMultiMatchQuery
2141− <|> queryBoolQuery `taggedWith` "bool"
2142− <|> queryBoostingQuery `taggedWith` "boosting"
2143− <|> queryCommonTermsQuery `taggedWith` "common"
2144− <|> constantScoreFilter `taggedWith` "constant_score"
2145− <|> constantScoreQuery `taggedWith` "constant_score"
2146− <|> queryDisMaxQuery `taggedWith` "dis_max"
2147− <|> queryFilteredQuery `taggedWith` "filtered"
2148− <|> queryFuzzyLikeThisQuery `taggedWith` "fuzzy_like_this"
2149− <|> queryFuzzyLikeFieldQuery `taggedWith` "fuzzy_like_this_field"
2150− <|> queryFuzzyQuery `taggedWith` "fuzzy"
2151− <|> queryHasChildQuery `taggedWith` "has_child"
2152− <|> queryHasParentQuery `taggedWith` "has_parent"
2153− <|> queryIndicesQuery `taggedWith` "indices"
2154− <|> matchAllQuery `taggedWith` "match_all"
2155− <|> queryMoreLikeThisQuery `taggedWith` "more_like_this"
2156− <|> queryMoreLikeThisFieldQuery `taggedWith` "more_like_this_field"
2157− <|> queryNestedQuery `taggedWith` "nested"
2158− <|> queryPrefixQuery `taggedWith` "prefix"
2159− <|> queryRangeQuery `taggedWith` "range"
2160− <|> queryRegexpQuery `taggedWith` "regexp"
2161− <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2162− <|> queryTemplateQueryInline `taggedWith` "template"
2163− where taggedWith parser k = parser =<< o .: k
2164− termQuery = fieldTagged $ \(FieldName fn) o ->
2165− TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
2166− termsQuery o = case HM.toList o of
2167− [(fn, vs)] -> do vals <- parseJSON vs
2168− case vals of
2169− x:xs -> return (TermsQuery fn (x :| xs))
2170− _ -> fail "Expected non empty list of values"
2171− _ -> fail "Expected object with 1 field-named key"
2172− idsQuery o = IdsQuery <$> o .: "type"
2173− <*> o .: "values"
2174− queryQueryStringQuery = pure . QueryQueryStringQuery
2175− queryMatchQuery = pure . QueryMatchQuery
2176− queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
2177− queryBoolQuery = pure . QueryBoolQuery
2178− queryBoostingQuery = pure . QueryBoostingQuery
2179− queryCommonTermsQuery = pure . QueryCommonTermsQuery
2180− constantScoreFilter o = case HM.lookup "filter" o of
2181− Just x -> ConstantScoreFilter <$> parseJSON x
2182− <*> o .: "boost"
2183− _ -> fail "Does not appear to be a ConstantScoreFilter"
2184− constantScoreQuery o = case HM.lookup "query" o of
2185− Just x -> ConstantScoreQuery <$> parseJSON x
2186− <*> o .: "boost"
2187− _ -> fail "Does not appear to be a ConstantScoreQuery"
2188− queryDisMaxQuery = pure . QueryDisMaxQuery
2189− queryFilteredQuery = pure . QueryFilteredQuery
2190− queryFuzzyLikeThisQuery = pure . QueryFuzzyLikeThisQuery
2191− queryFuzzyLikeFieldQuery = pure . QueryFuzzyLikeFieldQuery
2192− queryFuzzyQuery = pure . QueryFuzzyQuery
2193− queryHasChildQuery = pure . QueryHasChildQuery
2194− queryHasParentQuery = pure . QueryHasParentQuery
2195− queryIndicesQuery = pure . QueryIndicesQuery
2196− matchAllQuery o = MatchAllQuery <$> o .:? "boost"
2197− queryMoreLikeThisQuery = pure . QueryMoreLikeThisQuery
2198− queryMoreLikeThisFieldQuery = pure . QueryMoreLikeThisFieldQuery
2199− queryNestedQuery = pure . QueryNestedQuery
2200− queryPrefixQuery = pure . QueryPrefixQuery
2201− queryRangeQuery = pure . QueryRangeQuery
2202− queryRegexpQuery = pure . QueryRegexpQuery
2203− querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2204− queryTemplateQueryInline = pure . QueryTemplateQueryInline
2205−
2206−
2207−omitNulls :: [(Text, Value)] -> Value
2208−omitNulls = object . filter notNull where
2209− notNull (_, Null) = False
2210− notNull (_, Array a) = (not . V.null) a
2211− notNull _ = True
2212−
2213−
2214−instance ToJSON SimpleQueryStringQuery where
2215− toJSON SimpleQueryStringQuery {..} =
2216− omitNulls (base ++ maybeAdd)
2217− where base = [ "query" .= simpleQueryStringQuery ]
2218− maybeAdd = [ "fields" .= simpleQueryStringField
2219− , "default_operator" .= simpleQueryStringOperator
2220− , "analyzer" .= simpleQueryStringAnalyzer
2221− , "flags" .= simpleQueryStringFlags
2222− , "lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded
2223− , "locale" .= simpleQueryStringLocale ]
2224−
2225−instance FromJSON SimpleQueryStringQuery where
2226− parseJSON = withObject "SimpleQueryStringQuery" parse
2227− where parse o = SimpleQueryStringQuery <$> o .: "query"
2228− <*> o .:? "fields"
2229− <*> o .:? "default_operator"
2230− <*> o .:? "analyzer"
2231− <*> (parseFlags <$> o .:? "flags")
2232− <*> o .:? "lowercase_expanded_terms"
2233− <*> o .:? "locale"
2234− parseFlags (Just (x:xs)) = Just (x :| xs)
2235− parseFlags _ = Nothing
2236−
2237−instance ToJSON FieldOrFields where
2238− toJSON (FofField fieldName) =
2239− toJSON fieldName
2240− toJSON (FofFields fieldNames) =
2241− toJSON fieldNames
2242−
2243−instance FromJSON FieldOrFields where
2244− parseJSON v = FofField <$> parseJSON v
2245− <|> FofFields <$> (parseNEJSON =<< parseJSON v)
2246−
2247−instance ToJSON SimpleQueryFlag where
2248− toJSON SimpleQueryAll = "ALL"
2249− toJSON SimpleQueryNone = "NONE"
2250− toJSON SimpleQueryAnd = "AND"
2251− toJSON SimpleQueryOr = "OR"
2252− toJSON SimpleQueryPrefix = "PREFIX"
2253− toJSON SimpleQueryPhrase = "PHRASE"
2254− toJSON SimpleQueryPrecedence = "PRECEDENCE"
2255− toJSON SimpleQueryEscape = "ESCAPE"
2256− toJSON SimpleQueryWhitespace = "WHITESPACE"
2257− toJSON SimpleQueryFuzzy = "FUZZY"
2258− toJSON SimpleQueryNear = "NEAR"
2259− toJSON SimpleQuerySlop = "SLOP"
2260−
2261−instance FromJSON SimpleQueryFlag where
2262− parseJSON = withText "SimpleQueryFlag" parse
2263− where parse "ALL" = pure SimpleQueryAll
2264− parse "NONE" = pure SimpleQueryNone
2265− parse "AND" = pure SimpleQueryAnd
2266− parse "OR" = pure SimpleQueryOr
2267− parse "PREFIX" = pure SimpleQueryPrefix
2268− parse "PHRASE" = pure SimpleQueryPhrase
2269− parse "PRECEDENCE" = pure SimpleQueryPrecedence
2270− parse "ESCAPE" = pure SimpleQueryEscape
2271− parse "WHITESPACE" = pure SimpleQueryWhitespace
2272− parse "FUZZY" = pure SimpleQueryFuzzy
2273− parse "NEAR" = pure SimpleQueryNear
2274− parse "SLOP" = pure SimpleQuerySlop
2275− parse f = fail ("Unexpected SimpleQueryFlag: " <> show f)
2276−
2277−instance ToJSON RegexpQuery where
2278− toJSON (RegexpQuery (FieldName rqQueryField)
2279− (Regexp regexpQueryQuery) rqQueryFlags
2280− rqQueryBoost) =
2281− object [ rqQueryField .= omitNulls base ]
2282− where base = [ "value" .= regexpQueryQuery
2283− , "flags" .= rqQueryFlags
2284− , "boost" .= rqQueryBoost ]
2285−
2286−instance FromJSON RegexpQuery where
2287− parseJSON = withObject "RegexpQuery" parse
2288− where parse = fieldTagged $ \fn o ->
2289− RegexpQuery fn
2290− <$> o .: "value"
2291− <*> o .: "flags"
2292− <*> o .:? "boost"
2293−
2294−instance ToJSON QueryStringQuery where
2295− toJSON (QueryStringQuery qsQueryString
2296− qsDefaultField qsOperator
2297− qsAnalyzer qsAllowWildcard
2298− qsLowercaseExpanded qsEnablePositionIncrements
2299− qsFuzzyMaxExpansions qsFuzziness
2300− qsFuzzyPrefixLength qsPhraseSlop
2301− qsBoost qsAnalyzeWildcard
2302− qsGeneratePhraseQueries qsMinimumShouldMatch
2303− qsLenient qsLocale) =
2304− omitNulls base
2305− where
2306− base = [ "query" .= qsQueryString
2307− , "default_field" .= qsDefaultField
2308− , "default_operator" .= qsOperator
2309− , "analyzer" .= qsAnalyzer
2310− , "allow_leading_wildcard" .= qsAllowWildcard
2311− , "lowercase_expanded_terms" .= qsLowercaseExpanded
2312− , "enable_position_increments" .= qsEnablePositionIncrements
2313− , "fuzzy_max_expansions" .= qsFuzzyMaxExpansions
2314− , "fuzziness" .= qsFuzziness
2315− , "fuzzy_prefix_length" .= qsFuzzyPrefixLength
2316− , "phrase_slop" .= qsPhraseSlop
2317− , "boost" .= qsBoost
2318− , "analyze_wildcard" .= qsAnalyzeWildcard
2319− , "auto_generate_phrase_queries" .= qsGeneratePhraseQueries
2320− , "minimum_should_match" .= qsMinimumShouldMatch
2321− , "lenient" .= qsLenient
2322− , "locale" .= qsLocale ]
2323−
2324−instance FromJSON QueryStringQuery where
2325− parseJSON = withObject "QueryStringQuery" parse
2326− where parse o = QueryStringQuery
2327− <$> o .: "query"
2328− <*> o .:? "default_field"
2329− <*> o .:? "default_operator"
2330− <*> o .:? "analyzer"
2331− <*> o .:? "allow_leading_wildcard"
2332− <*> o .:? "lowercase_expanded_terms"
2333− <*> o .:? "enable_position_increments"
2334− <*> o .:? "fuzzy_max_expansions"
2335− <*> o .:? "fuzziness"
2336− <*> o .:? "fuzzy_prefix_length"
2337− <*> o .:? "phrase_slop"
2338− <*> o .:? "boost"
2339− <*> o .:? "analyze_wildcard"
2340− <*> o .:? "auto_generate_phrase_queries"
2341− <*> o .:? "minimum_should_match"
2342− <*> o .:? "lenient"
2343− <*> o .:? "locale"
2344−
2345−instance ToJSON RangeQuery where
2346− toJSON (RangeQuery (FieldName fieldName) range boost) =
2347− object [ fieldName .= object conjoined ]
2348− where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2349−
2350−instance FromJSON RangeQuery where
2351− parseJSON = withObject "RangeQuery" parse
2352− where parse = fieldTagged $ \fn o ->
2353− RangeQuery fn
2354− <$> parseJSON (Object o)
2355− <*> o .: "boost"
2356−
2357−instance FromJSON RangeValue where
2358− parseJSON = withObject "RangeValue" parse
2359− where parse o = parseDate o
2360− <|> parseDouble o
2361− parseDate o = do lt <- o .:? "lt"
2362− lte <- o .:? "lte"
2363− gt <- o .:? "gt"
2364− gte <- o .:? "gte"
2365− case (lt, lte, gt, gte) of
2366− (Just a, _, Just b, _) -> return (RangeDateGtLt (GreaterThanD b) (LessThanD a))
2367− (Just a, _, _, Just b)-> return (RangeDateGteLt (GreaterThanEqD b) (LessThanD a))
2368− (_, Just a, Just b, _)-> return (RangeDateGtLte (GreaterThanD b) (LessThanEqD a))
2369− (_, Just a, _, Just b)-> return (RangeDateGteLte (GreaterThanEqD b) (LessThanEqD a))
2370− (_, _, Just a, _)-> return (RangeDateGt (GreaterThanD a))
2371− (Just a, _, _, _)-> return (RangeDateLt (LessThanD a))
2372− (_, _, _, Just a)-> return (RangeDateGte (GreaterThanEqD a))
2373− (_, Just a, _, _)-> return (RangeDateLte (LessThanEqD a))
2374− (Nothing, Nothing, Nothing, Nothing) -> mzero
2375− parseDouble o = do lt <- o .:? "lt"
2376− lte <- o .:? "lte"
2377− gt <- o .:? "gt"
2378− gte <- o .:? "gte"
2379− case (lt, lte, gt, gte) of
2380− (Just a, _, Just b, _) -> return (RangeDoubleGtLt (GreaterThan b) (LessThan a))
2381− (Just a, _, _, Just b)-> return (RangeDoubleGteLt (GreaterThanEq b) (LessThan a))
2382− (_, Just a, Just b, _)-> return (RangeDoubleGtLte (GreaterThan b) (LessThanEq a))
2383− (_, Just a, _, Just b)-> return (RangeDoubleGteLte (GreaterThanEq b) (LessThanEq a))
2384− (_, _, Just a, _)-> return (RangeDoubleGt (GreaterThan a))
2385− (Just a, _, _, _)-> return (RangeDoubleLt (LessThan a))
2386− (_, _, _, Just a)-> return (RangeDoubleGte (GreaterThanEq a))
2387− (_, Just a, _, _)-> return (RangeDoubleLte (LessThanEq a))
2388− (Nothing, Nothing, Nothing, Nothing) -> mzero
2389−
2390−instance ToJSON PrefixQuery where
2391− toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
2392− object [ fieldName .= omitNulls base ]
2393− where base = [ "value" .= queryValue
2394− , "boost" .= boost ]
2395−
2396−instance FromJSON PrefixQuery where
2397− parseJSON = withObject "PrefixQuery" parse
2398− where parse = fieldTagged $ \fn o ->
2399− PrefixQuery fn
2400− <$> o .: "value"
2401− <*> o .:? "boost"
2402−
2403−instance ToJSON NestedQuery where
2404− toJSON (NestedQuery nqPath nqScoreType nqQuery) =
2405− object [ "path" .= nqPath
2406− , "score_mode" .= nqScoreType
2407− , "query" .= nqQuery ]
2408−
2409−instance FromJSON NestedQuery where
2410− parseJSON = withObject "NestedQuery" parse
2411− where parse o = NestedQuery
2412− <$> o .: "path"
2413− <*> o .: "score_mode"
2414− <*> o .: "query"
2415−
2416−instance ToJSON MoreLikeThisFieldQuery where
2417− toJSON (MoreLikeThisFieldQuery text (FieldName fieldName)
2418− percent mtf mqt stopwords mindf maxdf
2419− minwl maxwl boostTerms boost analyzer) =
2420− object [ fieldName .= omitNulls base ]
2421− where base = [ "like_text" .= text
2422− , "percent_terms_to_match" .= percent
2423− , "min_term_freq" .= mtf
2424− , "max_query_terms" .= mqt
2425− , "stop_words" .= stopwords
2426− , "min_doc_freq" .= mindf
2427− , "max_doc_freq" .= maxdf
2428− , "min_word_length" .= minwl
2429− , "max_word_length" .= maxwl
2430− , "boost_terms" .= boostTerms
2431− , "boost" .= boost
2432− , "analyzer" .= analyzer ]
2433−
2434−instance FromJSON MoreLikeThisFieldQuery where
2435− parseJSON = withObject "MoreLikeThisFieldQuery" parse
2436− where parse = fieldTagged $ \fn o ->
2437− MoreLikeThisFieldQuery
2438− <$> o .: "like_text"
2439− <*> pure fn
2440− <*> o .:? "percent_terms_to_match"
2441− <*> o .:? "min_term_freq"
2442− <*> o .:? "max_query_terms"
2443− -- <*> (optionalNE =<< o .:? "stop_words")
2444− <*> o .:? "stop_words"
2445− <*> o .:? "min_doc_freq"
2446− <*> o .:? "max_doc_freq"
2447− <*> o .:? "min_word_length"
2448− <*> o .:? "max_word_length"
2449− <*> o .:? "boost_terms"
2450− <*> o .:? "boost"
2451− <*> o .:? "analyzer"
2452− -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2453−
2454−instance ToJSON MoreLikeThisQuery where
2455− toJSON (MoreLikeThisQuery text fields percent
2456− mtf mqt stopwords mindf maxdf
2457− minwl maxwl boostTerms boost analyzer) =
2458− omitNulls base
2459− where base = [ "like_text" .= text
2460− , "fields" .= fields
2461− , "percent_terms_to_match" .= percent
2462− , "min_term_freq" .= mtf
2463− , "max_query_terms" .= mqt
2464− , "stop_words" .= stopwords
2465− , "min_doc_freq" .= mindf
2466− , "max_doc_freq" .= maxdf
2467− , "min_word_length" .= minwl
2468− , "max_word_length" .= maxwl
2469− , "boost_terms" .= boostTerms
2470− , "boost" .= boost
2471− , "analyzer" .= analyzer ]
2472−
2473−instance FromJSON MoreLikeThisQuery where
2474− parseJSON = withObject "MoreLikeThisQuery" parse
2475− where parse o = MoreLikeThisQuery
2476− <$> o .: "like_text"
2477− -- <*> (optionalNE =<< o .:? "fields")
2478− <*> o .:? "fields"
2479− <*> o .:? "percent_terms_to_match"
2480− <*> o .:? "min_term_freq"
2481− <*> o .:? "max_query_terms"
2482− -- <*> (optionalNE =<< o .:? "stop_words")
2483− <*> o .:? "stop_words"
2484− <*> o .:? "min_doc_freq"
2485− <*> o .:? "max_doc_freq"
2486− <*> o .:? "min_word_length"
2487− <*> o .:? "max_word_length"
2488− <*> o .:? "boost_terms"
2489− <*> o .:? "boost"
2490− <*> o .:? "analyzer"
2491− -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2492−
2493−instance ToJSON IndicesQuery where
2494− toJSON (IndicesQuery indices query noMatch) =
2495− omitNulls [ "indices" .= indices
2496− , "no_match_query" .= noMatch
2497− , "query" .= query ]
2498−
2499−instance FromJSON IndicesQuery where
2500− parseJSON = withObject "IndicesQuery" parse
2501− where parse o = IndicesQuery
2502− <$> o .:? "indices" .!= []
2503− <*> o .: "query"
2504− <*> o .:? "no_match_query"
2505−
2506−instance ToJSON HasParentQuery where
2507− toJSON (HasParentQuery queryType query scoreType) =
2508− omitNulls [ "parent_type" .= queryType
2509− , "score_type" .= scoreType
2510− , "query" .= query ]
2511−
2512−instance FromJSON HasParentQuery where
2513− parseJSON = withObject "HasParentQuery" parse
2514− where parse o = HasParentQuery
2515− <$> o .: "parent_type"
2516− <*> o .: "query"
2517− <*> o .:? "score_type"
2518−
2519−instance ToJSON HasChildQuery where
2520− toJSON (HasChildQuery queryType query scoreType) =
2521− omitNulls [ "query" .= query
2522− , "score_type" .= scoreType
2523− , "type" .= queryType ]
2524−
2525−instance FromJSON HasChildQuery where
2526− parseJSON = withObject "HasChildQuery" parse
2527− where parse o = HasChildQuery
2528− <$> o .: "type"
2529− <*> o .: "query"
2530− <*> o .:? "score_type"
2531−
2532−instance ToJSON FuzzyQuery where
2533− toJSON (FuzzyQuery (FieldName fieldName) queryText
2534− prefixLength maxEx fuzziness boost) =
2535− object [ fieldName .= omitNulls base ]
2536− where base = [ "value" .= queryText
2537− , "fuzziness" .= fuzziness
2538− , "prefix_length" .= prefixLength
2539− , "boost" .= boost
2540− , "max_expansions" .= maxEx ]
2541−
2542−instance FromJSON FuzzyQuery where
2543− parseJSON = withObject "FuzzyQuery" parse
2544− where parse = fieldTagged $ \fn o ->
2545− FuzzyQuery fn
2546− <$> o .: "value"
2547− <*> o .: "prefix_length"
2548− <*> o .: "max_expansions"
2549− <*> o .: "fuzziness"
2550− <*> o .:? "boost"
2551−
2552−instance ToJSON FuzzyLikeFieldQuery where
2553− toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
2554− fieldText maxTerms ignoreFreq fuzziness prefixLength
2555− boost analyzer) =
2556− object [ fieldName .=
2557− omitNulls [ "like_text" .= fieldText
2558− , "max_query_terms" .= maxTerms
2559− , "ignore_tf" .= ignoreFreq
2560− , "fuzziness" .= fuzziness
2561− , "prefix_length" .= prefixLength
2562− , "analyzer" .= analyzer
2563− , "boost" .= boost ]]
2564−
2565−instance FromJSON FuzzyLikeFieldQuery where
2566− parseJSON = withObject "FuzzyLikeFieldQuery" parse
2567− where parse = fieldTagged $ \fn o ->
2568− FuzzyLikeFieldQuery fn
2569− <$> o .: "like_text"
2570− <*> o .: "max_query_terms"
2571− <*> o .: "ignore_tf"
2572− <*> o .: "fuzziness"
2573− <*> o .: "prefix_length"
2574− <*> o .: "boost"
2575− <*> o .:? "analyzer"
2576−
2577−instance ToJSON FuzzyLikeThisQuery where
2578− toJSON (FuzzyLikeThisQuery fields text maxTerms
2579− ignoreFreq fuzziness prefixLength boost analyzer) =
2580− omitNulls base
2581− where base = [ "fields" .= fields
2582− , "like_text" .= text
2583− , "max_query_terms" .= maxTerms
2584− , "ignore_tf" .= ignoreFreq
2585− , "fuzziness" .= fuzziness
2586− , "prefix_length" .= prefixLength
2587− , "analyzer" .= analyzer
2588− , "boost" .= boost ]
2589−
2590−instance FromJSON FuzzyLikeThisQuery where
2591− parseJSON = withObject "FuzzyLikeThisQuery" parse
2592− where parse o = FuzzyLikeThisQuery
2593− <$> o .:? "fields" .!= []
2594− <*> o .: "like_text"
2595− <*> o .: "max_query_terms"
2596− <*> o .: "ignore_tf"
2597− <*> o .: "fuzziness"
2598− <*> o .: "prefix_length"
2599− <*> o .: "boost"
2600− <*> o .:? "analyzer"
2601−
2602−instance ToJSON FilteredQuery where
2603− toJSON (FilteredQuery query fFilter) =
2604− object [ "query" .= query
2605− , "filter" .= fFilter ]
2606−
2607−instance FromJSON FilteredQuery where
2608− parseJSON = withObject "FilteredQuery" parse
2609− where parse o = FilteredQuery
2610− <$> o .: "query"
2611− <*> o .: "filter"
2612−
2613−instance ToJSON DisMaxQuery where
2614− toJSON (DisMaxQuery queries tiebreaker boost) =
2615− omitNulls base
2616− where base = [ "queries" .= queries
2617− , "boost" .= boost
2618− , "tie_breaker" .= tiebreaker ]
2619−
2620−instance FromJSON DisMaxQuery where
2621− parseJSON = withObject "DisMaxQuery" parse
2622− where parse o = DisMaxQuery
2623− <$> o .:? "queries" .!= []
2624− <*> o .: "tie_breaker"
2625− <*> o .:? "boost"
2626−
2627−instance ToJSON CommonTermsQuery where
2628− toJSON (CommonTermsQuery (FieldName fieldName)
2629− (QueryString query) cf lfo hfo msm
2630− boost analyzer disableCoord) =
2631− object [fieldName .= omitNulls base ]
2632− where base = [ "query" .= query
2633− , "cutoff_frequency" .= cf
2634− , "low_freq_operator" .= lfo
2635− , "minimum_should_match" .= msm
2636− , "boost" .= boost
2637− , "analyzer" .= analyzer
2638− , "disable_coord" .= disableCoord
2639− , "high_freq_operator" .= hfo ]
2640−
2641−instance FromJSON CommonTermsQuery where
2642− parseJSON = withObject "CommonTermsQuery" parse
2643− where parse = fieldTagged $ \fn o ->
2644− CommonTermsQuery fn
2645− <$> o .: "query"
2646− <*> o .: "cutoff_frequency"
2647− <*> o .: "low_freq_operator"
2648− <*> o .: "high_freq_operator"
2649− <*> o .:? "minimum_should_match"
2650− <*> o .:? "boost"
2651− <*> o .:? "analyzer"
2652− <*> o .:? "disable_coord"
2653−
2654−instance ToJSON CommonMinimumMatch where
2655− toJSON (CommonMinimumMatch mm) = toJSON mm
2656− toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
2657− object [ "low_freq" .= lowF
2658− , "high_freq" .= highF ]
2659−
2660−instance FromJSON CommonMinimumMatch where
2661− parseJSON v = parseMinimum v
2662− <|> parseMinimumHighLow v
2663− where parseMinimum = fmap CommonMinimumMatch . parseJSON
2664− parseMinimumHighLow = fmap CommonMinimumMatchHighLow . withObject "CommonMinimumMatchHighLow" (\o ->
2665− MinimumMatchHighLow
2666− <$> o .: "low_freq"
2667− <*> o .: "high_freq")
2668−
2669−
2670−instance ToJSON BoostingQuery where
2671− toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
2672− object [ "positive" .= bqPositiveQuery
2673− , "negative" .= bqNegativeQuery
2674− , "negative_boost" .= bqNegativeBoost ]
2675−
2676−instance FromJSON BoostingQuery where
2677− parseJSON = withObject "BoostingQuery" parse
2678− where parse o = BoostingQuery
2679− <$> o .: "positive"
2680− <*> o .: "negative"
2681− <*> o .: "negative_boost"
2682−
2683−instance ToJSON BoolQuery where
2684− toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
2685− omitNulls base
2686− where base = [ "must" .= mustM
2687− , "must_not" .= notM
2688− , "should" .= shouldM
2689− , "minimum_should_match" .= bqMin
2690− , "boost" .= boost
2691− , "disable_coord" .= disableCoord ]
2692−
2693−instance FromJSON BoolQuery where
2694− parseJSON = withObject "BoolQuery" parse
2695− where parse o = BoolQuery
2696− <$> o .:? "must" .!= []
2697− <*> o .:? "must_not" .!= []
2698− <*> o .:? "should" .!= []
2699− <*> o .:? "minimum_should_match"
2700− <*> o .:? "boost"
2701− <*> o .:? "disable_coord"
2702−
2703−instance ToJSON MatchQuery where
2704− toJSON (MatchQuery (FieldName fieldName)
2705− (QueryString mqQueryString) booleanOperator
2706− zeroTermsQuery cutoffFrequency matchQueryType
2707− analyzer maxExpansions lenient boost) =
2708− object [ fieldName .= omitNulls base ]
2709− where base = [ "query" .= mqQueryString
2710− , "operator" .= booleanOperator
2711− , "zero_terms_query" .= zeroTermsQuery
2712− , "cutoff_frequency" .= cutoffFrequency
2713− , "type" .= matchQueryType
2714− , "analyzer" .= analyzer
2715− , "max_expansions" .= maxExpansions
2716− , "lenient" .= lenient
2717− , "boost" .= boost ]
2718−
2719−instance FromJSON MatchQuery where
2720− parseJSON = withObject "MatchQuery" parse
2721− where parse = fieldTagged $ \fn o ->
2722− MatchQuery fn
2723− <$> o .: "query"
2724− <*> o .: "operator"
2725− <*> o .: "zero_terms_query"
2726− <*> o .:? "cutoff_frequency"
2727− <*> o .:? "type"
2728− <*> o .:? "analyzer"
2729− <*> o .:? "max_expansions"
2730− <*> o .:? "lenient"
2731− <*> o .:? "boost"
2732−
2733−instance ToJSON MultiMatchQuery where
2734− toJSON (MultiMatchQuery fields (QueryString query) boolOp
2735− ztQ tb mmqt cf analyzer maxEx lenient) =
2736− object ["multi_match" .= omitNulls base]
2737− where base = [ "fields" .= fmap toJSON fields
2738− , "query" .= query
2739− , "operator" .= boolOp
2740− , "zero_terms_query" .= ztQ
2741− , "tie_breaker" .= tb
2742− , "type" .= mmqt
2743− , "cutoff_frequency" .= cf
2744− , "analyzer" .= analyzer
2745− , "max_expansions" .= maxEx
2746− , "lenient" .= lenient ]
2747−
2748−instance FromJSON MultiMatchQuery where
2749− parseJSON = withObject "MultiMatchQuery" parse
2750− where parse raw = do o <- raw .: "multi_match"
2751− MultiMatchQuery
2752− <$> o .:? "fields" .!= []
2753− <*> o .: "query"
2754− <*> o .: "operator"
2755− <*> o .: "zero_terms_query"
2756− <*> o .:? "tie_breaker"
2757− <*> o .:? "type"
2758− <*> o .:? "cutoff_frequency"
2759− <*> o .:? "analyzer"
2760− <*> o .:? "max_expansions"
2761− <*> o .:? "lenient"
2762−
2763−instance ToJSON MultiMatchQueryType where
2764− toJSON MultiMatchBestFields = "best_fields"
2765− toJSON MultiMatchMostFields = "most_fields"
2766− toJSON MultiMatchCrossFields = "cross_fields"
2767− toJSON MultiMatchPhrase = "phrase"
2768− toJSON MultiMatchPhrasePrefix = "phrase_prefix"
2769−
2770−instance FromJSON MultiMatchQueryType where
2771− parseJSON = withText "MultiMatchPhrasePrefix" parse
2772− where parse "best_fields" = pure MultiMatchBestFields
2773− parse "most_fields" = pure MultiMatchMostFields
2774− parse "cross_fields" = pure MultiMatchCrossFields
2775− parse "phrase" = pure MultiMatchPhrase
2776− parse "phrase_prefix" = pure MultiMatchPhrasePrefix
2777− parse t = fail ("Unexpected MultiMatchPhrasePrefix: " <> show t)
2778−
2779−instance ToJSON BooleanOperator where
2780− toJSON And = String "and"
2781− toJSON Or = String "or"
2782−
2783−instance FromJSON BooleanOperator where
2784− parseJSON = withText "BooleanOperator" parse
2785− where parse "and" = pure And
2786− parse "or" = pure Or
2787− parse o = fail ("Unexpected BooleanOperator: " <> show o)
2788−
2789−instance ToJSON ZeroTermsQuery where
2790− toJSON ZeroTermsNone = String "none"
2791− toJSON ZeroTermsAll = String "all"
2792−
2793−instance FromJSON ZeroTermsQuery where
2794− parseJSON = withText "ZeroTermsQuery" parse
2795− where parse "none" = pure ZeroTermsNone
2796− parse "all" = pure ZeroTermsAll
2797− parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
2798−
2799−instance ToJSON MatchQueryType where
2800− toJSON MatchPhrase = "phrase"
2801− toJSON MatchPhrasePrefix = "phrase_prefix"
2802−
2803−instance FromJSON MatchQueryType where
2804− parseJSON = withText "MatchQueryType" parse
2805− where parse "phrase" = pure MatchPhrase
2806− parse "phrase_prefix" = pure MatchPhrasePrefix
2807− parse t = fail ("Unexpected MatchQueryType: " <> show t)
2808−
2809−instance FromJSON Status where
2810− parseJSON (Object v) = Status <$>
2811− v .:? "ok" <*>
2812− (v .:? "status" .!= 200) <*>
2813− v .: "name" <*>
2814− v .: "version" <*>
2815− v .: "tagline"
2816− parseJSON _ = empty
2817−
2818−
2819−instance ToJSON IndexSettings where
2820− toJSON (IndexSettings s r) = object ["settings" .=
2821− object ["index" .=
2822− object ["number_of_shards" .= s, "number_of_replicas" .= r]
2823− ]
2824− ]
2825−
2826−instance FromJSON IndexSettings where
2827− parseJSON = withObject "IndexSettings" parse
2828− where parse o = do s <- o .: "settings"
2829− i <- s .: "index"
2830− IndexSettings <$> i .: "number_of_shards"
2831− <*> i .: "number_of_replicas"
2832−
2833−instance ToJSON UpdatableIndexSetting where
2834− toJSON (NumberOfReplicas x) = oPath ("index" :| ["number_of_replicas"]) x
2835− toJSON (AutoExpandReplicas x) = oPath ("index" :| ["auto_expand_replicas"]) x
2836− toJSON (RefreshInterval x) = oPath ("index" :| ["refresh_interval"]) (NominalDiffTimeJSON x)
2837− toJSON (IndexConcurrency x) = oPath ("index" :| ["concurrency"]) x
2838− toJSON (FailOnMergeFailure x) = oPath ("index" :| ["fail_on_merge_failure"]) x
2839− toJSON (TranslogFlushThresholdOps x) = oPath ("index" :| ["translog", "flush_threshold_ops"]) x
2840− toJSON (TranslogFlushThresholdSize x) = oPath ("index" :| ["translog", "flush_threshold_size"]) x
2841− toJSON (TranslogFlushThresholdPeriod x) = oPath ("index" :| ["translog", "flush_threshold_period"]) (NominalDiffTimeJSON x)
2842− toJSON (TranslogDisableFlush x) = oPath ("index" :| ["translog", "disable_flush"]) x
2843− toJSON (CacheFilterMaxSize x) = oPath ("index" :| ["cache", "filter", "max_size"]) x
2844− toJSON (CacheFilterExpire x) = oPath ("index" :| ["cache", "filter", "expire"]) (NominalDiffTimeJSON <$> x)
2845− toJSON (GatewaySnapshotInterval x) = oPath ("index" :| ["gateway", "snapshot_interval"]) (NominalDiffTimeJSON x)
2846− toJSON (RoutingAllocationInclude fs) = oPath ("index" :| ["routing", "allocation", "include"]) (attrFilterJSON fs)
2847− toJSON (RoutingAllocationExclude fs) = oPath ("index" :| ["routing", "allocation", "exclude"]) (attrFilterJSON fs)
2848− toJSON (RoutingAllocationRequire fs) = oPath ("index" :| ["routing", "allocation", "require"]) (attrFilterJSON fs)
2849− toJSON (RoutingAllocationEnable x) = oPath ("index" :| ["routing", "allocation", "enable"]) x
2850− toJSON (RoutingAllocationShardsPerNode x) = oPath ("index" :| ["routing", "allocation", "total_shards_per_node"]) x
2851− toJSON (RecoveryInitialShards x) = oPath ("index" :| ["recovery", "initial_shards"]) x
2852− toJSON (GCDeletes x) = oPath ("index" :| ["gc_deletes"]) (NominalDiffTimeJSON x)
2853− toJSON (TTLDisablePurge x) = oPath ("index" :| ["ttl", "disable_purge"]) x
2854− toJSON (TranslogFSType x) = oPath ("index" :| ["translog", "fs", "type"]) x
2855− toJSON (IndexCompoundFormat x) = oPath ("index" :| ["compound_format"]) x
2856− toJSON (IndexCompoundOnFlush x) = oPath ("index" :| ["compound_on_flush"]) x
2857− toJSON (WarmerEnabled x) = oPath ("index" :| ["warmer", "enabled"]) x
2858− toJSON (BlocksReadOnly x) = oPath ("blocks" :| ["read_only"]) x
2859− toJSON (BlocksRead x) = oPath ("blocks" :| ["read"]) x
2860− toJSON (BlocksWrite x) = oPath ("blocks" :| ["write"]) x
2861− toJSON (BlocksMetaData x) = oPath ("blocks" :| ["metadata"]) x
2862−
2863−instance FromJSON UpdatableIndexSetting where
2864− parseJSON = withObject "UpdatableIndexSetting" parse
2865− where parse o = numberOfReplicas `taggedAt` ["index", "number_of_replicas"]
2866− <|> autoExpandReplicas `taggedAt` ["index", "auto_expand_replicas"]
2867− <|> refreshInterval `taggedAt` ["index", "refresh_interval"]
2868− <|> indexConcurrency `taggedAt` ["index", "concurrency"]
2869− <|> failOnMergeFailure `taggedAt` ["index", "fail_on_merge_failure"]
2870− <|> translogFlushThresholdOps `taggedAt` ["index", "translog", "flush_threshold_ops"]
2871− <|> translogFlushThresholdSize `taggedAt` ["index", "translog", "flush_threshold_size"]
2872− <|> translogFlushThresholdPeriod `taggedAt` ["index", "translog", "flush_threshold_period"]
2873− <|> translogDisableFlush `taggedAt` ["index", "translog", "disable_flush"]
2874− <|> cacheFilterMaxSize `taggedAt` ["index", "cache", "filter", "max_size"]
2875− <|> cacheFilterExpire `taggedAt` ["index", "cache", "filter", "expire"]
2876− <|> gatewaySnapshotInterval `taggedAt` ["index", "gateway", "snapshot_interval"]
2877− <|> routingAllocationInclude `taggedAt` ["index", "routing", "allocation", "include"]
2878− <|> routingAllocationExclude `taggedAt` ["index", "routing", "allocation", "exclude"]
2879− <|> routingAllocationRequire `taggedAt` ["index", "routing", "allocation", "require"]
2880− <|> routingAllocationEnable `taggedAt` ["index", "routing", "allocation", "enable"]
2881− <|> routingAllocationShardsPerNode `taggedAt` ["index", "routing", "allocation", "total_shards_per_node"]
2882− <|> recoveryInitialShards `taggedAt` ["index", "recovery", "initial_shards"]
2883− <|> gcDeletes `taggedAt` ["index", "gc_deletes"]
2884− <|> ttlDisablePurge `taggedAt` ["index", "ttl", "disable_purge"]
2885− <|> translogFSType `taggedAt` ["index", "translog", "fs", "type"]
2886− <|> compoundFormat `taggedAt` ["index", "compound_format"]
2887− <|> compoundOnFlush `taggedAt` ["index", "compound_on_flush"]
2888− <|> warmerEnabled `taggedAt` ["index", "warmer", "enabled"]
2889− <|> blocksReadOnly `taggedAt` ["blocks", "read_only"]
2890− <|> blocksRead `taggedAt` ["blocks", "read"]
2891− <|> blocksWrite `taggedAt` ["blocks", "write"]
2892− <|> blocksMetaData `taggedAt` ["blocks", "metadata"]
2893− where taggedAt f ks = taggedAt' f (Object o) ks
2894− taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON (unStringlyTypeJSON v)))
2895− taggedAt' f v (k:ks) = withObject "Object" (\o -> do v' <- o .: k
2896− taggedAt' f v' ks) v
2897− numberOfReplicas = pure . NumberOfReplicas
2898− autoExpandReplicas = pure . AutoExpandReplicas
2899− refreshInterval = pure . RefreshInterval . ndtJSON
2900− indexConcurrency = pure . IndexConcurrency
2901− failOnMergeFailure = pure . FailOnMergeFailure
2902− translogFlushThresholdOps = pure . TranslogFlushThresholdOps
2903− translogFlushThresholdSize = pure . TranslogFlushThresholdSize
2904− translogFlushThresholdPeriod = pure . TranslogFlushThresholdPeriod . ndtJSON
2905− translogDisableFlush = pure . TranslogDisableFlush
2906− cacheFilterMaxSize = pure . CacheFilterMaxSize
2907− cacheFilterExpire = pure . CacheFilterExpire . fmap ndtJSON
2908− gatewaySnapshotInterval = pure . GatewaySnapshotInterval . ndtJSON
2909− routingAllocationInclude = fmap RoutingAllocationInclude . parseAttrFilter
2910− routingAllocationExclude = fmap RoutingAllocationExclude . parseAttrFilter
2911− routingAllocationRequire = fmap RoutingAllocationRequire . parseAttrFilter
2912− routingAllocationEnable = pure . RoutingAllocationEnable
2913− routingAllocationShardsPerNode = pure . RoutingAllocationShardsPerNode
2914− recoveryInitialShards = pure . RecoveryInitialShards
2915− gcDeletes = pure . GCDeletes . ndtJSON
2916− ttlDisablePurge = pure . TTLDisablePurge
2917− translogFSType = pure . TranslogFSType
2918− compoundFormat = pure . IndexCompoundFormat
2919− compoundOnFlush = pure . IndexCompoundOnFlush
2920− warmerEnabled = pure . WarmerEnabled
2921− blocksReadOnly = pure . BlocksReadOnly
2922− blocksRead = pure . BlocksRead
2923− blocksWrite = pure . BlocksWrite
2924− blocksMetaData = pure . BlocksMetaData
2925−
2926−instance FromJSON IndexSettingsSummary where
2927− parseJSON = withObject "IndexSettingsSummary" parse
2928− where parse o = case HM.toList o of
2929− [(ixn, v@(Object o'))] -> IndexSettingsSummary (IndexName ixn)
2930− <$> parseJSON v
2931− <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings")
2932− _ -> fail "Expected single-key object with index name"
2933− redundant (NumberOfReplicas _) = True
2934− redundant _ = False
2935−
2936−-- | For some reason in several settings APIs, all leaf values get returned
2937−-- as strings. This function attepmts to recover from this for all
2938−-- non-recursive JSON types. If nothing can be done, the value is left alone.
2939−unStringlyTypeJSON :: Value -> Value
2940−unStringlyTypeJSON (String "true") = Bool True
2941−unStringlyTypeJSON (String "false") = Bool False
2942−unStringlyTypeJSON (String "null") = Null
2943−unStringlyTypeJSON v@(String t) = case readMay (T.unpack t) of
2944− Just n -> Number n
2945− Nothing -> v
2946−unStringlyTypeJSON v = v
2947−
2948−
2949−parseSettings :: Object -> Parser [UpdatableIndexSetting]
2950−parseSettings o = do
2951− o' <- o .: "index"
2952− -- slice the index object into singleton hashmaps and try to parse each
2953− parses <- forM (HM.toList o') $ \(k, v) -> do
2954− -- blocks are now nested into the "index" key, which is not how they're serialized
2955− let atRoot = Object (HM.singleton k v)
2956− let atIndex = Object (HM.singleton "index" atRoot)
2957− optional (parseJSON atRoot <|> parseJSON atIndex)
2958− return (catMaybes parses)
2959−
2960−oPath :: ToJSON a => NonEmpty Text -> a -> Value
2961−oPath (k :| []) v = object [k .= v]
2962−oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
2963−
2964−attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
2965−attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
2966− | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
2967−
2968−parseAttrFilter :: Value -> Parser (NonEmpty NodeAttrFilter)
2969−parseAttrFilter = withObject "NonEmpty NodeAttrFilter" parse
2970− where parse o = case HM.toList o of
2971− [] -> fail "Expected non-empty list of NodeAttrFilters"
2972− x:xs -> DT.mapM (uncurry parse') (x :| xs)
2973− parse' n = withText "Text" $ \t ->
2974− case T.splitOn "," t of
2975− fv:fvs -> return (NodeAttrFilter (NodeAttrName n) (fv :| fvs))
2976− [] -> fail "Expected non-empty list of filter values"
2977−
2978−instance ToJSON ReplicaBounds where
2979− toJSON (ReplicasBounded a b) = String (showText a <> "-" <> showText b)
2980− toJSON (ReplicasLowerBounded a) = String (showText a <> "-all")
2981− toJSON ReplicasUnbounded = Bool False
2982−
2983−instance FromJSON ReplicaBounds where
2984− parseJSON v = withText "ReplicaBounds" parseText v
2985− <|> withBool "ReplicaBounds" parseBool v
2986− where parseText t = case T.splitOn "-" t of
2987− [a, "all"] -> ReplicasLowerBounded <$> parseReadText a
2988− [a, b] -> ReplicasBounded <$> parseReadText a
2989− <*> parseReadText b
2990− _ -> fail ("Could not parse ReplicaBounds: " <> show t)
2991− parseBool False = pure ReplicasUnbounded
2992− parseBool _ = fail "ReplicasUnbounded cannot be represented with True"
2993−
2994−instance ToJSON AllocationPolicy where
2995− toJSON AllocAll = String "all"
2996− toJSON AllocPrimaries = String "primaries"
2997− toJSON AllocNewPrimaries = String "new_primaries"
2998− toJSON AllocNone = String "none"
2999−
3000−instance FromJSON AllocationPolicy where
3001− parseJSON = withText "AllocationPolicy" parse
3002− where parse "all" = pure AllocAll
3003− parse "primaries" = pure AllocPrimaries
3004− parse "new_primaries" = pure AllocNewPrimaries
3005− parse "none" = pure AllocNone
3006− parse t = fail ("Invlaid AllocationPolicy: " <> show t)
3007−
3008−instance ToJSON InitialShardCount where
3009− toJSON QuorumShards = String "quorum"
3010− toJSON QuorumMinus1Shards = String "quorum-1"
3011− toJSON FullShards = String "full"
3012− toJSON FullMinus1Shards = String "full-1"
3013− toJSON (ExplicitShards x) = toJSON x
3014−
3015−instance FromJSON InitialShardCount where
3016− parseJSON v = withText "InitialShardCount" parseText v
3017− <|> ExplicitShards <$> parseJSON v
3018− where parseText "quorum" = pure QuorumShards
3019− parseText "quorum-1" = pure QuorumMinus1Shards
3020− parseText "full" = pure FullShards
3021− parseText "full-1" = pure FullMinus1Shards
3022− parseText _ = mzero
3023−
3024−instance ToJSON FSType where
3025− toJSON FSSimple = "simple"
3026− toJSON FSBuffered = "buffered"
3027−
3028−instance FromJSON FSType where
3029− parseJSON = withText "FSType" parse
3030− where parse "simple" = pure FSSimple
3031− parse "buffered" = pure FSBuffered
3032− parse t = fail ("Invalid FSType: " <> show t)
3033−
3034−instance ToJSON CompoundFormat where
3035− toJSON (CompoundFileFormat x) = Bool x
3036− toJSON (MergeSegmentVsTotalIndex x) = toJSON x
3037−
3038−instance FromJSON CompoundFormat where
3039− parseJSON v = CompoundFileFormat <$> parseJSON v
3040− <|> MergeSegmentVsTotalIndex <$> parseJSON v
3041−
3042−instance ToJSON NominalDiffTimeJSON where
3043− toJSON (NominalDiffTimeJSON t) = String (showText (round t :: Integer) <> "s")
3044−
3045−instance FromJSON NominalDiffTimeJSON where
3046− parseJSON = withText "NominalDiffTime" parse
3047− where parse t = case T.takeEnd 1 t of
3048− "s" -> NominalDiffTimeJSON . fromInteger <$> parseReadText (T.dropEnd 1 t)
3049− _ -> fail "Invalid or missing NominalDiffTime unit (expected s)"
3050−
3051−instance ToJSON IndexTemplate where
3052− toJSON (IndexTemplate p s m) = merge
3053− (object [ "template" .= p
3054− , "mappings" .= foldl' merge (object []) m
3055− ])
3056− (toJSON s)
3057− where
3058− merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
3059− merge o Null = o
3060− merge _ _ = undefined
3061−
3062−instance (FromJSON a) => FromJSON (EsResult a) where
3063− parseJSON jsonVal@(Object v) = do
3064− found <- v .:? "found" .!= False
3065− fr <- if found
3066− then parseJSON jsonVal
3067− else return Nothing
3068− EsResult <$> v .: "_index" <*>
3069− v .: "_type" <*>
3070− v .: "_id" <*>
3071− pure fr
3072− parseJSON _ = empty
3073−
3074−instance (FromJSON a) => FromJSON (EsResultFound a) where
3075− parseJSON (Object v) = EsResultFound <$>
3076− v .: "_version" <*>
3077− v .: "_source"
3078− parseJSON _ = empty
3079−
3080−instance FromJSON EsError where
3081− parseJSON (Object v) = EsError <$>
3082− v .: "status" <*>
3083− (v .: "error" <|> (v .: "error" >>= (.: "reason")))
3084− parseJSON _ = empty
3085−
3086−instance FromJSON IndexAliasesSummary where
3087− parseJSON = withObject "IndexAliasesSummary" parse
3088− where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)
3089− go ixn = withObject "index aliases" $ \ia -> do
3090− aliases <- ia .:? "aliases" .!= mempty
3091− forM (HM.toList aliases) $ \(aName, v) -> do
3092− let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))
3093− IndexAliasSummary indexAlias <$> parseJSON v
3094−
3095−
3096−instance ToJSON IndexAliasAction where
3097− toJSON (AddAlias ia opts) = object ["add" .= (iaObj <> optsObj)]
3098− where Object iaObj = toJSON ia
3099− Object optsObj = toJSON opts
3100− toJSON (RemoveAlias ia) = object ["remove" .= iaObj]
3101− where Object iaObj = toJSON ia
3102−
3103−instance ToJSON IndexAlias where
3104− toJSON IndexAlias {..} = object ["index" .= srcIndex
3105− , "alias" .= indexAlias
3106− ]
3107−
3108−instance ToJSON IndexAliasCreate where
3109− toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)
3110− where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter
3111− Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting
3112−
3113−instance ToJSON AliasRouting where
3114− toJSON (AllAliasRouting v) = object ["routing" .= v]
3115− toJSON (GranularAliasRouting srch idx) = object (catMaybes prs)
3116− where prs = [("search_routing" .=) <$> srch
3117− ,("index_routing" .=) <$> idx]
3118−
3119−instance FromJSON AliasRouting where
3120− parseJSON = withObject "AliasRouting" parse
3121− where parse o = parseAll o <|> parseGranular o
3122− parseAll o = AllAliasRouting <$> o .: "routing"
3123− parseGranular o = do
3124− sr <- o .:? "search_routing"
3125− ir <- o .:? "index_routing"
3126− if isNothing sr && isNothing ir
3127− then fail "Both search_routing and index_routing can't be blank"
3128− else return (GranularAliasRouting sr ir)
3129−
3130−instance FromJSON IndexAliasCreate where
3131− parseJSON v = withObject "IndexAliasCreate" parse v
3132− where parse o = IndexAliasCreate <$> optional (parseJSON v)
3133− <*> o .:? "filter"
3134−
3135−instance ToJSON SearchAliasRouting where
3136− toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
3137−
3138−instance FromJSON SearchAliasRouting where
3139− parseJSON = withText "SearchAliasRouting" parse
3140− where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3141−
3142−instance ToJSON Search where
3143− toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource sSuggest) =
3144− omitNulls [ "query" .= query
3145− , "filter" .= sFilter
3146− , "sort" .= sort
3147− , "aggregations" .= searchAggs
3148− , "highlight" .= highlight
3149− , "from" .= sFrom
3150− , "size" .= sSize
3151− , "track_scores" .= sTrackSortScores
3152− , "fields" .= sFields
3153− , "_source" .= sSource
3154− , "suggest" .= sSuggest]
3155−
3156−
3157−instance ToJSON Source where
3158− toJSON NoSource = toJSON False
3159− toJSON (SourcePatterns patterns) = toJSON patterns
3160− toJSON (SourceIncludeExclude incl excl) = object [ "include" .= incl, "exclude" .= excl ]
3161−
3162−instance ToJSON PatternOrPatterns where
3163− toJSON (PopPattern pattern) = toJSON pattern
3164− toJSON (PopPatterns patterns) = toJSON patterns
3165−
3166−instance ToJSON Include where
3167− toJSON (Include patterns) = toJSON patterns
3168−
3169−instance ToJSON Exclude where
3170− toJSON (Exclude patterns) = toJSON patterns
3171−
3172−instance ToJSON Pattern where
3173− toJSON (Pattern pattern) = toJSON pattern
3174−
3175−
3176−instance ToJSON FieldHighlight where
3177− toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
3178− object [ fName .= fSettings ]
3179− toJSON (FieldHighlight (FieldName fName) Nothing) =
3180− object [ fName .= emptyObject ]
3181−
3182−instance ToJSON Highlights where
3183− toJSON (Highlights global fields) =
3184− omitNulls (("fields" .= fields)
3185− : highlightSettingsPairs global)
3186−
3187−instance ToJSON HighlightSettings where
3188− toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
3189−
3190−highlightSettingsPairs :: Maybe HighlightSettings -> [Pair]
3191−highlightSettingsPairs Nothing = []
3192−highlightSettingsPairs (Just (Plain plh)) = plainHighPairs (Just plh)
3193−highlightSettingsPairs (Just (Postings ph)) = postHighPairs (Just ph)
3194−highlightSettingsPairs (Just (FastVector fvh)) = fastVectorHighPairs (Just fvh)
3195−
3196−
3197−plainHighPairs :: Maybe PlainHighlight -> [Pair]
3198−plainHighPairs Nothing = []
3199−plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
3200− [ "type" .= String "plain"]
3201− ++ commonHighlightPairs plCom
3202− ++ nonPostingsToPairs plNonPost
3203−
3204−postHighPairs :: Maybe PostingsHighlight -> [Pair]
3205−postHighPairs Nothing = []
3206−postHighPairs (Just (PostingsHighlight pCom)) =
3207− ("type" .= String "postings")
3208− : commonHighlightPairs pCom
3209−
3210−fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
3211−fastVectorHighPairs Nothing = []
3212−fastVectorHighPairs (Just
3213− (FastVectorHighlight fvCom fvNonPostSettings fvBoundChars
3214− fvBoundMaxScan fvFragOff fvMatchedFields
3215− fvPhraseLim)) =
3216− [ "type" .= String "fvh"
3217− , "boundary_chars" .= fvBoundChars
3218− , "boundary_max_scan" .= fvBoundMaxScan
3219− , "fragment_offset" .= fvFragOff
3220− , "matched_fields" .= fvMatchedFields
3221− , "phraseLimit" .= fvPhraseLim]
3222− ++ commonHighlightPairs fvCom
3223− ++ nonPostingsToPairs fvNonPostSettings
3224−
3225−deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
3226−deleteSeveral ks hm = foldr HM.delete hm ks
3227−
3228−commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
3229−commonHighlightPairs Nothing = []
3230−commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
3231− chNoMatchSize chHighlightQuery
3232− chRequireFieldMatch)) =
3233− [ "order" .= chScore
3234− , "force_source" .= chForceSource
3235− , "encoder" .= chEncoder
3236− , "no_match_size" .= chNoMatchSize
3237− , "highlight_query" .= chHighlightQuery
3238− , "require_fieldMatch" .= chRequireFieldMatch]
3239− ++ highlightTagToPairs chTag
3240−
3241−
3242−nonPostingsToPairs :: Maybe NonPostings -> [Pair]
3243−nonPostingsToPairs Nothing = []
3244−nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
3245− [ "fragment_size" .= npFragSize
3246− , "number_of_fragments" .= npNumOfFrags]
3247−
3248−parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
3249−parseNEJSON [] = fail "Expected non-empty list"
3250−parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
3251−
3252−
3253−instance ToJSON HighlightEncoder where
3254− toJSON DefaultEncoder = String "default"
3255− toJSON HTMLEncoder = String "html"
3256−
3257−highlightTagToPairs :: Maybe HighlightTag -> [Pair]
3258−highlightTagToPairs (Just (TagSchema _)) = [ "scheme" .= String "default"]
3259−highlightTagToPairs (Just (CustomTags (pre, post))) = [ "pre_tags" .= pre
3260− , "post_tags" .= post]
3261−highlightTagToPairs Nothing = []
3262−
3263−instance ToJSON SortSpec where
3264− toJSON (DefaultSortSpec
3265− (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped
3266− dsSortMode dsMissingSort dsNestedFilter)) =
3267− object [dsSortFieldName .= omitNulls base] where
3268− base = [ "order" .= dsSortOrder
3269− , "ignore_unmapped" .= dsIgnoreUnmapped
3270− , "mode" .= dsSortMode
3271− , "missing" .= dsMissingSort
3272− , "nested_filter" .= dsNestedFilter ]
3273−
3274− toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
3275− object [ "unit" .= units
3276− , field .= gdsLatLon
3277− , "order" .= gdsSortOrder ]
3278−
3279−
3280−instance ToJSON SortOrder where
3281− toJSON Ascending = String "asc"
3282− toJSON Descending = String "desc"
3283−
3284−
3285−instance ToJSON SortMode where
3286− toJSON SortMin = String "min"
3287− toJSON SortMax = String "max"
3288− toJSON SortSum = String "sum"
3289− toJSON SortAvg = String "avg"
3290−
3291−
3292−instance ToJSON Missing where
3293− toJSON LastMissing = String "_last"
3294− toJSON FirstMissing = String "_first"
3295− toJSON (CustomMissing txt) = String txt
3296−
3297−
3298−instance ToJSON ScoreType where
3299− toJSON ScoreTypeMax = "max"
3300− toJSON ScoreTypeAvg = "avg"
3301− toJSON ScoreTypeSum = "sum"
3302− toJSON ScoreTypeNone = "none"
3303−
3304−instance FromJSON ScoreType where
3305− parseJSON = withText "ScoreType" parse
3306− where parse "max" = pure ScoreTypeMax
3307− parse "avg" = pure ScoreTypeAvg
3308− parse "sum" = pure ScoreTypeSum
3309− parse "none" = pure ScoreTypeNone
3310− parse t = fail ("Unexpected ScoreType: " <> show t)
3311−
3312−instance ToJSON Distance where
3313− toJSON (Distance dCoefficient dUnit) =
3314− String boltedTogether where
3315− coefText = showText dCoefficient
3316− (String unitText) = toJSON dUnit
3317− boltedTogether = mappend coefText unitText
3318−
3319−instance FromJSON Distance where
3320− parseJSON = withText "Distance" parse
3321− where parse t = Distance <$> parseCoeff nT
3322− <*> parseJSON (String unitT)
3323− where (nT, unitT) = T.span validForNumber t
3324− -- may be a better way to do this
3325− validForNumber '-' = True
3326− validForNumber '.' = True
3327− validForNumber 'e' = True
3328− validForNumber c = isNumber c
3329− parseCoeff "" = fail "Empty string cannot be parsed as number"
3330− parseCoeff s = return (read (T.unpack s))
3331−
3332−instance ToJSON DistanceUnit where
3333− toJSON Miles = String "mi"
3334− toJSON Yards = String "yd"
3335− toJSON Feet = String "ft"
3336− toJSON Inches = String "in"
3337− toJSON Kilometers = String "km"
3338− toJSON Meters = String "m"
3339− toJSON Centimeters = String "cm"
3340− toJSON Millimeters = String "mm"
3341− toJSON NauticalMiles = String "nmi"
3342−
3343−
3344−instance FromJSON DistanceUnit where
3345− parseJSON = withText "DistanceUnit" parse
3346− where parse "mi" = pure Miles
3347− parse "yd" = pure Yards
3348− parse "ft" = pure Feet
3349− parse "in" = pure Inches
3350− parse "km" = pure Kilometers
3351− parse "m" = pure Meters
3352− parse "cm" = pure Centimeters
3353− parse "mm" = pure Millimeters
3354− parse "nmi" = pure NauticalMiles
3355− parse u = fail ("Unrecognized DistanceUnit: " <> show u)
3356−
3357−instance ToJSON DistanceType where
3358− toJSON Arc = String "arc"
3359− toJSON SloppyArc = String "sloppy_arc"
3360− toJSON Plane = String "plane"
3361−
3362−instance FromJSON DistanceType where
3363− parseJSON = withText "DistanceType" parse
3364− where parse "arc" = pure Arc
3365− parse "sloppy_arc" = pure SloppyArc
3366− parse "plane" = pure Plane
3367− parse t = fail ("Unrecognized DistanceType: " <> show t)
3368−
3369−
3370−instance ToJSON OptimizeBbox where
3371− toJSON NoOptimizeBbox = String "none"
3372− toJSON (OptimizeGeoFilterType gft) = toJSON gft
3373−
3374−instance FromJSON OptimizeBbox where
3375− parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
3376− <|> parseOptimize v
3377− where parseNoOptimize "none" = pure NoOptimizeBbox
3378− parseNoOptimize _ = mzero
3379− parseOptimize = fmap OptimizeGeoFilterType . parseJSON
3380−
3381−instance ToJSON GeoBoundingBoxConstraint where
3382− toJSON (GeoBoundingBoxConstraint
3383− (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =
3384− object [gbbcGeoBBField .= gbbcConstraintBox
3385− , "_cache" .= cache
3386− , "type" .= type']
3387−
3388−instance FromJSON GeoBoundingBoxConstraint where
3389− parseJSON = withObject "GeoBoundingBoxConstraint" parse
3390− where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of
3391− [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)
3392− <$> parseJSON v
3393− <*> o .:? "_cache" .!= defaultCache
3394− <*> o .: "type"
3395− _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
3396−
3397−instance ToJSON GeoFilterType where
3398− toJSON GeoFilterMemory = String "memory"
3399− toJSON GeoFilterIndexed = String "indexed"
3400−
3401−instance FromJSON GeoFilterType where
3402− parseJSON = withText "GeoFilterType" parse
3403− where parse "memory" = pure GeoFilterMemory
3404− parse "indexed" = pure GeoFilterIndexed
3405− parse t = fail ("Unrecognized GeoFilterType: " <> show t)
3406−
3407−instance ToJSON GeoBoundingBox where
3408− toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
3409− object ["top_left" .= gbbTopLeft
3410− , "bottom_right" .= gbbBottomRight]
3411−
3412−instance FromJSON GeoBoundingBox where
3413− parseJSON = withObject "GeoBoundingBox" parse
3414− where parse o = GeoBoundingBox
3415− <$> o .: "top_left"
3416− <*> o .: "bottom_right"
3417−
3418−instance ToJSON LatLon where
3419− toJSON (LatLon lLat lLon) =
3420− object ["lat" .= lLat
3421− , "lon" .= lLon]
3422−
3423−instance FromJSON LatLon where
3424− parseJSON = withObject "LatLon" parse
3425− where parse o = LatLon <$> o .: "lat"
3426− <*> o .: "lon"
3427−
3428−-- index for smaller ranges, fielddata for longer ranges
3429−instance ToJSON RangeExecution where
3430− toJSON RangeExecutionIndex = "index"
3431− toJSON RangeExecutionFielddata = "fielddata"
3432−
3433−
3434−instance FromJSON RangeExecution where
3435− parseJSON = withText "RangeExecution" parse
3436− where parse "index" = pure RangeExecutionIndex
3437− parse "fielddata" = pure RangeExecutionFielddata
3438− parse t = error ("Unrecognized RangeExecution " <> show t)
3439−
3440−instance ToJSON RegexpFlags where
3441− toJSON AllRegexpFlags = String "ALL"
3442− toJSON NoRegexpFlags = String "NONE"
3443− toJSON (SomeRegexpFlags (h :| fs)) = String $ T.intercalate "|" flagStrs
3444− where flagStrs = map flagStr . nub $ h:fs
3445− flagStr AnyString = "ANYSTRING"
3446− flagStr Automaton = "AUTOMATON"
3447− flagStr Complement = "COMPLEMENT"
3448− flagStr Empty = "EMPTY"
3449− flagStr Intersection = "INTERSECTION"
3450− flagStr Interval = "INTERVAL"
3451−
3452−instance FromJSON RegexpFlags where
3453− parseJSON = withText "RegexpFlags" parse
3454− where parse "ALL" = pure AllRegexpFlags
3455− parse "NONE" = pure NoRegexpFlags
3456− parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
3457−
3458−instance FromJSON RegexpFlag where
3459− parseJSON = withText "RegexpFlag" parse
3460− where parse "ANYSTRING" = pure AnyString
3461− parse "AUTOMATON" = pure Automaton
3462− parse "COMPLEMENT" = pure Complement
3463− parse "EMPTY" = pure Empty
3464− parse "INTERSECTION" = pure Intersection
3465− parse "INTERVAL" = pure Interval
3466− parse f = fail ("Unknown RegexpFlag: " <> show f)
3467−
3468−instance ToJSON Term where
3469− toJSON (Term field value) = object ["term" .= object
3470− [field .= value]]
3471−
3472−instance FromJSON Term where
3473− parseJSON = withObject "Term" parse
3474− where parse o = do termObj <- o .: "term"
3475− case HM.toList termObj of
3476− [(fn, v)] -> Term fn <$> parseJSON v
3477− _ -> fail "Expected object with 1 field-named key"
3478−
3479−instance ToJSON BoolMatch where
3480− toJSON (MustMatch term cache) = object ["must" .= term,
3481− "_cache" .= cache]
3482− toJSON (MustNotMatch term cache) = object ["must_not" .= term,
3483− "_cache" .= cache]
3484− toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
3485− "_cache" .= cache]
3486−
3487−instance FromJSON BoolMatch where
3488− parseJSON = withObject "BoolMatch" parse
3489− where parse o = mustMatch `taggedWith` "must"
3490− <|> mustNotMatch `taggedWith` "must_not"
3491− <|> shouldMatch `taggedWith` "should"
3492− where taggedWith parser k = parser =<< o .: k
3493− mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
3494− mustNotMatch t = MustNotMatch t <$> o .:? "_cache" .!= defaultCache
3495− shouldMatch t = ShouldMatch t <$> o .:? "_cache" .!= defaultCache
3496
443
3497instance (FromJSON a) => FromJSON (SearchResult a) where
444instance (FromJSON a) => FromJSON (SearchResult a) where
3498 parseJSON (Object v) = SearchResult <$>
445 parseJSON (Object v) = SearchResult <$>
@@ -3504,1747 +451,3 @@ instance (FromJSON a) => FromJSON (SearchResult a) where
3504 v .:? "_scroll_id" <*>
451 v .:? "_scroll_id" <*>
3505 v .:? "suggest"
452 v .:? "suggest"
3506 parseJSON _ = empty
453 parseJSON _ = empty
3507−
3508−instance (FromJSON a) => FromJSON (SearchHits a) where
3509− parseJSON (Object v) = SearchHits <$>
3510− v .: "total" <*>
3511− v .: "max_score" <*>
3512− v .: "hits"
3513− parseJSON _ = empty
3514−
3515−instance (FromJSON a) => FromJSON (Hit a) where
3516− parseJSON (Object v) = Hit <$>
3517− v .: "_index" <*>
3518− v .: "_type" <*>
3519− v .: "_id" <*>
3520− v .: "_score" <*>
3521− v .:? "_source" <*>
3522− v .:? "highlight"
3523− parseJSON _ = empty
3524−
3525−instance FromJSON ShardResult where
3526− parseJSON (Object v) = ShardResult <$>
3527− v .: "total" <*>
3528− v .: "successful" <*>
3529− v .: "failed"
3530− parseJSON _ = empty
3531−
3532−
3533−instance FromJSON DocVersion where
3534− parseJSON v = do
3535− i <- parseJSON v
3536− maybe (fail "DocVersion out of range") return $ mkDocVersion i
3537−
3538−-- This insanity is because ES *sometimes* returns Replica/Shard counts as strings
3539−instance FromJSON ReplicaCount where
3540− parseJSON v = parseAsInt v
3541− <|> parseAsString v
3542− where parseAsInt = fmap ReplicaCount . parseJSON
3543− parseAsString = withText "ReplicaCount" (fmap ReplicaCount . parseReadText)
3544−
3545−instance FromJSON ShardCount where
3546− parseJSON v = parseAsInt v
3547− <|> parseAsString v
3548− where parseAsInt = fmap ShardCount . parseJSON
3549− parseAsString = withText "ShardCount" (fmap ShardCount . parseReadText)
3550−
3551−instance Bounded DocVersion where
3552− minBound = DocVersion 1
3553− maxBound = DocVersion 9200000000000000000 -- 9.2e+18
3554−
3555−instance Enum DocVersion where
3556− succ x
3557− | x /= maxBound = DocVersion (succ $ docVersionNumber x)
3558− | otherwise = succError "DocVersion"
3559− pred x
3560− | x /= minBound = DocVersion (pred $ docVersionNumber x)
3561− | otherwise = predError "DocVersion"
3562− toEnum i =
3563− fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
3564− fromEnum = docVersionNumber
3565− enumFrom = boundedEnumFrom
3566− enumFromThen = boundedEnumFromThen
3567−
3568−-- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
3569−newtype EsUsername = EsUsername { esUsername :: Text } deriving (Read, Show, Eq)
3570−
3571−-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
3572−newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3573−
3574−
3575−data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
3576− | AllSnapshotRepos deriving (Eq, Generic, Show, Typeable)
3577−
3578−
3579−-- | Either specifies an exact repo name or one with globs in it,
3580−-- e.g. @RepoPattern "foo*"@ __NOTE__: Patterns are not supported on ES < 1.7
3581−data SnapshotRepoPattern = ExactRepo SnapshotRepoName
3582− | RepoPattern Text
3583− deriving (Eq, Generic, Show, Typeable)
3584−
3585−-- | The unique name of a snapshot repository.
3586−newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3587− deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
3588−
3589−
3590−-- | A generic representation of a snapshot repo. This is what gets
3591−-- sent to and parsed from the server. For repo types enabled by
3592−-- plugins that aren't exported by this library, consider making a
3593−-- custom type which implements 'SnapshotRepo'. If it is a common repo
3594−-- type, consider submitting a pull request to have it included in the
3595−-- library proper
3596−data GenericSnapshotRepo = GenericSnapshotRepo {
3597− gSnapshotRepoName :: SnapshotRepoName
3598− , gSnapshotRepoType :: SnapshotRepoType
3599− , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
3600− } deriving (Eq, Generic, Show, Typeable)
3601−
3602−
3603−instance SnapshotRepo GenericSnapshotRepo where
3604− toGSnapshotRepo = id
3605− fromGSnapshotRepo = Right
3606−
3607−
3608−newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3609− deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
3610−
3611−
3612−-- | Opaque representation of snapshot repo settings. Instances of
3613−-- 'SnapshotRepo' will produce this.
3614−newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
3615− deriving (Eq, Generic, Show, Typeable, ToJSON)
3616−
3617−
3618− -- Regardless of whether you send strongly typed json, my version of
3619− -- ES sends back stringly typed json in the settings, e.g. booleans
3620− -- as strings, so we'll try to convert them.
3621−instance FromJSON GenericSnapshotRepoSettings where
3622− parseJSON = fmap (GenericSnapshotRepoSettings . fmap unStringlyTypeJSON). parseJSON
3623−
3624−-- | The result of running 'verifySnapshotRepo'.
3625−newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
3626− deriving (Eq, Generic, Show, Typeable)
3627−
3628−
3629−instance FromJSON SnapshotVerification where
3630− parseJSON = withObject "SnapshotVerification" parse
3631− where
3632− parse o = do
3633− o2 <- o .: "nodes"
3634− SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
3635− parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
3636− SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
3637−
3638−
3639−-- | A node that has verified a snapshot
3640−data SnapshotNodeVerification = SnapshotNodeVerification {
3641− snvFullId :: FullNodeId
3642− , snvNodeName :: NodeName
3643− } deriving (Eq, Generic, Show, Typeable)
3644−
3645−
3646−-- | Unique, automatically-generated name assigned to nodes that are
3647−-- usually returned in node-oriented APIs.
3648−newtype FullNodeId = FullNodeId { fullNodeId :: Text }
3649− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3650−
3651−
3652−-- | A human-readable node name that is supplied by the user in the
3653−-- node config or automatically generated by ElasticSearch.
3654−newtype NodeName = NodeName { nodeName :: Text }
3655− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3656−
3657−newtype ClusterName = ClusterName { clusterName :: Text }
3658− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3659−
3660−data NodesInfo = NodesInfo {
3661− nodesInfo :: [NodeInfo]
3662− , nodesClusterName :: ClusterName
3663− } deriving (Eq, Show, Generic, Typeable)
3664−
3665−data NodesStats = NodesStats {
3666− nodesStats :: [NodeStats]
3667− , nodesStatsClusterName :: ClusterName
3668− } deriving (Eq, Show, Generic, Typeable)
3669−
3670−data NodeStats = NodeStats {
3671− nodeStatsName :: NodeName
3672− , nodeStatsFullId :: FullNodeId
3673− , nodeStatsBreakersStats :: Maybe NodeBreakersStats
3674− , nodeStatsHTTP :: NodeHTTPStats
3675− , nodeStatsTransport :: NodeTransportStats
3676− , nodeStatsFS :: NodeFSStats
3677− , nodeStatsNetwork :: NodeNetworkStats
3678− , nodeStatsThreadPool :: NodeThreadPoolsStats
3679− , nodeStatsJVM :: NodeJVMStats
3680− , nodeStatsProcess :: NodeProcessStats
3681− , nodeStatsOS :: NodeOSStats
3682− , nodeStatsIndices :: NodeIndicesStats
3683− } deriving (Eq, Show, Generic, Typeable)
3684−
3685−data NodeBreakersStats = NodeBreakersStats {
3686− nodeStatsParentBreaker :: NodeBreakerStats
3687− , nodeStatsRequestBreaker :: NodeBreakerStats
3688− , nodeStatsFieldDataBreaker :: NodeBreakerStats
3689− } deriving (Eq, Show, Generic, Typeable)
3690−
3691−data NodeBreakerStats = NodeBreakerStats {
3692− nodeBreakersTripped :: Int
3693− , nodeBreakersOverhead :: Double
3694− , nodeBreakersEstSize :: Bytes
3695− , nodeBreakersLimitSize :: Bytes
3696− } deriving (Eq, Show, Generic, Typeable)
3697−
3698−data NodeHTTPStats = NodeHTTPStats {
3699− nodeHTTPTotalOpened :: Int
3700− , nodeHTTPCurrentOpen :: Int
3701− } deriving (Eq, Show, Generic, Typeable)
3702−
3703−data NodeTransportStats = NodeTransportStats {
3704− nodeTransportTXSize :: Bytes
3705− , nodeTransportCount :: Int
3706− , nodeTransportRXSize :: Bytes
3707− , nodeTransportRXCount :: Int
3708− , nodeTransportServerOpen :: Int
3709− } deriving (Eq, Show, Generic, Typeable)
3710−
3711−data NodeFSStats = NodeFSStats {
3712− nodeFSDataPaths :: [NodeDataPathStats]
3713− , nodeFSTotal :: NodeFSTotalStats
3714− , nodeFSTimestamp :: UTCTime
3715− } deriving (Eq, Show, Generic, Typeable)
3716−
3717−data NodeDataPathStats = NodeDataPathStats {
3718− nodeDataPathDiskServiceTime :: Maybe Double
3719− , nodeDataPathDiskQueue :: Maybe Double
3720− , nodeDataPathIOSize :: Maybe Bytes
3721− , nodeDataPathWriteSize :: Maybe Bytes
3722− , nodeDataPathReadSize :: Maybe Bytes
3723− , nodeDataPathIOOps :: Maybe Int
3724− , nodeDataPathWrites :: Maybe Int
3725− , nodeDataPathReads :: Maybe Int
3726− , nodeDataPathAvailable :: Bytes
3727− , nodeDataPathFree :: Bytes
3728− , nodeDataPathTotal :: Bytes
3729− , nodeDataPathType :: Maybe Text
3730− , nodeDataPathDevice :: Text
3731− , nodeDataPathMount :: Text
3732− , nodeDataPathPath :: Text
3733− } deriving (Eq, Show, Generic, Typeable)
3734−
3735−data NodeFSTotalStats = NodeFSTotalStats {
3736− nodeFSTotalDiskServiceTime :: Maybe Double
3737− , nodeFSTotalDiskQueue :: Maybe Double
3738− , nodeFSTotalIOSize :: Maybe Bytes
3739− , nodeFSTotalWriteSize :: Maybe Bytes
3740− , nodeFSTotalReadSize :: Maybe Bytes
3741− , nodeFSTotalIOOps :: Maybe Int
3742− , nodeFSTotalWrites :: Maybe Int
3743− , nodeFSTotalReads :: Maybe Int
3744− , nodeFSTotalAvailable :: Bytes
3745− , nodeFSTotalFree :: Bytes
3746− , nodeFSTotalTotal :: Bytes
3747− } deriving (Eq, Show, Generic, Typeable)
3748−
3749−data NodeNetworkStats = NodeNetworkStats {
3750− nodeNetTCPOutRSTs :: Int
3751− , nodeNetTCPInErrs :: Int
3752− , nodeNetTCPAttemptFails :: Int
3753− , nodeNetTCPEstabResets :: Int
3754− , nodeNetTCPRetransSegs :: Int
3755− , nodeNetTCPOutSegs :: Int
3756− , nodeNetTCPInSegs :: Int
3757− , nodeNetTCPCurrEstab :: Int
3758− , nodeNetTCPPassiveOpens :: Int
3759− , nodeNetTCPActiveOpens :: Int
3760− } deriving (Eq, Show, Generic, Typeable)
3761−
3762−data NodeThreadPoolsStats = NodeThreadPoolsStats {
3763− nodeThreadPoolsStatsSnapshot :: NodeThreadPoolStats
3764− , nodeThreadPoolsStatsBulk :: NodeThreadPoolStats
3765− , nodeThreadPoolsStatsMerge :: NodeThreadPoolStats
3766− , nodeThreadPoolsStatsGet :: NodeThreadPoolStats
3767− , nodeThreadPoolsStatsManagement :: NodeThreadPoolStats
3768− , nodeThreadPoolsStatsFetchShardStore :: Maybe NodeThreadPoolStats
3769− , nodeThreadPoolsStatsOptimize :: NodeThreadPoolStats
3770− , nodeThreadPoolsStatsFlush :: NodeThreadPoolStats
3771− , nodeThreadPoolsStatsSearch :: NodeThreadPoolStats
3772− , nodeThreadPoolsStatsWarmer :: NodeThreadPoolStats
3773− , nodeThreadPoolsStatsGeneric :: NodeThreadPoolStats
3774− , nodeThreadPoolsStatsSuggest :: NodeThreadPoolStats
3775− , nodeThreadPoolsStatsRefresh :: NodeThreadPoolStats
3776− , nodeThreadPoolsStatsIndex :: NodeThreadPoolStats
3777− , nodeThreadPoolsStatsListener :: Maybe NodeThreadPoolStats
3778− , nodeThreadPoolsStatsFetchShardStarted :: Maybe NodeThreadPoolStats
3779− , nodeThreadPoolsStatsPercolate :: NodeThreadPoolStats
3780− } deriving (Eq, Show, Generic, Typeable)
3781−
3782−data NodeThreadPoolStats = NodeThreadPoolStats {
3783− nodeThreadPoolCompleted :: Int
3784− , nodeThreadPoolLargest :: Int
3785− , nodeThreadPoolRejected :: Int
3786− , nodeThreadPoolActive :: Int
3787− , nodeThreadPoolQueue :: Int
3788− , nodeThreadPoolThreads :: Int
3789− } deriving (Eq, Show, Generic, Typeable)
3790−
3791−data NodeJVMStats = NodeJVMStats {
3792− nodeJVMStatsMappedBufferPool :: JVMBufferPoolStats
3793− , nodeJVMStatsDirectBufferPool :: JVMBufferPoolStats
3794− , nodeJVMStatsGCOldCollector :: JVMGCStats
3795− , nodeJVMStatsGCYoungCollector :: JVMGCStats
3796− , nodeJVMStatsPeakThreadsCount :: Int
3797− , nodeJVMStatsThreadsCount :: Int
3798− , nodeJVMStatsOldPool :: JVMPoolStats
3799− , nodeJVMStatsSurvivorPool :: JVMPoolStats
3800− , nodeJVMStatsYoungPool :: JVMPoolStats
3801− , nodeJVMStatsNonHeapCommitted :: Bytes
3802− , nodeJVMStatsNonHeapUsed :: Bytes
3803− , nodeJVMStatsHeapMax :: Bytes
3804− , nodeJVMStatsHeapCommitted :: Bytes
3805− , nodeJVMStatsHeapUsedPercent :: Int
3806− , nodeJVMStatsHeapUsed :: Bytes
3807− , nodeJVMStatsUptime :: NominalDiffTime
3808− , nodeJVMStatsTimestamp :: UTCTime
3809− } deriving (Eq, Show, Generic, Typeable)
3810−
3811−data JVMBufferPoolStats = JVMBufferPoolStats {
3812− jvmBufferPoolStatsTotalCapacity :: Bytes
3813− , jvmBufferPoolStatsUsed :: Bytes
3814− , jvmBufferPoolStatsCount :: Int
3815− } deriving (Eq, Show, Generic, Typeable)
3816−
3817−data JVMGCStats = JVMGCStats {
3818− jvmGCStatsCollectionTime :: NominalDiffTime
3819− , jvmGCStatsCollectionCount :: Int
3820− } deriving (Eq, Show, Generic, Typeable)
3821−
3822−data JVMPoolStats = JVMPoolStats {
3823− jvmPoolStatsPeakMax :: Bytes
3824− , jvmPoolStatsPeakUsed :: Bytes
3825− , jvmPoolStatsMax :: Bytes
3826− , jvmPoolStatsUsed :: Bytes
3827− } deriving (Eq, Show, Generic, Typeable)
3828−
3829−data NodeProcessStats = NodeProcessStats {
3830− nodeProcessMemTotalVirtual :: Bytes
3831− , nodeProcessMemShare :: Bytes
3832− , nodeProcessMemResident :: Bytes
3833− , nodeProcessCPUTotal :: NominalDiffTime
3834− , nodeProcessCPUUser :: NominalDiffTime
3835− , nodeProcessCPUSys :: NominalDiffTime
3836− , nodeProcessCPUPercent :: Int
3837− , nodeProcessOpenFDs :: Int
3838− , nodeProcessTimestamp :: UTCTime
3839− } deriving (Eq, Show, Generic, Typeable)
3840−
3841−data NodeOSStats = NodeOSStats {
3842− nodeOSSwapFree :: Bytes
3843− , nodeOSSwapUsed :: Bytes
3844− , nodeOSMemActualUsed :: Bytes
3845− , nodeOSMemActualFree :: Bytes
3846− , nodeOSMemUsedPercent :: Int
3847− , nodeOSMemFreePercent :: Int
3848− , nodeOSMemUsed :: Bytes
3849− , nodeOSMemFree :: Bytes
3850− , nodeOSCPUStolen :: Int
3851− , nodeOSCPUUsage :: Int
3852− , nodeOSCPUIdle :: Int
3853− , nodeOSCPUUser :: Int
3854− , nodeOSCPUSys :: Int
3855− , nodeOSLoad :: Maybe LoadAvgs
3856− , nodeOSUptime :: NominalDiffTime
3857− , nodeOSTimestamp :: UTCTime
3858− } deriving (Eq, Show, Generic, Typeable)
3859−
3860−data LoadAvgs = LoadAvgs {
3861− loadAvg1Min :: Double
3862− , loadAvg5Min :: Double
3863− , loadAvg15Min :: Double
3864− } deriving (Eq, Show, Generic, Typeable)
3865−
3866−data NodeIndicesStats = NodeIndicesStats {
3867− nodeIndicesStatsRecoveryThrottleTime :: Maybe NominalDiffTime
3868− , nodeIndicesStatsRecoveryCurrentAsTarget :: Maybe Int
3869− , nodeIndicesStatsRecoveryCurrentAsSource :: Maybe Int
3870− , nodeIndicesStatsQueryCacheMisses :: Maybe Int
3871− , nodeIndicesStatsQueryCacheHits :: Maybe Int
3872− , nodeIndicesStatsQueryCacheEvictions :: Maybe Int
3873− , nodeIndicesStatsQueryCacheSize :: Maybe Bytes
3874− , nodeIndicesStatsSuggestCurrent :: Int
3875− , nodeIndicesStatsSuggestTime :: NominalDiffTime
3876− , nodeIndicesStatsSuggestTotal :: Int
3877− , nodeIndicesStatsTranslogSize :: Bytes
3878− , nodeIndicesStatsTranslogOps :: Int
3879− , nodeIndicesStatsSegFixedBitSetMemory :: Maybe Bytes
3880− , nodeIndicesStatsSegVersionMapMemory :: Bytes
3881− , nodeIndicesStatsSegIndexWriterMaxMemory :: Maybe Bytes
3882− , nodeIndicesStatsSegIndexWriterMemory :: Bytes
3883− , nodeIndicesStatsSegMemory :: Bytes
3884− , nodeIndicesStatsSegCount :: Int
3885− , nodeIndicesStatsCompletionSize :: Bytes
3886− , nodeIndicesStatsPercolateQueries :: Int
3887− , nodeIndicesStatsPercolateMemory :: Bytes
3888− , nodeIndicesStatsPercolateCurrent :: Int
3889− , nodeIndicesStatsPercolateTime :: NominalDiffTime
3890− , nodeIndicesStatsPercolateTotal :: Int
3891− , nodeIndicesStatsFieldDataEvictions :: Int
3892− , nodeIndicesStatsFieldDataMemory :: Bytes
3893− , nodeIndicesStatsIDCacheMemory :: Bytes
3894− , nodeIndicesStatsFilterCacheEvictions :: Int
3895− , nodeIndicesStatsFilterCacheMemory :: Bytes
3896− , nodeIndicesStatsWarmerTotalTime :: NominalDiffTime
3897− , nodeIndicesStatsWarmerTotal :: Int
3898− , nodeIndicesStatsWarmerCurrent :: Int
3899− , nodeIndicesStatsFlushTotalTime :: NominalDiffTime
3900− , nodeIndicesStatsFlushTotal :: Int
3901− , nodeIndicesStatsRefreshTotalTime :: NominalDiffTime
3902− , nodeIndicesStatsRefreshTotal :: Int
3903− , nodeIndicesStatsMergesTotalSize :: Bytes
3904− , nodeIndicesStatsMergesTotalDocs :: Int
3905− , nodeIndicesStatsMergesTotalTime :: NominalDiffTime
3906− , nodeIndicesStatsMergesTotal :: Int
3907− , nodeIndicesStatsMergesCurrentSize :: Bytes
3908− , nodeIndicesStatsMergesCurrentDocs :: Int
3909− , nodeIndicesStatsMergesCurrent :: Int
3910− , nodeIndicesStatsSearchFetchCurrent :: Int
3911− , nodeIndicesStatsSearchFetchTime :: NominalDiffTime
3912− , nodeIndicesStatsSearchFetchTotal :: Int
3913− , nodeIndicesStatsSearchQueryCurrent :: Int
3914− , nodeIndicesStatsSearchQueryTime :: NominalDiffTime
3915− , nodeIndicesStatsSearchQueryTotal :: Int
3916− , nodeIndicesStatsSearchOpenContexts :: Int
3917− , nodeIndicesStatsGetCurrent :: Int
3918− , nodeIndicesStatsGetMissingTime :: NominalDiffTime
3919− , nodeIndicesStatsGetMissingTotal :: Int
3920− , nodeIndicesStatsGetExistsTime :: NominalDiffTime
3921− , nodeIndicesStatsGetExistsTotal :: Int
3922− , nodeIndicesStatsGetTime :: NominalDiffTime
3923− , nodeIndicesStatsGetTotal :: Int
3924− , nodeIndicesStatsIndexingThrottleTime :: Maybe NominalDiffTime
3925− , nodeIndicesStatsIndexingIsThrottled :: Maybe Bool
3926− , nodeIndicesStatsIndexingNoopUpdateTotal :: Maybe Int
3927− , nodeIndicesStatsIndexingDeleteCurrent :: Int
3928− , nodeIndicesStatsIndexingDeleteTime :: NominalDiffTime
3929− , nodeIndicesStatsIndexingDeleteTotal :: Int
3930− , nodeIndicesStatsIndexingIndexCurrent :: Int
3931− , nodeIndicesStatsIndexingIndexTime :: NominalDiffTime
3932− , nodeIndicesStatsIndexingTotal :: Int
3933− , nodeIndicesStatsStoreThrottleTime :: NominalDiffTime
3934− , nodeIndicesStatsStoreSize :: Bytes
3935− , nodeIndicesStatsDocsDeleted :: Int
3936− , nodeIndicesStatsDocsCount :: Int
3937− } deriving (Eq, Show, Generic, Typeable)
3938−
3939−-- | A quirky address format used throughout ElasticSearch. An example
3940−-- would be inet[/1.1.1.1:9200]. inet may be a placeholder for a
3941−-- <https://en.wikipedia.org/wiki/Fully_qualified_domain_name FQDN>.
3942−newtype EsAddress = EsAddress { esAddress :: Text }
3943− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3944−
3945−-- | Typically a 7 character hex string.
3946−newtype BuildHash = BuildHash { buildHash :: Text }
3947− deriving (Eq, Ord, Generic, Read, Show, Typeable, FromJSON, ToJSON)
3948−
3949−newtype PluginName = PluginName { pluginName :: Text }
3950− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3951−
3952−data NodeInfo = NodeInfo {
3953− nodeInfoHTTPAddress :: EsAddress
3954− , nodeInfoBuild :: BuildHash
3955− , nodeInfoESVersion :: VersionNumber
3956− , nodeInfoIP :: Server
3957− , nodeInfoHost :: Server
3958− , nodeInfoTransportAddress :: EsAddress
3959− , nodeInfoName :: NodeName
3960− , nodeInfoFullId :: FullNodeId
3961− , nodeInfoPlugins :: [NodePluginInfo]
3962− , nodeInfoHTTP :: NodeHTTPInfo
3963− , nodeInfoTransport :: NodeTransportInfo
3964− , nodeInfoNetwork :: NodeNetworkInfo
3965− , nodeInfoThreadPool :: NodeThreadPoolsInfo
3966− , nodeInfoJVM :: NodeJVMInfo
3967− , nodeInfoProcess :: NodeProcessInfo
3968− , nodeInfoOS :: NodeOSInfo
3969− , nodeInfoSettings :: Object
3970− -- ^ The members of the settings objects are not consistent,
3971− -- dependent on plugins, etc.
3972− } deriving (Eq, Show, Generic, Typeable)
3973−
3974−data NodePluginInfo = NodePluginInfo {
3975− nodePluginSite :: Bool
3976− -- ^ Is this a site plugin?
3977− , nodePluginJVM :: Bool
3978− -- ^ Is this plugin running on the JVM
3979− , nodePluginDescription :: Text
3980− , nodePluginVersion :: MaybeNA VersionNumber
3981− , nodePluginName :: PluginName
3982− } deriving (Eq, Show, Generic, Typeable)
3983−
3984−data NodeHTTPInfo = NodeHTTPInfo {
3985− nodeHTTPMaxContentLength :: Bytes
3986− , nodeHTTPTransportAddress :: BoundTransportAddress
3987− } deriving (Eq, Show, Generic, Typeable)
3988−
3989−data NodeTransportInfo = NodeTransportInfo {
3990− nodeTransportProfiles :: [BoundTransportAddress]
3991− , nodeTransportAddress :: BoundTransportAddress
3992− } deriving (Eq, Show, Generic, Typeable)
3993−
3994−data BoundTransportAddress = BoundTransportAddress {
3995− publishAddress :: EsAddress
3996− , boundAddress :: EsAddress
3997− } deriving (Eq, Show, Generic, Typeable)
3998−
3999−data NodeNetworkInfo = NodeNetworkInfo {
4000− nodeNetworkPrimaryInterface :: NodeNetworkInterface
4001− , nodeNetworkRefreshInterval :: NominalDiffTime
4002− } deriving (Eq, Show, Generic, Typeable)
4003−
4004−newtype MacAddress = MacAddress { macAddress :: Text }
4005− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4006−
4007−newtype NetworkInterfaceName = NetworkInterfaceName { networkInterfaceName :: Text }
4008− deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4009−
4010−data NodeNetworkInterface = NodeNetworkInterface {
4011− nodeNetIfaceMacAddress :: MacAddress
4012− , nodeNetIfaceName :: NetworkInterfaceName
4013− , nodeNetIfaceAddress :: Server
4014− } deriving (Eq, Show, Generic, Typeable)
4015−
4016−data NodeThreadPoolsInfo = NodeThreadPoolsInfo {
4017− nodeThreadPoolsRefresh :: NodeThreadPoolInfo
4018− , nodeThreadPoolsManagement :: NodeThreadPoolInfo
4019− , nodeThreadPoolsPercolate :: NodeThreadPoolInfo
4020− , nodeThreadPoolsListener :: Maybe NodeThreadPoolInfo
4021− , nodeThreadPoolsFetchShardStarted :: Maybe NodeThreadPoolInfo
4022− , nodeThreadPoolsSearch :: NodeThreadPoolInfo
4023− , nodeThreadPoolsFlush :: NodeThreadPoolInfo
4024− , nodeThreadPoolsWarmer :: NodeThreadPoolInfo
4025− , nodeThreadPoolsOptimize :: NodeThreadPoolInfo
4026− , nodeThreadPoolsBulk :: NodeThreadPoolInfo
4027− , nodeThreadPoolsSuggest :: NodeThreadPoolInfo
4028− , nodeThreadPoolsMerge :: NodeThreadPoolInfo
4029− , nodeThreadPoolsSnapshot :: NodeThreadPoolInfo
4030− , nodeThreadPoolsGet :: NodeThreadPoolInfo
4031− , nodeThreadPoolsFetchShardStore :: Maybe NodeThreadPoolInfo
4032− , nodeThreadPoolsIndex :: NodeThreadPoolInfo
4033− , nodeThreadPoolsGeneric :: NodeThreadPoolInfo
4034− } deriving (Eq, Show, Generic, Typeable)
4035−
4036−data NodeThreadPoolInfo = NodeThreadPoolInfo {
4037− nodeThreadPoolQueueSize :: ThreadPoolSize
4038− , nodeThreadPoolKeepalive :: Maybe NominalDiffTime
4039− , nodeThreadPoolMin :: Maybe Int
4040− , nodeThreadPoolMax :: Maybe Int
4041− , nodeThreadPoolType :: ThreadPoolType
4042− } deriving (Eq, Show, Generic, Typeable)
4043−
4044−data ThreadPoolSize = ThreadPoolBounded Int
4045− | ThreadPoolUnbounded
4046− deriving (Eq, Show, Generic, Typeable)
4047−
4048−data ThreadPoolType = ThreadPoolScaling
4049− | ThreadPoolFixed
4050− | ThreadPoolCached
4051− deriving (Eq, Show, Generic, Typeable)
4052−
4053−data NodeJVMInfo = NodeJVMInfo {
4054− nodeJVMInfoMemoryPools :: [JVMMemoryPool]
4055− , nodeJVMInfoMemoryPoolsGCCollectors :: [JVMGCCollector]
4056− , nodeJVMInfoMemoryInfo :: JVMMemoryInfo
4057− , nodeJVMInfoStartTime :: UTCTime
4058− , nodeJVMInfoVMVendor :: Text
4059− , nodeJVMVMVersion :: VersionNumber
4060− -- ^ JVM doesn't seme to follow normal version conventions
4061− , nodeJVMVMName :: Text
4062− , nodeJVMVersion :: VersionNumber
4063− , nodeJVMPID :: PID
4064− } deriving (Eq, Show, Generic, Typeable)
4065−
4066−-- | Handles quirks in the way JVM versions are rendered (1.7.0_101 -> 1.7.0.101)
4067−newtype JVMVersion = JVMVersion { unJVMVersion :: VersionNumber }
4068−
4069−data JVMMemoryInfo = JVMMemoryInfo {
4070− jvmMemoryInfoDirectMax :: Bytes
4071− , jvmMemoryInfoNonHeapMax :: Bytes
4072− , jvmMemoryInfoNonHeapInit :: Bytes
4073− , jvmMemoryInfoHeapMax :: Bytes
4074− , jvmMemoryInfoHeapInit :: Bytes
4075− } deriving (Eq, Show, Generic, Typeable)
4076−
4077−newtype JVMMemoryPool = JVMMemoryPool {
4078− jvmMemoryPool :: Text
4079− } deriving (Eq, Show, Generic, Typeable, FromJSON)
4080−
4081−newtype JVMGCCollector = JVMGCCollector {
4082− jvmGCCollector :: Text
4083− } deriving (Eq, Show, Generic, Typeable, FromJSON)
4084−
4085−newtype PID = PID {
4086− pid :: Int
4087− } deriving (Eq, Show, Generic, Typeable, FromJSON)
4088−
4089−data NodeOSInfo = NodeOSInfo {
4090− nodeOSSwap :: Bytes
4091− , nodeOSMem :: Bytes
4092− , nodeOSCPUInfo :: CPUInfo
4093− , nodeOSAvailableProcessors :: Int
4094− , nodeOSRefreshInterval :: NominalDiffTime
4095− } deriving (Eq, Show, Generic, Typeable)
4096−
4097−data CPUInfo = CPUInfo {
4098− cpuCacheSize :: Bytes
4099− , cpuCoresPerSocket :: Int
4100− , cpuTotalSockets :: Int
4101− , cpuTotalCores :: Int
4102− , cpuMHZ :: Int
4103− , cpuModel :: Text
4104− , cpuVendor :: Text
4105− } deriving (Eq, Show, Generic, Typeable)
4106−
4107−data NodeProcessInfo = NodeProcessInfo {
4108− nodeProcessMLockAll :: Bool
4109− -- ^ See <https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html>
4110− , nodeProcessMaxFileDescriptors :: Int
4111− , nodeProcessId :: PID
4112− , nodeProcessRefreshInterval :: NominalDiffTime
4113− } deriving (Eq, Show, Generic, Typeable)
4114−
4115−data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
4116− repoUpdateVerify :: Bool
4117− -- ^ After creation/update, synchronously check that nodes can
4118− -- write to this repo. Defaults to True. You may use False if you
4119− -- need a faster response and plan on verifying manually later
4120− -- with 'verifySnapshotRepo'.
4121− } deriving (Eq, Show, Generic, Typeable)
4122−
4123−
4124−-- | Reasonable defaults for repo creation/update
4125−--
4126−-- * repoUpdateVerify True
4127−defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
4128−defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
4129−
4130−
4131−-- | A filesystem-based snapshot repo that ships with
4132−-- ElasticSearch. This is an instance of 'SnapshotRepo' so it can be
4133−-- used with 'updateSnapshotRepo'
4134−data FsSnapshotRepo = FsSnapshotRepo {
4135− fsrName :: SnapshotRepoName
4136− , fsrLocation :: FilePath
4137− , fsrCompressMetadata :: Bool
4138− , fsrChunkSize :: Maybe Bytes
4139− -- ^ Size by which to split large files during snapshotting.
4140− , fsrMaxRestoreBytesPerSec :: Maybe Bytes
4141− -- ^ Throttle node restore rate. If not supplied, defaults to 40mb/sec
4142− , fsrMaxSnapshotBytesPerSec :: Maybe Bytes
4143− -- ^ Throttle node snapshot rate. If not supplied, defaults to 40mb/sec
4144− } deriving (Eq, Generic, Show, Typeable)
4145−
4146−
4147−instance SnapshotRepo FsSnapshotRepo where
4148− toGSnapshotRepo FsSnapshotRepo {..} =
4149− GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
4150− where
4151− Object settings = object $ [ "location" .= fsrLocation
4152− , "compress" .= fsrCompressMetadata
4153− ] ++ optionalPairs
4154− optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
4155− , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
4156− , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
4157− ]
4158− fromGSnapshotRepo GenericSnapshotRepo {..}
4159− | gSnapshotRepoType == fsRepoType = do
4160− let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
4161− parseRepo $ do
4162− FsSnapshotRepo gSnapshotRepoName <$> o .: "location"
4163− <*> o .:? "compress" .!= False
4164− <*> o .:? "chunk_size"
4165− <*> o .:? "max_restore_bytes_per_sec"
4166− <*> o .:? "max_snapshot_bytes_per_sec"
4167− | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
4168−
4169−
4170−parseRepo :: Parser a -> Either SnapshotRepoConversionError a
4171−parseRepo parser = case parseEither (const parser) () of
4172− Left e -> Left (OtherRepoConversionError (T.pack e))
4173− Right a -> Right a
4174−
4175−
4176−fsRepoType :: SnapshotRepoType
4177−fsRepoType = SnapshotRepoType "fs"
4178−
4179−-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
4180−class SnapshotRepo r where
4181− toGSnapshotRepo :: r -> GenericSnapshotRepo
4182− fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
4183−
4184−
4185−data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType SnapshotRepoType
4186− -- ^ Expected type and actual type
4187− | OtherRepoConversionError Text
4188− deriving (Show, Eq, Generic, Typeable)
4189−
4190−
4191−instance Exception SnapshotRepoConversionError
4192−
4193−
4194−data SnapshotCreateSettings = SnapshotCreateSettings {
4195− snapWaitForCompletion :: Bool
4196− -- ^ Should the API call return immediately after initializing
4197− -- the snapshot or wait until completed? Note that if this is
4198− -- enabled it could wait a long time, so you should adjust your
4199− -- 'ManagerSettings' accordingly to set long timeouts or
4200− -- explicitly handle timeouts.
4201− , snapIndices :: Maybe IndexSelection
4202− -- ^ Nothing will snapshot all indices. Just [] is permissable and
4203− -- will essentially be a no-op snapshot.
4204− , snapIgnoreUnavailable :: Bool
4205− -- ^ If set to True, any matched indices that don't exist will be
4206− -- ignored. Otherwise it will be an error and fail.
4207− , snapIncludeGlobalState :: Bool
4208− , snapPartial :: Bool
4209− -- ^ If some indices failed to snapshot (e.g. if not all primary
4210− -- shards are available), should the process proceed?
4211− } deriving (Eq, Generic, Show, Typeable)
4212−
4213−
4214−-- | Reasonable defaults for snapshot creation
4215−--
4216−-- * snapWaitForCompletion False
4217−-- * snapIndices Nothing
4218−-- * snapIgnoreUnavailable False
4219−-- * snapIncludeGlobalState True
4220−-- * snapPartial False
4221−defaultSnapshotCreateSettings :: SnapshotCreateSettings
4222−defaultSnapshotCreateSettings = SnapshotCreateSettings {
4223− snapWaitForCompletion = False
4224− , snapIndices = Nothing
4225− , snapIgnoreUnavailable = False
4226− , snapIncludeGlobalState = True
4227− , snapPartial = False
4228− }
4229−
4230−
4231−data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
4232− | AllSnapshots deriving (Eq, Generic, Show, Typeable)
4233−
4234−
4235−-- | Either specifies an exact snapshot name or one with globs in it,
4236−-- e.g. @SnapPattern "foo*"@ __NOTE__: Patterns are not supported on
4237−-- ES < 1.7
4238−data SnapshotPattern = ExactSnap SnapshotName
4239− | SnapPattern Text
4240− deriving (Eq, Generic, Show, Typeable)
4241−
4242−
4243−-- | General information about the state of a snapshot. Has some
4244−-- redundancies with 'SnapshotStatus'
4245−data SnapshotInfo = SnapshotInfo {
4246− snapInfoShards :: ShardResult
4247− , snapInfoFailures :: [SnapshotShardFailure]
4248− , snapInfoDuration :: NominalDiffTime
4249− , snapInfoEndTime :: UTCTime
4250− , snapInfoStartTime :: UTCTime
4251− , snapInfoState :: SnapshotState
4252− , snapInfoIndices :: [IndexName]
4253− , snapInfoName :: SnapshotName
4254− } deriving (Eq, Generic, Show, Typeable)
4255−
4256−
4257−instance FromJSON SnapshotInfo where
4258− parseJSON = withObject "SnapshotInfo" parse
4259− where
4260− parse o = SnapshotInfo <$> o .: "shards"
4261− <*> o .: "failures"
4262− <*> (unMS <$> o .: "duration_in_millis")
4263− <*> (posixMS <$> o .: "end_time_in_millis")
4264− <*> (posixMS <$> o .: "start_time_in_millis")
4265− <*> o .: "state"
4266− <*> o .: "indices"
4267− <*> o .: "snapshot"
4268−
4269−data SnapshotShardFailure = SnapshotShardFailure {
4270− snapShardFailureIndex :: IndexName
4271− , snapShardFailureNodeId :: Maybe NodeName -- I'm not 100% sure this isn't actually 'FullNodeId'
4272− , snapShardFailureReason :: Text
4273− , snapShardFailureShardId :: ShardId
4274− } deriving (Eq, Show, Generic, Typeable)
4275−
4276−
4277−instance FromJSON SnapshotShardFailure where
4278− parseJSON = withObject "SnapshotShardFailure" parse
4279− where
4280− parse o = SnapshotShardFailure <$> o .: "index"
4281− <*> o .:? "node_id"
4282− <*> o .: "reason"
4283− <*> o .: "shard_id"
4284−
4285−
4286−newtype ShardId = ShardId { shardId :: Int }
4287− deriving (Eq, Show, Generic, Typeable, FromJSON)
4288−
4289−-- | Milliseconds
4290−newtype MS = MS NominalDiffTime
4291−
4292−
4293−-- keeps the unexported constructor warnings at bay
4294−unMS :: MS -> NominalDiffTime
4295−unMS (MS t) = t
4296−
4297−
4298−instance FromJSON MS where
4299− parseJSON = withScientific "MS" (return . MS . parse)
4300− where
4301− parse n = fromInteger ((truncate n) * 1000)
4302−
4303−
4304−data SnapshotState = SnapshotInit
4305− | SnapshotStarted
4306− | SnapshotSuccess
4307− | SnapshotFailed
4308− | SnapshotAborted
4309− | SnapshotMissing
4310− | SnapshotWaiting
4311− deriving (Show, Eq, Generic, Typeable)
4312−
4313−instance FromJSON SnapshotState where
4314− parseJSON = withText "SnapshotState" parse
4315− where
4316− parse "INIT" = return SnapshotInit
4317− parse "STARTED" = return SnapshotStarted
4318− parse "SUCCESS" = return SnapshotSuccess
4319− parse "FAILED" = return SnapshotFailed
4320− parse "ABORTED" = return SnapshotAborted
4321− parse "MISSING" = return SnapshotMissing
4322− parse "WAITING" = return SnapshotWaiting
4323− parse t = fail ("Invalid snapshot state " <> T.unpack t)
4324−
4325−
4326−newtype SnapshotName = SnapshotName { snapshotName :: Text }
4327− deriving (Show, Eq, Ord, Generic, Typeable, ToJSON, FromJSON)
4328−
4329−
4330−data SnapshotRestoreSettings = SnapshotRestoreSettings {
4331− snapRestoreWaitForCompletion :: Bool
4332− -- ^ Should the API call return immediately after initializing
4333− -- the restore or wait until completed? Note that if this is
4334− -- enabled, it could wait a long time, so you should adjust your
4335− -- 'ManagerSettings' accordingly to set long timeouts or
4336− -- explicitly handle timeouts.
4337− , snapRestoreIndices :: Maybe IndexSelection
4338− -- ^ Nothing will restore all indices in the snapshot. Just [] is
4339− -- permissable and will essentially be a no-op restore.
4340− , snapRestoreIgnoreUnavailable :: Bool
4341− -- ^ If set to True, any indices that do not exist will be ignored
4342− -- during snapshot rather than failing the restore.
4343− , snapRestoreIncludeGlobalState :: Bool
4344− -- ^ If set to false, will ignore any global state in the snapshot
4345− -- and will not restore it.
4346− , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
4347− -- ^ A regex pattern for matching indices. Used with
4348− -- 'snapRestoreRenameReplacement', the restore can reference the
4349− -- matched index and create a new index name upon restore.
4350− , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
4351− -- ^ Expression of how index renames should be constructed.
4352− , snapRestorePartial :: Bool
4353− -- ^ If some indices fail to restore, should the process proceed?
4354− , snapRestoreIncludeAliases :: Bool
4355− -- ^ Should the restore also restore the aliases captured in the
4356− -- snapshot.
4357− , snapRestoreIndexSettingsOverrides :: Maybe RestoreIndexSettings
4358− -- ^ Settings to apply during the restore process. __NOTE:__ This
4359− -- option is not supported in ES < 1.5 and should be set to
4360− -- Nothing in that case.
4361− , snapRestoreIgnoreIndexSettings :: Maybe (NonEmpty Text)
4362− -- ^ This type could be more rich but it isn't clear which
4363− -- settings are allowed to be ignored during restore, so we're
4364− -- going with including this feature in a basic form rather than
4365− -- omitting it. One example here would be
4366− -- "index.refresh_interval". Any setting specified here will
4367− -- revert back to the server default during the restore process.
4368− } deriving (Eq, Generic, Show, Typeable)
4369−
4370−-- | Regex-stype pattern, e.g. "index_(.+)" to match index names
4371−newtype RestoreRenamePattern = RestoreRenamePattern { rrPattern :: Text }
4372− deriving (Show, Eq, Generic, Typeable, Ord, ToJSON)
4373−
4374−
4375−-- | A single token in a index renaming scheme for a restore. These
4376−-- are concatenated into a string before being sent to
4377−-- ElasticSearch. Check out these Java
4378−-- <https://docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html docs> to find out more if you're into that sort of thing.
4379−data RestoreRenameToken = RRTLit Text
4380− -- ^ Just a literal string of characters
4381− | RRSubWholeMatch
4382− -- ^ Equivalent to $0. The entire matched pattern, not any subgroup
4383− | RRSubGroup RRGroupRefNum
4384− -- ^ A specific reference to a group number
4385− deriving (Show, Eq, Generic, Typeable)
4386−
4387−
4388−-- | A group number for regex matching. Only values from 1-9 are
4389−-- supported. Construct with 'mkRRGroupRefNum'
4390−newtype RRGroupRefNum = RRGroupRefNum { rrGroupRefNum :: Int }
4391− deriving (Show, Eq, Generic, Typeable, Ord)
4392−
4393−instance Bounded RRGroupRefNum where
4394− minBound = RRGroupRefNum 1
4395− maxBound = RRGroupRefNum 9
4396−
4397−
4398−-- | Only allows valid group number references (1-9).
4399−mkRRGroupRefNum :: Int -> Maybe RRGroupRefNum
4400−mkRRGroupRefNum i
4401− | i >= (rrGroupRefNum minBound) && i <= (rrGroupRefNum maxBound) =
4402− Just $ RRGroupRefNum i
4403− | otherwise = Nothing
4404−
4405−
4406−-- | Reasonable defaults for snapshot restores
4407−--
4408−-- * snapRestoreWaitForCompletion False
4409−-- * snapRestoreIndices Nothing
4410−-- * snapRestoreIgnoreUnavailable False
4411−-- * snapRestoreIncludeGlobalState True
4412−-- * snapRestoreRenamePattern Nothing
4413−-- * snapRestoreRenameReplacement Nothing
4414−-- * snapRestorePartial False
4415−-- * snapRestoreIncludeAliases True
4416−-- * snapRestoreIndexSettingsOverrides Nothing
4417−-- * snapRestoreIgnoreIndexSettings Nothing
4418−defaultSnapshotRestoreSettings :: SnapshotRestoreSettings
4419−defaultSnapshotRestoreSettings = SnapshotRestoreSettings {
4420− snapRestoreWaitForCompletion = False
4421− , snapRestoreIndices = Nothing
4422− , snapRestoreIgnoreUnavailable = False
4423− , snapRestoreIncludeGlobalState = True
4424− , snapRestoreRenamePattern = Nothing
4425− , snapRestoreRenameReplacement = Nothing
4426− , snapRestorePartial = False
4427− , snapRestoreIncludeAliases = True
4428− , snapRestoreIndexSettingsOverrides = Nothing
4429− , snapRestoreIgnoreIndexSettings = Nothing
4430− }
4431−
4432−
4433−-- | Index settings that can be overridden. The docs only mention you
4434−-- can update number of replicas, but there may be more. You
4435−-- definitely cannot override shard count.
4436−data RestoreIndexSettings = RestoreIndexSettings {
4437− restoreOverrideReplicas :: Maybe ReplicaCount
4438− } deriving (Show, Eq, Generic, Typeable)
4439−
4440−
4441−instance ToJSON RestoreIndexSettings where
4442− toJSON RestoreIndexSettings {..} = object prs
4443− where
4444− prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]
4445−
4446−
4447−instance FromJSON NodesInfo where
4448− parseJSON = withObject "NodesInfo" parse
4449− where
4450− parse o = do
4451− nodes <- o .: "nodes"
4452− infos <- forM (HM.toList nodes) $ \(fullNID, v) -> do
4453− node <- parseJSON v
4454− parseNodeInfo (FullNodeId fullNID) node
4455− cn <- o .: "cluster_name"
4456− return (NodesInfo infos cn)
4457−
4458−instance FromJSON NodesStats where
4459− parseJSON = withObject "NodesStats" parse
4460− where
4461− parse o = do
4462− nodes <- o .: "nodes"
4463− stats <- forM (HM.toList nodes) $ \(fullNID, v) -> do
4464− node <- parseJSON v
4465− parseNodeStats (FullNodeId fullNID) node
4466− cn <- o .: "cluster_name"
4467− return (NodesStats stats cn)
4468−
4469−instance FromJSON NodeBreakerStats where
4470− parseJSON = withObject "NodeBreakerStats" parse
4471− where
4472− parse o = NodeBreakerStats <$> o .: "tripped"
4473− <*> o .: "overhead"
4474− <*> o .: "estimated_size_in_bytes"
4475− <*> o .: "limit_size_in_bytes"
4476−
4477−instance FromJSON NodeHTTPStats where
4478− parseJSON = withObject "NodeHTTPStats" parse
4479− where
4480− parse o = NodeHTTPStats <$> o .: "total_opened"
4481− <*> o .: "current_open"
4482−
4483−instance FromJSON NodeTransportStats where
4484− parseJSON = withObject "NodeTransportStats" parse
4485− where
4486− parse o = NodeTransportStats <$> o .: "tx_size_in_bytes"
4487− <*> o .: "tx_count"
4488− <*> o .: "rx_size_in_bytes"
4489− <*> o .: "rx_count"
4490− <*> o .: "server_open"
4491−
4492−instance FromJSON NodeFSStats where
4493− parseJSON = withObject "NodeFSStats" parse
4494− where
4495− parse o = NodeFSStats <$> o .: "data"
4496− <*> o .: "total"
4497− <*> (posixMS <$> o .: "timestamp")
4498−
4499−instance FromJSON NodeDataPathStats where
4500− parseJSON = withObject "NodeDataPathStats" parse
4501− where
4502− parse o =
4503− NodeDataPathStats <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
4504− <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
4505− <*> o .:? "disk_io_size_in_bytes"
4506− <*> o .:? "disk_write_size_in_bytes"
4507− <*> o .:? "disk_read_size_in_bytes"
4508− <*> o .:? "disk_io_op"
4509− <*> o .:? "disk_writes"
4510− <*> o .:? "disk_reads"
4511− <*> o .: "available_in_bytes"
4512− <*> o .: "free_in_bytes"
4513− <*> o .: "total_in_bytes"
4514− <*> o .:? "type"
4515− <*> o .: "dev"
4516− <*> o .: "mount"
4517− <*> o .: "path"
4518−
4519−newtype StringlyTypedDouble = StringlyTypedDouble { unStringlyTypedDouble :: Double }
4520−
4521−
4522−instance FromJSON StringlyTypedDouble where
4523− parseJSON = fmap StringlyTypedDouble . parseJSON . unStringlyTypeJSON
4524−
4525−
4526−instance FromJSON NodeFSTotalStats where
4527− parseJSON = withObject "NodeFSTotalStats" parse
4528− where
4529− parse o = NodeFSTotalStats <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
4530− <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
4531− <*> o .:? "disk_io_size_in_bytes"
4532− <*> o .:? "disk_write_size_in_bytes"
4533− <*> o .:? "disk_read_size_in_bytes"
4534− <*> o .:? "disk_io_op"
4535− <*> o .:? "disk_writes"
4536− <*> o .:? "disk_reads"
4537− <*> o .: "available_in_bytes"
4538− <*> o .: "free_in_bytes"
4539− <*> o .: "total_in_bytes"
4540−
4541−instance FromJSON NodeNetworkStats where
4542− parseJSON = withObject "NodeNetworkStats" parse
4543− where
4544− parse o = do
4545− tcp <- o .: "tcp"
4546− NodeNetworkStats <$> tcp .: "out_rsts"
4547− <*> tcp .: "in_errs"
4548− <*> tcp .: "attempt_fails"
4549− <*> tcp .: "estab_resets"
4550− <*> tcp .: "retrans_segs"
4551− <*> tcp .: "out_segs"
4552− <*> tcp .: "in_segs"
4553− <*> tcp .: "curr_estab"
4554− <*> tcp .: "passive_opens"
4555− <*> tcp .: "active_opens"
4556−
4557−instance FromJSON NodeThreadPoolsStats where
4558− parseJSON = withObject "NodeThreadPoolsStats" parse
4559− where
4560− parse o = NodeThreadPoolsStats <$> o .: "snapshot"
4561− <*> o .: "bulk"
4562− <*> o .: "merge"
4563− <*> o .: "get"
4564− <*> o .: "management"
4565− <*> o .:? "fetch_shard_store"
4566− <*> o .: "optimize"
4567− <*> o .: "flush"
4568− <*> o .: "search"
4569− <*> o .: "warmer"
4570− <*> o .: "generic"
4571− <*> o .: "suggest"
4572− <*> o .: "refresh"
4573− <*> o .: "index"
4574− <*> o .:? "listener"
4575− <*> o .:? "fetch_shard_started"
4576− <*> o .: "percolate"
4577−instance FromJSON NodeThreadPoolStats where
4578− parseJSON = withObject "NodeThreadPoolStats" parse
4579− where
4580− parse o = NodeThreadPoolStats <$> o .: "completed"
4581− <*> o .: "largest"
4582− <*> o .: "rejected"
4583− <*> o .: "active"
4584− <*> o .: "queue"
4585− <*> o .: "threads"
4586−
4587−instance FromJSON NodeJVMStats where
4588− parseJSON = withObject "NodeJVMStats" parse
4589− where
4590− parse o = do
4591− bufferPools <- o .: "buffer_pools"
4592− mapped <- bufferPools .: "mapped"
4593− direct <- bufferPools .: "direct"
4594− gc <- o .: "gc"
4595− collectors <- gc .: "collectors"
4596− oldC <- collectors .: "old"
4597− youngC <- collectors .: "young"
4598− threads <- o .: "threads"
4599− mem <- o .: "mem"
4600− pools <- mem .: "pools"
4601− oldM <- pools .: "old"
4602− survivorM <- pools .: "survivor"
4603− youngM <- pools .: "young"
4604− NodeJVMStats <$> pure mapped
4605− <*> pure direct
4606− <*> pure oldC
4607− <*> pure youngC
4608− <*> threads .: "peak_count"
4609− <*> threads .: "count"
4610− <*> pure oldM
4611− <*> pure survivorM
4612− <*> pure youngM
4613− <*> mem .: "non_heap_committed_in_bytes"
4614− <*> mem .: "non_heap_used_in_bytes"
4615− <*> mem .: "heap_max_in_bytes"
4616− <*> mem .: "heap_committed_in_bytes"
4617− <*> mem .: "heap_used_percent"
4618− <*> mem .: "heap_used_in_bytes"
4619− <*> (unMS <$> o .: "uptime_in_millis")
4620− <*> (posixMS <$> o .: "timestamp")
4621−
4622−instance FromJSON JVMBufferPoolStats where
4623− parseJSON = withObject "JVMBufferPoolStats" parse
4624− where
4625− parse o = JVMBufferPoolStats <$> o .: "total_capacity_in_bytes"
4626− <*> o .: "used_in_bytes"
4627− <*> o .: "count"
4628−
4629−instance FromJSON JVMGCStats where
4630− parseJSON = withObject "JVMGCStats" parse
4631− where
4632− parse o = JVMGCStats <$> (unMS <$> o .: "collection_time_in_millis")
4633− <*> o .: "collection_count"
4634−
4635−instance FromJSON JVMPoolStats where
4636− parseJSON = withObject "JVMPoolStats" parse
4637− where
4638− parse o = JVMPoolStats <$> o .: "peak_max_in_bytes"
4639− <*> o .: "peak_used_in_bytes"
4640− <*> o .: "max_in_bytes"
4641− <*> o .: "used_in_bytes"
4642−
4643−instance FromJSON NodeProcessStats where
4644− parseJSON = withObject "NodeProcessStats" parse
4645− where
4646− parse o = do
4647− mem <- o .: "mem"
4648− cpu <- o .: "cpu"
4649− NodeProcessStats <$> mem .: "total_virtual_in_bytes"
4650− <*> mem .: "share_in_bytes"
4651− <*> mem .: "resident_in_bytes"
4652− <*> (unMS <$> cpu .: "total_in_millis")
4653− <*> (unMS <$> cpu .: "user_in_millis")
4654− <*> (unMS <$> cpu .: "sys_in_millis")
4655− <*> cpu .: "percent"
4656− <*> o .: "open_file_descriptors"
4657− <*> (posixMS <$> o .: "timestamp")
4658−
4659−instance FromJSON NodeOSStats where
4660− parseJSON = withObject "NodeOSStats" parse
4661− where
4662− parse o = do
4663− swap <- o .: "swap"
4664− mem <- o .: "mem"
4665− cpu <- o .: "cpu"
4666− load <- o .:? "load_average"
4667− NodeOSStats <$> swap .: "free_in_bytes"
4668− <*> swap .: "used_in_bytes"
4669− <*> mem .: "actual_used_in_bytes"
4670− <*> mem .: "actual_free_in_bytes"
4671− <*> mem .: "used_percent"
4672− <*> mem .: "free_percent"
4673− <*> mem .: "used_in_bytes"
4674− <*> mem .: "free_in_bytes"
4675− <*> cpu .: "stolen"
4676− <*> cpu .: "usage"
4677− <*> cpu .: "idle"
4678− <*> cpu .: "user"
4679− <*> cpu .: "sys"
4680− <*> pure load
4681− <*> (unMS <$> o .: "uptime_in_millis")
4682− <*> (posixMS <$> o .: "timestamp")
4683−
4684−instance FromJSON LoadAvgs where
4685− parseJSON = withArray "LoadAvgs" parse
4686− where
4687− parse v = case V.toList v of
4688− [one, five, fifteen] -> LoadAvgs <$> parseJSON one
4689− <*> parseJSON five
4690− <*> parseJSON fifteen
4691− _ -> fail "Expecting a triple of Doubles"
4692−
4693−instance FromJSON NodeIndicesStats where
4694− parseJSON = withObject "NodeIndicesStats" parse
4695− where
4696− parse o = do
4697− let (.::) mv k = case mv of
4698− Just v -> Just <$> v .: k
4699− Nothing -> pure Nothing
4700− mRecovery <- o .:? "recovery"
4701− mQueryCache <- o .:? "query_cache"
4702− suggest <- o .: "suggest"
4703− translog <- o .: "translog"
4704− segments <- o .: "segments"
4705− completion <- o .: "completion"
4706− percolate <- o .: "percolate"
4707− fielddata <- o .: "fielddata"
4708− idCache <- o .: "id_cache"
4709− filterCache <- o .: "filter_cache"
4710− warmer <- o .: "warmer"
4711− flush <- o .: "flush"
4712− refresh <- o .: "refresh"
4713− merges <- o .: "merges"
4714− search <- o .: "search"
4715− getStats <- o .: "get"
4716− indexing <- o .: "indexing"
4717− store <- o .: "store"
4718− docs <- o .: "docs"
4719− NodeIndicesStats <$> (fmap unMS <$> mRecovery .:: "throttle_time_in_millis")
4720− <*> mRecovery .:: "current_as_target"
4721− <*> mRecovery .:: "current_as_source"
4722− <*> mQueryCache .:: "miss_count"
4723− <*> mQueryCache .:: "hit_count"
4724− <*> mQueryCache .:: "evictions"
4725− <*> mQueryCache .:: "memory_size_in_bytes"
4726− <*> suggest .: "current"
4727− <*> (unMS <$> suggest .: "time_in_millis")
4728− <*> suggest .: "total"
4729− <*> translog .: "size_in_bytes"
4730− <*> translog .: "operations"
4731− <*> segments .:? "fixed_bit_set_memory_in_bytes"
4732− <*> segments .: "version_map_memory_in_bytes"
4733− <*> segments .:? "index_writer_max_memory_in_bytes"
4734− <*> segments .: "index_writer_memory_in_bytes"
4735− <*> segments .: "memory_in_bytes"
4736− <*> segments .: "count"
4737− <*> completion .: "size_in_bytes"
4738− <*> percolate .: "queries"
4739− <*> percolate .: "memory_size_in_bytes"
4740− <*> percolate .: "current"
4741− <*> (unMS <$> percolate .: "time_in_millis")
4742− <*> percolate .: "total"
4743− <*> fielddata .: "evictions"
4744− <*> fielddata .: "memory_size_in_bytes"
4745− <*> idCache .: "memory_size_in_bytes"
4746− <*> filterCache .: "evictions"
4747− <*> filterCache .: "memory_size_in_bytes"
4748− <*> (unMS <$> warmer .: "total_time_in_millis")
4749− <*> warmer .: "total"
4750− <*> warmer .: "current"
4751− <*> (unMS <$> flush .: "total_time_in_millis")
4752− <*> flush .: "total"
4753− <*> (unMS <$> refresh .: "total_time_in_millis")
4754− <*> refresh .: "total"
4755− <*> merges .: "total_size_in_bytes"
4756− <*> merges .: "total_docs"
4757− <*> (unMS <$> merges .: "total_time_in_millis")
4758− <*> merges .: "total"
4759− <*> merges .: "current_size_in_bytes"
4760− <*> merges .: "current_docs"
4761− <*> merges .: "current"
4762− <*> search .: "fetch_current"
4763− <*> (unMS <$> search .: "fetch_time_in_millis")
4764− <*> search .: "fetch_total"
4765− <*> search .: "query_current"
4766− <*> (unMS <$> search .: "query_time_in_millis")
4767− <*> search .: "query_total"
4768− <*> search .: "open_contexts"
4769− <*> getStats .: "current"
4770− <*> (unMS <$> getStats .: "missing_time_in_millis")
4771− <*> getStats .: "missing_total"
4772− <*> (unMS <$> getStats .: "exists_time_in_millis")
4773− <*> getStats .: "exists_total"
4774− <*> (unMS <$> getStats .: "time_in_millis")
4775− <*> getStats .: "total"
4776− <*> (fmap unMS <$> indexing .:? "throttle_time_in_millis")
4777− <*> indexing .:? "is_throttled"
4778− <*> indexing .:? "noop_update_total"
4779− <*> indexing .: "delete_current"
4780− <*> (unMS <$> indexing .: "delete_time_in_millis")
4781− <*> indexing .: "delete_total"
4782− <*> indexing .: "index_current"
4783− <*> (unMS <$> indexing .: "index_time_in_millis")
4784− <*> indexing .: "index_total"
4785− <*> (unMS <$> store .: "throttle_time_in_millis")
4786− <*> store .: "size_in_bytes"
4787− <*> docs .: "deleted"
4788− <*> docs .: "count"
4789−
4790−instance FromJSON NodeBreakersStats where
4791− parseJSON = withObject "NodeBreakersStats" parse
4792− where
4793− parse o = NodeBreakersStats <$> o .: "parent"
4794− <*> o .: "request"
4795− <*> o .: "fielddata"
4796−
4797−parseNodeStats :: FullNodeId -> Object -> Parser NodeStats
4798−parseNodeStats fnid o = do
4799− NodeStats <$> o .: "name"
4800− <*> pure fnid
4801− <*> o .:? "breakers"
4802− <*> o .: "http"
4803− <*> o .: "transport"
4804− <*> o .: "fs"
4805− <*> o .: "network"
4806− <*> o .: "thread_pool"
4807− <*> o .: "jvm"
4808− <*> o .: "process"
4809− <*> o .: "os"
4810− <*> o .: "indices"
4811−
4812−parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
4813−parseNodeInfo nid o =
4814− NodeInfo <$> o .: "http_address"
4815− <*> o .: "build"
4816− <*> o .: "version"
4817− <*> o .: "ip"
4818− <*> o .: "host"
4819− <*> o .: "transport_address"
4820− <*> o .: "name"
4821− <*> pure nid
4822− <*> o .: "plugins"
4823− <*> o .: "http"
4824− <*> o .: "transport"
4825− <*> o .: "network"
4826− <*> o .: "thread_pool"
4827− <*> o .: "jvm"
4828− <*> o .: "process"
4829− <*> o .: "os"
4830− <*> o .: "settings"
4831−
4832−instance FromJSON NodePluginInfo where
4833− parseJSON = withObject "NodePluginInfo" parse
4834− where
4835− parse o = NodePluginInfo <$> o .: "site"
4836− <*> o .: "jvm"
4837− <*> o .: "description"
4838− <*> o .: "version"
4839− <*> o .: "name"
4840−
4841−instance FromJSON NodeHTTPInfo where
4842− parseJSON = withObject "NodeHTTPInfo" parse
4843− where
4844− parse o = NodeHTTPInfo <$> o .: "max_content_length_in_bytes"
4845− <*> parseJSON (Object o)
4846−
4847−instance FromJSON BoundTransportAddress where
4848− parseJSON = withObject "BoundTransportAddress" parse
4849− where
4850− parse o = BoundTransportAddress <$> o .: "publish_address"
4851− <*> o .: "bound_address"
4852−
4853−instance FromJSON NodeOSInfo where
4854− parseJSON = withObject "NodeOSInfo" parse
4855− where
4856− parse o = do
4857− swap <- o .: "swap"
4858− mem <- o .: "mem"
4859− NodeOSInfo <$> swap .: "total_in_bytes"
4860− <*> mem .: "total_in_bytes"
4861− <*> o .: "cpu"
4862− <*> o .: "available_processors"
4863− <*> (unMS <$> o .: "refresh_interval_in_millis")
4864−
4865−
4866−instance FromJSON CPUInfo where
4867− parseJSON = withObject "CPUInfo" parse
4868− where
4869− parse o = CPUInfo <$> o .: "cache_size_in_bytes"
4870− <*> o .: "cores_per_socket"
4871− <*> o .: "total_sockets"
4872− <*> o .: "total_cores"
4873− <*> o .: "mhz"
4874− <*> o .: "model"
4875− <*> o .: "vendor"
4876−
4877−instance FromJSON NodeProcessInfo where
4878− parseJSON = withObject "NodeProcessInfo" parse
4879− where
4880− parse o = NodeProcessInfo <$> o .: "mlockall"
4881− <*> o .: "max_file_descriptors"
4882− <*> o .: "id"
4883− <*> (unMS <$> o .: "refresh_interval_in_millis")
4884−
4885−instance FromJSON NodeJVMInfo where
4886− parseJSON = withObject "NodeJVMInfo" parse
4887− where
4888− parse o = NodeJVMInfo <$> o .: "memory_pools"
4889− <*> o .: "gc_collectors"
4890− <*> o .: "mem"
4891− <*> (posixMS <$> o .: "start_time_in_millis")
4892− <*> o .: "vm_vendor"
4893− <*> o .: "vm_version"
4894− <*> o .: "vm_name"
4895− <*> (unJVMVersion <$> o .: "version")
4896− <*> o .: "pid"
4897−
4898−instance FromJSON JVMVersion where
4899− parseJSON (String t) =
4900− JVMVersion <$> parseJSON (String (T.replace "_" "." t))
4901− parseJSON v = JVMVersion <$> parseJSON v
4902−
4903−instance FromJSON JVMMemoryInfo where
4904− parseJSON = withObject "JVMMemoryInfo" parse
4905− where
4906− parse o = JVMMemoryInfo <$> o .: "direct_max_in_bytes"
4907− <*> o .: "non_heap_max_in_bytes"
4908− <*> o .: "non_heap_init_in_bytes"
4909− <*> o .: "heap_max_in_bytes"
4910− <*> o .: "heap_init_in_bytes"
4911−
4912−instance FromJSON NodeThreadPoolsInfo where
4913− parseJSON = withObject "NodeThreadPoolsInfo" parse
4914− where
4915− parse o = NodeThreadPoolsInfo <$> o .: "refresh"
4916− <*> o .: "management"
4917− <*> o .: "percolate"
4918− <*> o .:? "listener"
4919− <*> o .:? "fetch_shard_started"
4920− <*> o .: "search"
4921− <*> o .: "flush"
4922− <*> o .: "warmer"
4923− <*> o .: "optimize"
4924− <*> o .: "bulk"
4925− <*> o .: "suggest"
4926− <*> o .: "merge"
4927− <*> o .: "snapshot"
4928− <*> o .: "get"
4929− <*> o .:? "fetch_shard_store"
4930− <*> o .: "index"
4931− <*> o .: "generic"
4932−
4933−instance FromJSON NodeThreadPoolInfo where
4934− parseJSON = withObject "NodeThreadPoolInfo" parse
4935− where
4936− parse o = do
4937− ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
4938− NodeThreadPoolInfo <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
4939− <*> pure ka
4940− <*> o .:? "min"
4941− <*> o .:? "max"
4942− <*> o .: "type"
4943−
4944−parseStringInterval :: (Monad m) => String -> m NominalDiffTime
4945−parseStringInterval s = case span isNumber s of
4946− ("", _) -> fail "Invalid interval"
4947− (nS, unitS) -> case (readMay nS, readMay unitS) of
4948− (Just n, Just unit) -> return (fromInteger (n * unitNDT unit))
4949− (Nothing, _) -> fail "Invalid interval number"
4950− (_, Nothing) -> fail "Invalid interval unit"
4951− where
4952− unitNDT Seconds = 1
4953− unitNDT Minutes = 60
4954− unitNDT Hours = 60 * 60
4955− unitNDT Days = 24 * 60 * 60
4956− unitNDT Weeks = 7 * 24 * 60 * 60
4957−
4958−instance FromJSON ThreadPoolSize where
4959− parseJSON v = parseAsNumber v <|> parseAsString v
4960− where
4961− parseAsNumber = parseAsInt <=< parseJSON
4962− parseAsInt (-1) = return ThreadPoolUnbounded
4963− parseAsInt n
4964− | n >= 0 = return (ThreadPoolBounded n)
4965− | otherwise = fail "Thread pool size must be >= -1."
4966− parseAsString = withText "ThreadPoolSize" $ \t ->
4967− case first (readMay . T.unpack) (T.span isNumber t) of
4968− (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
4969− (Just n, "") -> return (ThreadPoolBounded n)
4970− _ -> fail ("Invalid thread pool size " <> T.unpack t)
4971−
4972−instance FromJSON ThreadPoolType where
4973− parseJSON = withText "ThreadPoolType" parse
4974− where
4975− parse "scaling" = return ThreadPoolScaling
4976− parse "fixed" = return ThreadPoolFixed
4977− parse "cached" = return ThreadPoolCached
4978− parse e = fail ("Unexpected thread pool type" <> T.unpack e)
4979−
4980−instance FromJSON NodeTransportInfo where
4981− parseJSON = withObject "NodeTransportInfo" parse
4982− where
4983− parse o = NodeTransportInfo <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
4984− <*> parseJSON (Object o)
4985− parseProfiles (Object o) | HM.null o = return []
4986− parseProfiles v@(Array _) = parseJSON v
4987− parseProfiles Null = return []
4988− parseProfiles _ = fail "Could not parse profiles"
4989−
4990−instance FromJSON NodeNetworkInfo where
4991− parseJSON = withObject "NodeNetworkInfo" parse
4992− where
4993− parse o = NodeNetworkInfo <$> o .: "primary_interface"
4994− <*> (unMS <$> o .: "refresh_interval_in_millis")
4995−
4996−
4997−instance FromJSON NodeNetworkInterface where
4998− parseJSON = withObject "NodeNetworkInterface" parse
4999− where
5000− parse o = NodeNetworkInterface <$> o .: "mac_address"
5001− <*> o .: "name"
5002− <*> o .: "address"
5003−
5004−newtype MaybeNA a = MaybeNA { unMaybeNA :: Maybe a }
5005− deriving (Show, Eq)
5006−
5007−instance FromJSON a => FromJSON (MaybeNA a) where
5008− parseJSON (String "NA") = pure $ MaybeNA Nothing
5009− parseJSON o = MaybeNA . Just <$> parseJSON o
5010−
5011−
5012−data Suggest = Suggest { suggestText :: Text
5013− , suggestName :: Text
5014− , suggestType :: SuggestType
5015− }
5016− deriving (Show, Generic, Eq, Read, Typeable)
5017−
5018−instance ToJSON Suggest where
5019− toJSON Suggest{..} = object [ "text" .= suggestText
5020− , suggestName .= suggestType
5021− ]
5022−
5023−instance FromJSON Suggest where
5024− parseJSON (Object o) = do
5025− suggestText' <- o .: "text"
5026− let dropTextList = HM.toList $ HM.filterWithKey (\x _ -> x /= "text") o
5027− suggestName' <- case dropTextList of
5028− [(x, _)] -> return x
5029− _ -> fail "error parsing Suggest field name"
5030− suggestType' <- o .: suggestName'
5031− return $ Suggest suggestText' suggestName' suggestType'
5032− parseJSON x = typeMismatch "Suggest" x
5033−
5034−data SuggestType = SuggestTypePhraseSuggester PhraseSuggester
5035− deriving (Show, Generic, Eq, Read, Typeable)
5036−
5037−instance ToJSON SuggestType where
5038− toJSON (SuggestTypePhraseSuggester x) = object ["phrase" .= x]
5039−
5040−instance FromJSON SuggestType where
5041− parseJSON = withObject "SuggestType" parse
5042− where parse o = phraseSuggester `taggedWith` "phrase"
5043− where taggedWith parser k = parser =<< o .: k
5044− phraseSuggester = pure . SuggestTypePhraseSuggester
5045−
5046−data PhraseSuggester =
5047− PhraseSuggester { phraseSuggesterField :: FieldName
5048− , phraseSuggesterGramSize :: Maybe Int
5049− , phraseSuggesterRealWordErrorLikelihood :: Maybe Int
5050− , phraseSuggesterConfidence :: Maybe Int
5051− , phraseSuggesterMaxErrors :: Maybe Int
5052− , phraseSuggesterSeparator :: Maybe Text
5053− , phraseSuggesterSize :: Maybe Size
5054− , phraseSuggesterAnalyzer :: Maybe Analyzer
5055− , phraseSuggesterShardSize :: Maybe Int
5056− , phraseSuggesterHighlight :: Maybe PhraseSuggesterHighlighter
5057− , phraseSuggesterCollate :: Maybe PhraseSuggesterCollate
5058− , phraseSuggesterCandidateGenerators :: [DirectGenerators]
5059− }
5060− deriving (Show, Generic, Eq, Read, Typeable)
5061−
5062−instance ToJSON PhraseSuggester where
5063− toJSON PhraseSuggester{..} = omitNulls [ "field" .= phraseSuggesterField
5064− , "gram_size" .= phraseSuggesterGramSize
5065− , "real_word_error_likelihood" .= phraseSuggesterRealWordErrorLikelihood
5066− , "confidence" .= phraseSuggesterConfidence
5067− , "max_errors" .= phraseSuggesterMaxErrors
5068− , "separator" .= phraseSuggesterSeparator
5069− , "size" .= phraseSuggesterSize
5070− , "analyzer" .= phraseSuggesterAnalyzer
5071− , "shard_size" .= phraseSuggesterShardSize
5072− , "highlight" .= phraseSuggesterHighlight
5073− , "collate" .= phraseSuggesterCollate
5074− , "direct_generator" .= phraseSuggesterCandidateGenerators
5075− ]
5076−
5077−instance FromJSON PhraseSuggester where
5078− parseJSON = withObject "PhraseSuggester" parse
5079− where parse o = PhraseSuggester
5080− <$> o .: "field"
5081− <*> o .:? "gram_size"
5082− <*> o .:? "real_word_error_likelihood"
5083− <*> o .:? "confidence"
5084− <*> o .:? "max_errors"
5085− <*> o .:? "separator"
5086− <*> o .:? "size"
5087− <*> o .:? "analyzer"
5088− <*> o .:? "shard_size"
5089− <*> o .:? "highlight"
5090− <*> o .:? "collate"
5091− <*> o .:? "direct_generator" .!= []
5092−
5093−mkPhraseSuggester :: FieldName -> PhraseSuggester
5094−mkPhraseSuggester fName =
5095− PhraseSuggester fName Nothing Nothing Nothing Nothing Nothing Nothing
5096− Nothing Nothing Nothing Nothing []
5097−
5098−data PhraseSuggesterHighlighter =
5099− PhraseSuggesterHighlighter { phraseSuggesterHighlighterPreTag :: Text
5100− , phraseSuggesterHighlighterPostTag :: Text
5101− }
5102− deriving (Show, Generic, Eq, Read, Typeable)
5103−
5104−instance ToJSON PhraseSuggesterHighlighter where
5105− toJSON PhraseSuggesterHighlighter{..} =
5106− object [ "pre_tag" .= phraseSuggesterHighlighterPreTag
5107− , "post_tag" .= phraseSuggesterHighlighterPostTag
5108− ]
5109−
5110−instance FromJSON PhraseSuggesterHighlighter where
5111− parseJSON = withObject "PhraseSuggesterHighlighter" parse
5112− where parse o = PhraseSuggesterHighlighter
5113− <$> o .: "pre_tag"
5114− <*> o .: "post_tag"
5115−
5116−data PhraseSuggesterCollate =
5117− PhraseSuggesterCollate { phraseSuggesterCollateTemplateQuery :: TemplateQueryInline
5118− , phraseSuggesterCollatePrune :: Bool
5119− }
5120− deriving (Show, Generic, Eq, Read, Typeable)
5121−
5122−instance ToJSON PhraseSuggesterCollate where
5123− toJSON PhraseSuggesterCollate{..} = object [ "query" .= object
5124− [ "inline" .= (inline phraseSuggesterCollateTemplateQuery)
5125− ]
5126− , "params" .= (params phraseSuggesterCollateTemplateQuery)
5127− , "prune" .= phraseSuggesterCollatePrune
5128− ]
5129−
5130−instance FromJSON PhraseSuggesterCollate where
5131− parseJSON (Object o) = do
5132− query' <- o .: "query"
5133− inline' <- query' .: "inline"
5134− params' <- o .: "params"
5135− prune' <- o .:? "prune" .!= False
5136− return $ PhraseSuggesterCollate (TemplateQueryInline inline' params') prune'
5137− parseJSON x = typeMismatch "PhraseSuggesterCollate" x
5138−
5139−data SuggestOptions =
5140− SuggestOptions { suggestOptionsText :: Text
5141− , suggestOptionsScore :: Double
5142− , suggestOptionsFreq :: Maybe Int
5143− , suggestOptionsHighlighted :: Maybe Text
5144− }
5145− deriving (Eq, Read, Show)
5146−
5147−instance FromJSON SuggestOptions where
5148− parseJSON = withObject "SuggestOptions" parse
5149− where parse o = SuggestOptions
5150− <$> o .: "text"
5151− <*> o .: "score"
5152− <*> o .:? "freq"
5153− <*> o .:? "highlighted"
5154−
5155−data SuggestResponse =
5156− SuggestResponse { suggestResponseText :: Text
5157− , suggestResponseOffset :: Int
5158− , suggestResponseLength :: Int
5159− , suggestResponseOptions :: [SuggestOptions]
5160− }
5161− deriving (Eq, Read, Show)
5162−
5163−instance FromJSON SuggestResponse where
5164− parseJSON = withObject "SuggestResponse" parse
5165− where parse o = SuggestResponse
5166− <$> o .: "text"
5167− <*> o .: "offset"
5168− <*> o .: "length"
5169− <*> o .: "options"
5170−
5171−data NamedSuggestionResponse =
5172− NamedSuggestionResponse { nsrName :: Text
5173− , nsrResponses :: [SuggestResponse]
5174− }
5175− deriving (Eq, Read, Show)
5176−
5177−instance FromJSON NamedSuggestionResponse where
5178− parseJSON (Object o) = do
5179− suggestionName' <- case HM.toList o of
5180− [(x, _)] -> return x
5181− _ -> fail "error parsing NamedSuggestionResponse name"
5182− suggestionResponses' <- o .: suggestionName'
5183− return $ NamedSuggestionResponse suggestionName' suggestionResponses'
5184−
5185− parseJSON x = typeMismatch "NamedSuggestionResponse" x
5186−
5187−data DirectGeneratorSuggestModeTypes = DirectGeneratorSuggestModeMissing
5188− | DirectGeneratorSuggestModePopular
5189− | DirectGeneratorSuggestModeAlways
5190− deriving (Show, Eq, Read, Generic, Typeable)
5191−
5192−instance ToJSON DirectGeneratorSuggestModeTypes where
5193− toJSON DirectGeneratorSuggestModeMissing = "missing"
5194− toJSON DirectGeneratorSuggestModePopular = "popular"
5195− toJSON DirectGeneratorSuggestModeAlways = "always"
5196−
5197−instance FromJSON DirectGeneratorSuggestModeTypes where
5198− parseJSON = withText "DirectGeneratorSuggestModeTypes" parse
5199− where parse "missing" = pure DirectGeneratorSuggestModeMissing
5200− parse "popular" = pure DirectGeneratorSuggestModePopular
5201− parse "always" = pure DirectGeneratorSuggestModeAlways
5202− parse f = fail ("Unexpected DirectGeneratorSuggestModeTypes: " <> show f)
5203−
5204−data DirectGenerators = DirectGenerators
5205− { directGeneratorsField :: FieldName
5206− , directGeneratorsSize :: Maybe Int
5207− , directGeneratorSuggestMode :: DirectGeneratorSuggestModeTypes
5208− , directGeneratorMaxEdits :: Maybe Double
5209− , directGeneratorPrefixLength :: Maybe Int
5210− , directGeneratorMinWordLength :: Maybe Int
5211− , directGeneratorMaxInspections :: Maybe Int
5212− , directGeneratorMinDocFreq :: Maybe Double
5213− , directGeneratorMaxTermFreq :: Maybe Double
5214− , directGeneratorPreFilter :: Maybe Text
5215− , directGeneratorPostFilter :: Maybe Text
5216− }
5217− deriving (Show, Eq, Read, Generic, Typeable)
5218−
5219−
5220−instance ToJSON DirectGenerators where
5221− toJSON DirectGenerators{..} = omitNulls [ "field" .= directGeneratorsField
5222− , "size" .= directGeneratorsSize
5223− , "suggest_mode" .= directGeneratorSuggestMode
5224− , "max_edits" .= directGeneratorMaxEdits
5225− , "prefix_length" .= directGeneratorPrefixLength
5226− , "min_word_length" .= directGeneratorMinWordLength
5227− , "max_inspections" .= directGeneratorMaxInspections
5228− , "min_doc_freq" .= directGeneratorMinDocFreq
5229− , "max_term_freq" .= directGeneratorMaxTermFreq
5230− , "pre_filter" .= directGeneratorPreFilter
5231− , "post_filter" .= directGeneratorPostFilter
5232− ]
5233−
5234−instance FromJSON DirectGenerators where
5235− parseJSON = withObject "DirectGenerators" parse
5236− where parse o = DirectGenerators
5237− <$> o .: "field"
5238− <*> o .:? "size"
5239− <*> o .: "suggest_mode"
5240− <*> o .:? "max_edits"
5241− <*> o .:? "prefix_length"
5242− <*> o .:? "min_word_length"
5243− <*> o .:? "max_inspections"
5244− <*> o .:? "min_doc_freq"
5245− <*> o .:? "max_term_freq"
5246− <*> o .:? "pre_filter"
5247− <*> o .:? "post_filter"
5248−
5249−mkDirectGenerators :: FieldName -> DirectGenerators
5250−mkDirectGenerators fn = DirectGenerators fn Nothing DirectGeneratorSuggestModeMissing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
src/Database/V5/Bloodhound/Internal/Client.hs−4
@@ -236,10 +236,6 @@ data UpdatableIndexSetting = NumberOfReplicas ReplicaCount
236 -- ^ Analysis is not a dynamic setting and can only be performed on a closed index.
236 -- ^ Analysis is not a dynamic setting and can only be performed on a closed index.
237 deriving (Eq, Show)
237 deriving (Eq, Show)
238
238
239−oPath :: ToJSON a => NonEmpty Text -> a -> Value
240−oPath (k :| []) v = object [k .= v]
241−oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
242−
243attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
239attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
244attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
240attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
245 | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
241 | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
tests/V1/Test/Aggregation.hsnew file+132
@@ -0,0 +1,132 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Aggregation (spec) where
4+
5+import Test.Common
6+import Test.Import
7+
8+import Control.Error (fmapL, note)
9+import qualified Data.Map as M
10+import qualified Database.V1.Bloodhound
11+
12+spec :: Spec
13+spec =
14+ describe "Aggregation API" $ do
15+ it "returns term aggregation results" $ withTestEnv $ do
16+ _ <- insertData
17+ let terms = TermsAgg $ mkTermsAggregation "user"
18+ let search = mkAggregateSearch Nothing $ mkAggregations "users" terms
19+ searchExpectAggs search
20+ searchValidBucketAgg search "users" toTerms
21+
22+ it "return sub-aggregation results" $ withTestEnv $ do
23+ _ <- insertData
24+ let subaggs = mkAggregations "age_agg" . TermsAgg $ mkTermsAggregation "age"
25+ agg = TermsAgg $ (mkTermsAggregation "user") { termAggs = Just subaggs}
26+ search = mkAggregateSearch Nothing $ mkAggregations "users" agg
27+ reply <- searchByIndex testIndex search
28+ let result = decode (responseBody reply) :: Maybe (SearchResult Tweet)
29+ usersAggResults = result >>= aggregations >>= toTerms "users"
30+ subAggResults = usersAggResults >>= (listToMaybe . buckets) >>= termsAggs >>= toTerms "age_agg"
31+ subAddResultsExists = isJust subAggResults
32+ liftIO $ subAddResultsExists `shouldBe` True
33+
34+ it "returns cardinality aggregation results" $ withTestEnv $ do
35+ _ <- insertData
36+ let cardinality = CardinalityAgg $ mkCardinalityAggregation $ FieldName "user"
37+ let search = mkAggregateSearch Nothing $ mkAggregations "users" cardinality
38+ let search' = search { Database.V1.Bloodhound.from = From 0, size = Size 0 }
39+ searchExpectAggs search'
40+ let docCountPair k n = (k, object ["value" .= Number n])
41+ res <- searchTweets search'
42+ liftIO $
43+ fmap aggregations res `shouldBe` Right (Just (M.fromList [ docCountPair "users" 1]))
44+
45+ it "can give collection hint parameters to term aggregations" $ when' (atleast es13) $ withTestEnv $ do
46+ _ <- insertData
47+ let terms = TermsAgg $ (mkTermsAggregation "user") { termCollectMode = Just BreadthFirst }
48+ let search = mkAggregateSearch Nothing $ mkAggregations "users" terms
49+ searchExpectAggs search
50+ searchValidBucketAgg search "users" toTerms
51+
52+ -- One of these fails with 1.7.3
53+ it "can give execution hint parameters to term aggregations" $ when' (atmost es11) $ withTestEnv $ do
54+ _ <- insertData
55+ searchTermsAggHint [Map, Ordinals]
56+
57+ it "can give execution hint parameters to term aggregations" $ when' (is es12) $ withTestEnv $ do
58+ _ <- insertData
59+ searchTermsAggHint [GlobalOrdinals, GlobalOrdinalsHash, GlobalOrdinalsLowCardinality, Map, Ordinals]
60+
61+ it "can give execution hint parameters to term aggregations" $ when' (atleast es12) $ withTestEnv $ do
62+ _ <- insertData
63+ searchTermsAggHint [GlobalOrdinals, GlobalOrdinalsHash, GlobalOrdinalsLowCardinality, Map]
64+ -- One of the above.
65+
66+ it "can execute value_count aggregations" $ withTestEnv $ do
67+ _ <- insertData
68+ _ <- insertOther
69+ let ags = mkAggregations "user_count" (ValueCountAgg (FieldValueCount (FieldName "user"))) <>
70+ mkAggregations "bogus_count" (ValueCountAgg (FieldValueCount (FieldName "bogus")))
71+ let search = mkAggregateSearch Nothing ags
72+ let docCountPair k n = (k, object ["value" .= Number n])
73+ res <- searchTweets search
74+ liftIO $
75+ fmap aggregations res `shouldBe` Right (Just (M.fromList [ docCountPair "user_count" 2
76+ , docCountPair "bogus_count" 0
77+ ]))
78+
79+ it "can execute date_range aggregations" $ withTestEnv $ do
80+ let now = fromGregorian 2015 3 14
81+ let ltAMonthAgo = UTCTime (fromGregorian 2015 3 1) 0
82+ let ltAWeekAgo = UTCTime (fromGregorian 2015 3 10) 0
83+ let oldDoc = exampleTweet { postDate = ltAMonthAgo }
84+ let newDoc = exampleTweet { postDate = ltAWeekAgo }
85+ _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings oldDoc (DocId "1")
86+ _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings newDoc (DocId "2")
87+ _ <- refreshIndex testIndex
88+ let thisMonth = DateRangeFrom (DateMathExpr (DMDate now) [SubtractTime 1 DMMonth])
89+ let thisWeek = DateRangeFrom (DateMathExpr (DMDate now) [SubtractTime 1 DMWeek])
90+ let agg = DateRangeAggregation (FieldName "postDate") Nothing (thisMonth :| [thisWeek])
91+ let ags = mkAggregations "date_ranges" (DateRangeAgg agg)
92+ let search = mkAggregateSearch Nothing ags
93+ res <- searchTweets search
94+ liftIO $ hitsTotal . searchHits <$> res `shouldBe` Right 2
95+ let bucks = do magrs <- fmapL show (aggregations <$> res)
96+ agrs <- note "no aggregations returned" magrs
97+ rawBucks <- note "no date_ranges aggregation" $ M.lookup "date_ranges" agrs
98+ parseEither parseJSON rawBucks
99+ let fromMonthT = UTCTime (fromGregorian 2015 2 14) 0
100+ let fromWeekT = UTCTime (fromGregorian 2015 3 7) 0
101+ liftIO $ buckets <$> bucks `shouldBe` Right [ DateRangeResult "2015-02-14T00:00:00.000Z-*"
102+ (Just fromMonthT)
103+ (Just "2015-02-14T00:00:00.000Z")
104+ Nothing
105+ Nothing
106+ 2
107+ Nothing
108+ , DateRangeResult "2015-03-07T00:00:00.000Z-*"
109+ (Just fromWeekT)
110+ (Just "2015-03-07T00:00:00.000Z")
111+ Nothing
112+ Nothing
113+ 1
114+ Nothing
115+ ]
116+
117+ it "returns date histogram aggregation results" $ withTestEnv $ do
118+ _ <- insertData
119+ let histogram = DateHistogramAgg $ mkDateHistogram (FieldName "postDate") Minute
120+ let search = mkAggregateSearch Nothing (mkAggregations "byDate" histogram)
121+ searchExpectAggs search
122+ searchValidBucketAgg search "byDate" toDateHistogram
123+
124+ it "can execute missing aggregations" $ withTestEnv $ do
125+ _ <- insertData
126+ _ <- insertExtra
127+ let ags = mkAggregations "missing_agg" (MissingAgg (MissingAggregation "extra"))
128+ let search = mkAggregateSearch Nothing ags
129+ let docCountPair k n = (k, object ["doc_count" .= Number n])
130+ res <- searchTweets search
131+ liftIO $
132+ fmap aggregations res `shouldBe` Right (Just (M.fromList [docCountPair "missing_agg" 1]))
tests/V1/Test/ApproxEq.hsnew file+63
@@ -0,0 +1,63 @@
1+{-# LANGUAGE DefaultSignatures #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Test.ApproxEq where
5+
6+import Database.V1.Bloodhound
7+
8+import Test.Import
9+
10+import qualified Data.List.NonEmpty as NE
11+
12+-- | Typeclass for "equal where it matters". Use this to specify
13+-- less-strict equivalence for things such as lists that can wind up
14+-- in an unpredictable order
15+class ApproxEq a where
16+ (=~) :: a -> a -> Bool
17+
18+ showApproxEq :: a -> String
19+ default showApproxEq :: (Show a) => a -> String
20+ showApproxEq = show
21+
22+(==~) :: (ApproxEq a) => a -> a -> Property
23+a ==~ b = counterexample (showApproxEq a ++ " !=~ " ++ showApproxEq b) (a =~ b)
24+
25+instance ApproxEq NominalDiffTime where (=~) = (==)
26+instance ApproxEq Bool where (=~) = (==)
27+instance ApproxEq Int where (=~) = (==)
28+instance (Eq a, Show a) => ApproxEq (Maybe a) where (=~) = (==)
29+instance ApproxEq Char where
30+ (=~) = (==)
31+
32+instance ApproxEq NodeAttrFilter where (=~) = (==)
33+instance ApproxEq NodeAttrName where (=~) = (==)
34+instance (Eq a, Show a) => ApproxEq (NonEmpty a) where (=~) = (==)
35+instance (ApproxEq l, Show l, ApproxEq r, Show r) => ApproxEq (Either l r) where
36+ Left a =~ Left b = a =~ b
37+ Right a =~ Right b = a =~ b
38+ _ =~ _ = False
39+ showApproxEq (Left x) = "Left " <> showApproxEq x
40+ showApproxEq (Right x) = "Right " <> showApproxEq x
41+instance (ApproxEq a, Show a) => ApproxEq [a] where
42+ as =~ bs = and (zipWith (=~) as bs)
43+instance ApproxEq ReplicaCount where (=~) = (==)
44+instance ApproxEq ReplicaBounds where (=~) = (==)
45+instance ApproxEq Bytes where (=~) = (==)
46+instance ApproxEq AllocationPolicy where (=~) = (==)
47+instance ApproxEq InitialShardCount where (=~) = (==)
48+instance ApproxEq FSType where (=~) = (==)
49+
50+-- | Due to the way nodeattrfilters get serialized here, they may come
51+-- out in a different order, but they are morally equivalent
52+instance ApproxEq UpdatableIndexSetting where
53+ RoutingAllocationInclude a =~ RoutingAllocationInclude b =
54+ NE.sort a =~ NE.sort b
55+ RoutingAllocationExclude a =~ RoutingAllocationExclude b =
56+ NE.sort a =~ NE.sort b
57+ RoutingAllocationRequire a =~ RoutingAllocationRequire b =
58+ NE.sort a =~ NE.sort b
59+ a =~ b = a == b
60+ showApproxEq (RoutingAllocationInclude xs) = show (RoutingAllocationInclude (NE.sort xs))
61+ showApproxEq (RoutingAllocationExclude xs) = show (RoutingAllocationExclude (NE.sort xs))
62+ showApproxEq (RoutingAllocationRequire xs) = show (RoutingAllocationRequire (NE.sort xs))
63+ showApproxEq x = show x
tests/V1/Test/BulkAPI.hsnew file+77
@@ -0,0 +1,77 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.BulkAPI (spec) where
4+
5+import Test.Common
6+import Test.Import
7+
8+import qualified Data.Vector as V
9+import qualified Lens.Micro.Aeson as LMA
10+
11+newtype BulkTest =
12+ BulkTest Text
13+ deriving (Eq, Show)
14+
15+instance ToJSON BulkTest where
16+ toJSON (BulkTest name') =
17+ object ["name" .= name']
18+
19+instance FromJSON BulkTest where
20+ parseJSON = withObject "BulkTest" parse
21+ where
22+ parse o = do
23+ t <- o .: "name"
24+ BulkTest <$> parseJSON t
25+
26+spec :: Spec
27+spec =
28+ describe "Bulk API" $
29+ it "inserts all documents we request" $ withTestEnv $ do
30+ _ <- insertData
31+ let firstTest = BulkTest "blah"
32+ let secondTest = BulkTest "bloo"
33+ let firstDoc = BulkIndex testIndex
34+ testMapping (DocId "2") (toJSON firstTest)
35+ let secondDoc = BulkCreate testIndex
36+ testMapping (DocId "3") (toJSON secondTest)
37+ let stream = V.fromList [firstDoc, secondDoc]
38+ _ <- bulk stream
39+ _ <- refreshIndex testIndex
40+ fDoc <- getDocument testIndex testMapping (DocId "2")
41+ sDoc <- getDocument testIndex testMapping (DocId "3")
42+ -- note that we cannot query for fourthDoc and fifthDoc since we
43+ -- do not know their autogenerated ids.
44+ let maybeFirst =
45+ eitherDecode
46+ $ responseBody fDoc
47+ :: Either String (EsResult BulkTest)
48+ let maybeSecond =
49+ eitherDecode
50+ $ responseBody sDoc
51+ :: Either String (EsResult BulkTest)
52+ liftIO $ do
53+ fmap getSource maybeFirst `shouldBe` Right (Just firstTest)
54+ fmap getSource maybeSecond `shouldBe` Right (Just secondTest)
55+ -- Since we can't get the docs by doc id, we check for their existence in
56+ -- a match all query.
57+ let query = MatchAllQuery Nothing
58+ let search = mkSearch (Just query) Nothing
59+ resp <- searchByIndex testIndex search
60+ parsed <- parseEsResponse resp :: BH IO (Either EsError (SearchResult Value))
61+ case parsed of
62+ Left e ->
63+ liftIO $ expectationFailure ("Expected a script-transformed result but got: " <> show e)
64+ (Right sr) -> do
65+ liftIO $
66+ hitsTotal (searchHits sr) `shouldBe` 3
67+ let nameList :: [Text]
68+ nameList =
69+ hits (searchHits sr)
70+ ^.. traverse
71+ . to hitSource
72+ . _Just
73+ . LMA.key "name"
74+ . _String
75+ liftIO $
76+ nameList
77+ `shouldBe` ["blah","bloo"]
tests/V1/Test/Common.hsnew file+289
@@ -0,0 +1,289 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE TemplateHaskell #-}
3+
4+module Test.Common where
5+
6+import Test.Import
7+
8+import qualified Data.Map as M
9+import qualified Data.Version as Vers
10+import qualified Network.HTTP.Types.Status as NHTS
11+
12+testServer :: Server
13+testServer = Server "http://localhost:9200"
14+testIndex :: IndexName
15+testIndex = IndexName "bloodhound-tests-twitter-1"
16+testMapping :: MappingName
17+testMapping = MappingName "tweet"
18+
19+withTestEnv :: BH IO a -> IO a
20+withTestEnv = withBH defaultManagerSettings testServer
21+
22+data Location = Location { lat :: Double
23+ , lon :: Double } deriving (Eq, Show)
24+
25+data Tweet = Tweet { user :: Text
26+ , postDate :: UTCTime
27+ , message :: Text
28+ , age :: Int
29+ , location :: Location
30+ , extra :: Maybe Text }
31+ deriving (Eq, Show)
32+
33+$(deriveJSON defaultOptions ''Location)
34+$(deriveJSON defaultOptions ''Tweet)
35+
36+data ParentMapping = ParentMapping deriving (Eq, Show)
37+
38+instance ToJSON ParentMapping where
39+ toJSON ParentMapping =
40+ object ["properties" .=
41+ object [ "user" .= object ["type" .= ("string" :: Text)
42+ ]
43+ -- Serializing the date as a date is breaking other tests, mysteriously.
44+ -- , "postDate" .= object [ "type" .= ("date" :: Text)
45+ -- , "format" .= ("YYYY-MM-dd`T`HH:mm:ss.SSSZZ" :: Text)]
46+ , "message" .= object ["type" .= ("string" :: Text)]
47+ , "age" .= object ["type" .= ("integer" :: Text)]
48+ , "location" .= object ["type" .= ("geo_point" :: Text)]
49+ , "extra" .= object ["type" .= ("string" :: Text), "index" .= ("not_analyzed" :: Text)]
50+ ]]
51+
52+es13 :: Vers.Version
53+es13 = Vers.Version [1, 3, 0] []
54+
55+es12 :: Vers.Version
56+es12 = Vers.Version [1, 2, 0] []
57+
58+es11 :: Vers.Version
59+es11 = Vers.Version [1, 1, 0] []
60+
61+es14 :: Vers.Version
62+es14 = Vers.Version [1, 4, 0] []
63+
64+es15 :: Vers.Version
65+es15 = Vers.Version [1, 5, 0] []
66+
67+es16 :: Vers.Version
68+es16 = Vers.Version [1, 6, 0] []
69+
70+es20 :: Vers.Version
71+es20 = Vers.Version [2, 0, 0] []
72+
73+es50 :: Vers.Version
74+es50 = Vers.Version [5, 0, 0] []
75+
76+getServerVersion :: IO (Maybe Vers.Version)
77+getServerVersion = fmap extractVersion <$> withTestEnv getStatus
78+ where
79+ extractVersion = versionNumber . number . version
80+
81+createExampleIndex :: (MonadBH m) => m Reply
82+createExampleIndex =
83+ createIndex (IndexSettings (ShardCount 1) (ReplicaCount 0)) testIndex
84+
85+deleteExampleIndex :: (MonadBH m) => m Reply
86+deleteExampleIndex =
87+ deleteIndex testIndex
88+
89+validateStatus :: Show body => Response body -> Int -> Expectation
90+validateStatus resp expected =
91+ if actual == expected
92+ then return ()
93+ else expectationFailure ("Expected " <> show expected <> " but got " <> show actual <> ": " <> show body)
94+ where
95+ actual = NHTS.statusCode (responseStatus resp)
96+ body = responseBody resp
97+
98+data ChildMapping = ChildMapping deriving (Eq, Show)
99+
100+instance ToJSON ChildMapping where
101+ toJSON ChildMapping =
102+ object ["_parent" .= object ["type" .= ("parent" :: Text)]
103+ , "properties" .=
104+ object [ "user" .= object ["type" .= ("string" :: Text)
105+ ]
106+ -- Serializing the date as a date is breaking other tests, mysteriously.
107+ -- , "postDate" .= object [ "type" .= ("date" :: Text)
108+ -- , "format" .= ("YYYY-MM-dd`T`HH:mm:ss.SSSZZ" :: Text)]
109+ , "message" .= object ["type" .= ("string" :: Text)]
110+ , "age" .= object ["type" .= ("integer" :: Text)]
111+ , "location" .= object ["type" .= ("geo_point" :: Text)]
112+ , "extra" .= object ["type" .= ("string" :: Text), "index" .= ("not_analyzed" :: Text)]
113+ ]]
114+
115+data TweetMapping = TweetMapping deriving (Eq, Show)
116+
117+instance ToJSON TweetMapping where
118+ toJSON TweetMapping =
119+ object ["tweet" .=
120+ object ["properties" .=
121+ object [ "user" .= object [ "type" .= ("string" :: Text)
122+ ]
123+ -- Serializing the date as a date is breaking other tests, mysteriously.
124+ -- , "postDate" .= object [ "type" .= ("date" :: Text)
125+ -- , "format" .= ("YYYY-MM-dd`T`HH:mm:ss.SSSZZ" :: Text)]
126+ , "message" .= object ["type" .= ("string" :: Text)]
127+ , "age" .= object ["type" .= ("integer" :: Text)]
128+ , "location" .= object ["type" .= ("geo_point" :: Text)]
129+ , "extra" .= object ["type" .= ("string" :: Text), "index" .= ("not_analyzed" :: Text)]
130+ ]]]
131+
132+exampleTweet :: Tweet
133+exampleTweet = Tweet { user = "bitemyapp"
134+ , postDate = UTCTime
135+ (ModifiedJulianDay 55000)
136+ (secondsToDiffTime 10)
137+ , message = "Use haskell!"
138+ , age = 10000
139+ , location = Location 40.12 (-71.34)
140+ , extra = Nothing }
141+
142+tweetWithExtra :: Tweet
143+tweetWithExtra = Tweet { user = "bitemyapp"
144+ , postDate = UTCTime
145+ (ModifiedJulianDay 55000)
146+ (secondsToDiffTime 10)
147+ , message = "Use haskell!"
148+ , age = 10000
149+ , location = Location 40.12 (-71.34)
150+ , extra = Just "blah blah" }
151+
152+newAge :: Int
153+newAge = 31337
154+
155+newUser :: Text
156+newUser = "someotherapp"
157+
158+tweetPatch :: Value
159+tweetPatch =
160+ object [ "age" .= newAge
161+ , "user" .= newUser
162+ ]
163+
164+patchedTweet :: Tweet
165+patchedTweet = exampleTweet{age = newAge, user = newUser}
166+
167+otherTweet :: Tweet
168+otherTweet = Tweet { user = "notmyapp"
169+ , postDate = UTCTime
170+ (ModifiedJulianDay 55000)
171+ (secondsToDiffTime 11)
172+ , message = "Use haskell!"
173+ , age = 1000
174+ , location = Location 40.12 (-71.34)
175+ , extra = Nothing }
176+
177+resetIndex :: BH IO ()
178+resetIndex = do
179+ _ <- deleteExampleIndex
180+ _ <- createExampleIndex
181+ _ <- putMapping testIndex testMapping TweetMapping
182+ return ()
183+
184+insertData :: BH IO Reply
185+insertData = do
186+ resetIndex
187+ insertData' defaultIndexDocumentSettings
188+
189+insertData' :: IndexDocumentSettings -> BH IO Reply
190+insertData' ids = do
191+ r <- indexDocument testIndex testMapping ids exampleTweet (DocId "1")
192+ _ <- refreshIndex testIndex
193+ return r
194+
195+updateData :: BH IO Reply
196+updateData = do
197+ r <- updateDocument testIndex testMapping defaultIndexDocumentSettings tweetPatch (DocId "1")
198+ _ <- refreshIndex testIndex
199+ return r
200+
201+insertOther :: BH IO ()
202+insertOther = do
203+ _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings otherTweet (DocId "2")
204+ _ <- refreshIndex testIndex
205+ return ()
206+
207+insertExtra :: BH IO ()
208+insertExtra = do
209+ _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings tweetWithExtra (DocId "4")
210+ _ <- refreshIndex testIndex
211+ return ()
212+
213+insertWithSpaceInId :: BH IO ()
214+insertWithSpaceInId = do
215+ _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings exampleTweet (DocId "Hello World")
216+ _ <- refreshIndex testIndex
217+ return ()
218+
219+searchTweet :: Search -> BH IO (Either EsError Tweet)
220+searchTweet search = do
221+ result <- searchTweets search
222+ let myTweet :: Either EsError Tweet
223+ myTweet = grabFirst result
224+ return myTweet
225+
226+searchTweets :: Search -> BH IO (Either EsError (SearchResult Tweet))
227+searchTweets search = parseEsResponse =<< searchByIndex testIndex search
228+
229+searchExpectNoResults :: Search -> BH IO ()
230+searchExpectNoResults search = do
231+ result <- searchTweets search
232+ let emptyHits = fmap (hits . searchHits) result
233+ liftIO $
234+ emptyHits `shouldBe` Right []
235+
236+searchExpectAggs :: Search -> BH IO ()
237+searchExpectAggs search = do
238+ reply <- searchByIndex testIndex search
239+ let isEmpty x = return (M.null x)
240+ let result = decode (responseBody reply) :: Maybe (SearchResult Tweet)
241+ liftIO $
242+ (result >>= aggregations >>= isEmpty) `shouldBe` Just False
243+
244+searchValidBucketAgg :: (BucketAggregation a, FromJSON a, Show a) =>
245+ Search -> Text -> (Text -> AggregationResults -> Maybe (Bucket a)) -> BH IO ()
246+searchValidBucketAgg search aggKey extractor = do
247+ reply <- searchByIndex testIndex search
248+ let bucketDocs = docCount . head . buckets
249+ let result = decode (responseBody reply) :: Maybe (SearchResult Tweet)
250+ let count = result >>= aggregations >>= extractor aggKey >>= \x -> return (bucketDocs x)
251+ liftIO $
252+ count `shouldBe` Just 1
253+
254+searchTermsAggHint :: [ExecutionHint] -> BH IO ()
255+searchTermsAggHint hints = do
256+ let terms hint = TermsAgg $ (mkTermsAggregation "user") { termExecutionHint = Just hint }
257+ let search hint = mkAggregateSearch Nothing $ mkAggregations "users" $ terms hint
258+ forM_ hints $ searchExpectAggs . search
259+ forM_ hints (\x -> searchValidBucketAgg (search x) "users" toTerms)
260+
261+searchTweetHighlight :: Search
262+ -> BH IO (Either EsError (Maybe HitHighlight))
263+searchTweetHighlight search = do
264+ result <- searchTweets search
265+ let tweetHit :: Either EsError (Maybe (Hit Tweet))
266+ tweetHit = fmap (headMay . hits . searchHits) result
267+ myHighlight :: Either EsError (Maybe HitHighlight)
268+ myHighlight = (join . fmap hitHighlight) <$> tweetHit
269+ return myHighlight
270+
271+searchExpectSource :: Source -> Either EsError Value -> BH IO ()
272+searchExpectSource src expected = do
273+ _ <- insertData
274+ let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
275+ let search = (mkSearch (Just query) Nothing) { source = Just src }
276+ reply <- searchByIndex testIndex search
277+ result <- parseEsResponse reply
278+ let value = grabFirst result
279+ liftIO $
280+ value `shouldBe` expected
281+
282+atleast :: Vers.Version -> IO Bool
283+atleast v = getServerVersion >>= \x -> return $ x >= Just v
284+
285+atmost :: Vers.Version -> IO Bool
286+atmost v = getServerVersion >>= \x -> return $ x <= Just v
287+
288+is :: Vers.Version -> IO Bool
289+is v = getServerVersion >>= \x -> return $ x == Just v
tests/V1/Test/Documents.hsnew file+52
@@ -0,0 +1,52 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Documents where
4+
5+import Test.Common
6+import Test.Import
7+
8+spec :: Spec
9+spec =
10+ describe "document API" $ do
11+ it "indexes, updates, gets, and then deletes the generated document" $ withTestEnv $ do
12+ _ <- insertData
13+ _ <- updateData
14+ docInserted <- getDocument testIndex testMapping (DocId "1")
15+ let newTweet = eitherDecode
16+ (responseBody docInserted) :: Either String (EsResult Tweet)
17+ liftIO $ fmap getSource newTweet `shouldBe` Right (Just patchedTweet)
18+
19+ it "indexes, gets, and then deletes the generated document with a DocId containing a space" $ withTestEnv $ do
20+ _ <- insertWithSpaceInId
21+ docInserted <- getDocument testIndex testMapping (DocId "Hello World")
22+ let newTweet = eitherDecode
23+ (responseBody docInserted) :: Either String (EsResult Tweet)
24+ liftIO $ fmap getSource newTweet `shouldBe` Right (Just exampleTweet)
25+
26+ it "produces a parseable result when looking up a bogus document" $ withTestEnv $ do
27+ doc <- getDocument testIndex testMapping (DocId "bogus")
28+ let noTweet = eitherDecode
29+ (responseBody doc) :: Either String (EsResult Tweet)
30+ liftIO $ fmap foundResult noTweet `shouldBe` Right Nothing
31+
32+ it "can use optimistic concurrency control" $ withTestEnv $ do
33+ let ev = ExternalDocVersion minBound
34+ let cfg = defaultIndexDocumentSettings { idsVersionControl = ExternalGT ev }
35+ resetIndex
36+ res <- insertData' cfg
37+ liftIO $ isCreated res `shouldBe` True
38+ res' <- insertData' cfg
39+ liftIO $ isVersionConflict res' `shouldBe` True
40+
41+ it "indexes two documents in a parent/child relationship and checks that the child exists" $ withTestEnv $ do
42+ resetIndex
43+ let validateStatus' stat = liftIO . flip validateStatus stat
44+ _ <- validateStatus' 200 =<< putMapping testIndex (MappingName "child") ChildMapping
45+ _ <- validateStatus' 200 =<< putMapping testIndex (MappingName "parent") ParentMapping
46+ _ <- validateStatus' 201 =<< indexDocument testIndex (MappingName "parent") defaultIndexDocumentSettings exampleTweet (DocId "1")
47+ let parent = (Just . DocumentParent . DocId) "1"
48+ ids = IndexDocumentSettings NoVersionControl parent
49+ _ <- validateStatus' 201 =<< indexDocument testIndex (MappingName "child") ids otherTweet (DocId "2")
50+ _ <- refreshIndex testIndex
51+ exists <- documentExists testIndex (MappingName "child") parent (DocId "2")
52+ liftIO $ exists `shouldBe` True
tests/V1/Test/Generators.hsnew file+432
@@ -0,0 +1,432 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE TemplateHaskell #-}
6+
7+module Test.Generators where
8+
9+import Database.V1.Bloodhound
10+
11+import Test.Import
12+
13+import qualified Data.HashMap.Strict as HM
14+import qualified Data.List as L
15+import qualified Data.List.NonEmpty as NE
16+import qualified Data.Map as M
17+import qualified Data.Text as T
18+import qualified Data.Version as Vers
19+import Test.QuickCheck.TH.Generators
20+
21+import Test.ApproxEq
22+
23+instance Arbitrary NominalDiffTime where
24+ arbitrary = fromInteger <$> arbitrary
25+
26+#if !MIN_VERSION_QuickCheck(2,8,0)
27+instance (Arbitrary k, Ord k, Arbitrary v) => Arbitrary (M.Map k v) where
28+ arbitrary = M.fromList <$> arbitrary
29+#endif
30+
31+instance Arbitrary Text where
32+ arbitrary = T.pack <$> arbitrary
33+
34+instance Arbitrary UTCTime where
35+ arbitrary = UTCTime
36+ <$> arbitrary
37+ <*> (fromRational . toRational <$> choose (0::Double, 86400))
38+
39+instance Arbitrary Day where
40+ arbitrary =
41+ ModifiedJulianDay . (2000 +) <$> arbitrary
42+ shrink =
43+ (ModifiedJulianDay <$>) . shrink . toModifiedJulianDay
44+
45+#if !MIN_VERSION_QuickCheck(2,9,0)
46+instance Arbitrary a => Arbitrary (NonEmpty a) where
47+ arbitrary = liftA2 (:|) arbitrary arbitrary
48+#endif
49+
50+arbitraryScore :: Gen Score
51+arbitraryScore = fmap getPositive <$> arbitrary
52+
53+instance (Arbitrary a, Typeable a) => Arbitrary (Hit a) where
54+ arbitrary = Hit <$> arbitrary
55+ <*> arbitrary
56+ <*> arbitrary
57+ <*> arbitraryScore
58+ <*> arbitrary
59+ <*> arbitrary
60+
61+instance (Arbitrary a, Typeable a) => Arbitrary (SearchHits a) where
62+ arbitrary = reduceSize $ do
63+ tot <- getPositive <$> arbitrary
64+ score <- arbitraryScore
65+ hs <- arbitrary
66+ return $ SearchHits tot score hs
67+
68+
69+reduceSize :: Gen a -> Gen a
70+reduceSize f = sized $ \n -> resize (n `div` 2) f
71+
72+arbitraryAlphaNum :: Gen Char
73+arbitraryAlphaNum = oneof [choose ('a', 'z')
74+ ,choose ('A','Z')
75+ , choose ('0', '9')]
76+
77+instance Arbitrary RoutingValue where
78+ arbitrary = RoutingValue . T.pack <$> listOf1 arbitraryAlphaNum
79+
80+instance Arbitrary AliasRouting where
81+ arbitrary = oneof [allAlias
82+ ,one
83+ ,theOther
84+ ,both']
85+ where one = GranularAliasRouting
86+ <$> (Just <$> arbitrary)
87+ <*> pure Nothing
88+ theOther = GranularAliasRouting Nothing
89+ <$> (Just <$> arbitrary)
90+ both' = GranularAliasRouting
91+ <$> (Just <$> arbitrary)
92+ <*> (Just <$> arbitrary)
93+ allAlias = AllAliasRouting <$> arbitrary
94+
95+
96+
97+instance Arbitrary FieldName where
98+ arbitrary =
99+ FieldName
100+ . T.pack
101+ <$> listOf1 arbitraryAlphaNum
102+
103+
104+#if MIN_VERSION_base(4,10,0)
105+-- Test.QuickCheck.Modifiers
106+
107+qcNonEmptyToNonEmpty :: NonEmptyList a -> NonEmpty a
108+qcNonEmptyToNonEmpty (NonEmpty (a : xs)) = (a :| xs)
109+qcNonEmptyToNonEmpty (NonEmpty []) = error "NonEmpty was empty!"
110+
111+instance Arbitrary a => Arbitrary (NonEmpty a) where
112+ arbitrary =
113+ qcNonEmptyToNonEmpty
114+ <$> arbitrary
115+#endif
116+
117+instance Arbitrary RegexpFlags where
118+ arbitrary = oneof [ pure AllRegexpFlags
119+ , pure NoRegexpFlags
120+ , SomeRegexpFlags <$> genUniqueFlags
121+ ]
122+ where genUniqueFlags =
123+ NE.fromList . L.nub
124+ <$> listOf1 arbitrary
125+
126+instance Arbitrary IndexAliasCreate where
127+ arbitrary =
128+ IndexAliasCreate
129+ <$> arbitrary
130+ <*> reduceSize arbitrary
131+
132+instance Arbitrary ReplicaBounds where
133+ arbitrary = oneof [ replicasBounded
134+ , replicasLowerBounded
135+ , pure ReplicasUnbounded
136+ ]
137+ where replicasBounded = do
138+ Positive a <- arbitrary
139+ Positive b <- arbitrary
140+ return (ReplicasBounded a b)
141+ replicasLowerBounded = do
142+ Positive a <- arbitrary
143+ return (ReplicasLowerBounded a)
144+
145+instance Arbitrary NodeAttrName where
146+ arbitrary =
147+ NodeAttrName
148+ . T.pack
149+ <$> listOf1 arbitraryAlphaNum
150+
151+
152+instance Arbitrary NodeAttrFilter where
153+ arbitrary = do
154+ n <- arbitrary
155+ s:ss <- listOf1 (listOf1 arbitraryAlphaNum)
156+ let ts = T.pack <$> s :| ss
157+ return (NodeAttrFilter n ts)
158+
159+instance Arbitrary VersionNumber where
160+ arbitrary = mk . fmap getPositive . getNonEmpty <$> arbitrary
161+ where
162+ mk versions = VersionNumber (Vers.Version versions [])
163+
164+instance Arbitrary TemplateQueryKeyValuePairs where
165+ arbitrary = TemplateQueryKeyValuePairs . HM.fromList <$> arbitrary
166+ shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . HM.fromList) . shrink $ HM.toList x
167+
168+makeArbitrary ''FilteredQuery
169+instance Arbitrary FilteredQuery where arbitrary = reduceSize arbitraryFilteredQuery
170+makeArbitrary ''Query
171+instance Arbitrary Query where arbitrary = reduceSize arbitraryQuery
172+makeArbitrary ''Filter
173+instance Arbitrary Filter where arbitrary = reduceSize arbitraryFilter
174+makeArbitrary ''IndexName
175+instance Arbitrary IndexName where arbitrary = arbitraryIndexName
176+makeArbitrary ''MappingName
177+instance Arbitrary MappingName where arbitrary = arbitraryMappingName
178+makeArbitrary ''DocId
179+instance Arbitrary DocId where arbitrary = arbitraryDocId
180+makeArbitrary ''Version
181+instance Arbitrary Version where arbitrary = arbitraryVersion
182+makeArbitrary ''BuildHash
183+instance Arbitrary BuildHash where arbitrary = arbitraryBuildHash
184+makeArbitrary ''IndexAliasRouting
185+instance Arbitrary IndexAliasRouting where arbitrary = arbitraryIndexAliasRouting
186+makeArbitrary ''ShardCount
187+instance Arbitrary ShardCount where arbitrary = arbitraryShardCount
188+makeArbitrary ''ReplicaCount
189+instance Arbitrary ReplicaCount where arbitrary = arbitraryReplicaCount
190+makeArbitrary ''TemplateName
191+instance Arbitrary TemplateName where arbitrary = arbitraryTemplateName
192+makeArbitrary ''TemplatePattern
193+instance Arbitrary TemplatePattern where arbitrary = arbitraryTemplatePattern
194+makeArbitrary ''QueryString
195+instance Arbitrary QueryString where arbitrary = arbitraryQueryString
196+makeArbitrary ''CacheName
197+instance Arbitrary CacheName where arbitrary = arbitraryCacheName
198+makeArbitrary ''CacheKey
199+instance Arbitrary CacheKey where arbitrary = arbitraryCacheKey
200+makeArbitrary ''Existence
201+instance Arbitrary Existence where arbitrary = arbitraryExistence
202+makeArbitrary ''CutoffFrequency
203+instance Arbitrary CutoffFrequency where arbitrary = arbitraryCutoffFrequency
204+makeArbitrary ''Analyzer
205+instance Arbitrary Analyzer where arbitrary = arbitraryAnalyzer
206+makeArbitrary ''MaxExpansions
207+instance Arbitrary MaxExpansions where arbitrary = arbitraryMaxExpansions
208+makeArbitrary ''Lenient
209+instance Arbitrary Lenient where arbitrary = arbitraryLenient
210+makeArbitrary ''Tiebreaker
211+instance Arbitrary Tiebreaker where arbitrary = arbitraryTiebreaker
212+makeArbitrary ''Boost
213+instance Arbitrary Boost where arbitrary = arbitraryBoost
214+makeArbitrary ''BoostTerms
215+instance Arbitrary BoostTerms where arbitrary = arbitraryBoostTerms
216+makeArbitrary ''MinimumMatch
217+instance Arbitrary MinimumMatch where arbitrary = arbitraryMinimumMatch
218+makeArbitrary ''DisableCoord
219+instance Arbitrary DisableCoord where arbitrary = arbitraryDisableCoord
220+makeArbitrary ''IgnoreTermFrequency
221+instance Arbitrary IgnoreTermFrequency where arbitrary = arbitraryIgnoreTermFrequency
222+makeArbitrary ''MinimumTermFrequency
223+instance Arbitrary MinimumTermFrequency where arbitrary = arbitraryMinimumTermFrequency
224+makeArbitrary ''MaxQueryTerms
225+instance Arbitrary MaxQueryTerms where arbitrary = arbitraryMaxQueryTerms
226+makeArbitrary ''Fuzziness
227+instance Arbitrary Fuzziness where arbitrary = arbitraryFuzziness
228+makeArbitrary ''PrefixLength
229+instance Arbitrary PrefixLength where arbitrary = arbitraryPrefixLength
230+makeArbitrary ''TypeName
231+instance Arbitrary TypeName where arbitrary = arbitraryTypeName
232+makeArbitrary ''PercentMatch
233+instance Arbitrary PercentMatch where arbitrary = arbitraryPercentMatch
234+makeArbitrary ''StopWord
235+instance Arbitrary StopWord where arbitrary = arbitraryStopWord
236+makeArbitrary ''QueryPath
237+instance Arbitrary QueryPath where arbitrary = arbitraryQueryPath
238+makeArbitrary ''AllowLeadingWildcard
239+instance Arbitrary AllowLeadingWildcard where arbitrary = arbitraryAllowLeadingWildcard
240+makeArbitrary ''LowercaseExpanded
241+instance Arbitrary LowercaseExpanded where arbitrary = arbitraryLowercaseExpanded
242+makeArbitrary ''EnablePositionIncrements
243+instance Arbitrary EnablePositionIncrements where arbitrary = arbitraryEnablePositionIncrements
244+makeArbitrary ''AnalyzeWildcard
245+instance Arbitrary AnalyzeWildcard where arbitrary = arbitraryAnalyzeWildcard
246+makeArbitrary ''GeneratePhraseQueries
247+instance Arbitrary GeneratePhraseQueries where arbitrary = arbitraryGeneratePhraseQueries
248+makeArbitrary ''Locale
249+instance Arbitrary Locale where arbitrary = arbitraryLocale
250+makeArbitrary ''MaxWordLength
251+instance Arbitrary MaxWordLength where arbitrary = arbitraryMaxWordLength
252+makeArbitrary ''MinWordLength
253+instance Arbitrary MinWordLength where arbitrary = arbitraryMinWordLength
254+makeArbitrary ''PhraseSlop
255+instance Arbitrary PhraseSlop where arbitrary = arbitraryPhraseSlop
256+makeArbitrary ''MinDocFrequency
257+instance Arbitrary MinDocFrequency where arbitrary = arbitraryMinDocFrequency
258+makeArbitrary ''MaxDocFrequency
259+instance Arbitrary MaxDocFrequency where arbitrary = arbitraryMaxDocFrequency
260+makeArbitrary ''Regexp
261+instance Arbitrary Regexp where arbitrary = arbitraryRegexp
262+makeArbitrary ''SimpleQueryStringQuery
263+instance Arbitrary SimpleQueryStringQuery where arbitrary = arbitrarySimpleQueryStringQuery
264+makeArbitrary ''FieldOrFields
265+instance Arbitrary FieldOrFields where arbitrary = arbitraryFieldOrFields
266+makeArbitrary ''SimpleQueryFlag
267+instance Arbitrary SimpleQueryFlag where arbitrary = arbitrarySimpleQueryFlag
268+makeArbitrary ''RegexpQuery
269+instance Arbitrary RegexpQuery where arbitrary = arbitraryRegexpQuery
270+makeArbitrary ''QueryStringQuery
271+instance Arbitrary QueryStringQuery where arbitrary = arbitraryQueryStringQuery
272+makeArbitrary ''RangeQuery
273+instance Arbitrary RangeQuery where arbitrary = arbitraryRangeQuery
274+makeArbitrary ''RangeValue
275+instance Arbitrary RangeValue where arbitrary = arbitraryRangeValue
276+makeArbitrary ''PrefixQuery
277+instance Arbitrary PrefixQuery where arbitrary = arbitraryPrefixQuery
278+makeArbitrary ''NestedQuery
279+instance Arbitrary NestedQuery where arbitrary = arbitraryNestedQuery
280+makeArbitrary ''MoreLikeThisFieldQuery
281+instance Arbitrary MoreLikeThisFieldQuery where arbitrary = arbitraryMoreLikeThisFieldQuery
282+makeArbitrary ''MoreLikeThisQuery
283+instance Arbitrary MoreLikeThisQuery where arbitrary = arbitraryMoreLikeThisQuery
284+makeArbitrary ''IndicesQuery
285+instance Arbitrary IndicesQuery where arbitrary = arbitraryIndicesQuery
286+makeArbitrary ''HasParentQuery
287+instance Arbitrary HasParentQuery where arbitrary = arbitraryHasParentQuery
288+makeArbitrary ''HasChildQuery
289+instance Arbitrary HasChildQuery where arbitrary = arbitraryHasChildQuery
290+makeArbitrary ''FuzzyQuery
291+instance Arbitrary FuzzyQuery where arbitrary = arbitraryFuzzyQuery
292+makeArbitrary ''FuzzyLikeFieldQuery
293+instance Arbitrary FuzzyLikeFieldQuery where arbitrary = arbitraryFuzzyLikeFieldQuery
294+makeArbitrary ''FuzzyLikeThisQuery
295+instance Arbitrary FuzzyLikeThisQuery where arbitrary = arbitraryFuzzyLikeThisQuery
296+makeArbitrary ''DisMaxQuery
297+instance Arbitrary DisMaxQuery where arbitrary = arbitraryDisMaxQuery
298+makeArbitrary ''CommonTermsQuery
299+instance Arbitrary CommonTermsQuery where arbitrary = arbitraryCommonTermsQuery
300+makeArbitrary ''DistanceRange
301+instance Arbitrary DistanceRange where arbitrary = arbitraryDistanceRange
302+makeArbitrary ''MultiMatchQuery
303+instance Arbitrary MultiMatchQuery where arbitrary = arbitraryMultiMatchQuery
304+makeArbitrary ''LessThanD
305+instance Arbitrary LessThanD where arbitrary = arbitraryLessThanD
306+makeArbitrary ''LessThanEqD
307+instance Arbitrary LessThanEqD where arbitrary = arbitraryLessThanEqD
308+makeArbitrary ''GreaterThanD
309+instance Arbitrary GreaterThanD where arbitrary = arbitraryGreaterThanD
310+makeArbitrary ''GreaterThanEqD
311+instance Arbitrary GreaterThanEqD where arbitrary = arbitraryGreaterThanEqD
312+makeArbitrary ''LessThan
313+instance Arbitrary LessThan where arbitrary = arbitraryLessThan
314+makeArbitrary ''LessThanEq
315+instance Arbitrary LessThanEq where arbitrary = arbitraryLessThanEq
316+makeArbitrary ''GreaterThan
317+instance Arbitrary GreaterThan where arbitrary = arbitraryGreaterThan
318+makeArbitrary ''GreaterThanEq
319+instance Arbitrary GreaterThanEq where arbitrary = arbitraryGreaterThanEq
320+makeArbitrary ''GeoPoint
321+instance Arbitrary GeoPoint where arbitrary = arbitraryGeoPoint
322+makeArbitrary ''NullValue
323+instance Arbitrary NullValue where arbitrary = arbitraryNullValue
324+makeArbitrary ''MinimumMatchHighLow
325+instance Arbitrary MinimumMatchHighLow where arbitrary = arbitraryMinimumMatchHighLow
326+makeArbitrary ''CommonMinimumMatch
327+instance Arbitrary CommonMinimumMatch where arbitrary = arbitraryCommonMinimumMatch
328+makeArbitrary ''BoostingQuery
329+instance Arbitrary BoostingQuery where arbitrary = arbitraryBoostingQuery
330+makeArbitrary ''BoolQuery
331+instance Arbitrary BoolQuery where arbitrary = arbitraryBoolQuery
332+makeArbitrary ''MatchQuery
333+instance Arbitrary MatchQuery where arbitrary = arbitraryMatchQuery
334+makeArbitrary ''MultiMatchQueryType
335+instance Arbitrary MultiMatchQueryType where arbitrary = arbitraryMultiMatchQueryType
336+makeArbitrary ''BooleanOperator
337+instance Arbitrary BooleanOperator where arbitrary = arbitraryBooleanOperator
338+makeArbitrary ''ZeroTermsQuery
339+instance Arbitrary ZeroTermsQuery where arbitrary = arbitraryZeroTermsQuery
340+makeArbitrary ''MatchQueryType
341+instance Arbitrary MatchQueryType where arbitrary = arbitraryMatchQueryType
342+makeArbitrary ''SearchAliasRouting
343+instance Arbitrary SearchAliasRouting where arbitrary = arbitrarySearchAliasRouting
344+makeArbitrary ''ScoreType
345+instance Arbitrary ScoreType where arbitrary = arbitraryScoreType
346+makeArbitrary ''Distance
347+instance Arbitrary Distance where arbitrary = arbitraryDistance
348+makeArbitrary ''DistanceUnit
349+instance Arbitrary DistanceUnit where arbitrary = arbitraryDistanceUnit
350+makeArbitrary ''DistanceType
351+instance Arbitrary DistanceType where arbitrary = arbitraryDistanceType
352+makeArbitrary ''OptimizeBbox
353+instance Arbitrary OptimizeBbox where arbitrary = arbitraryOptimizeBbox
354+makeArbitrary ''GeoBoundingBoxConstraint
355+instance Arbitrary GeoBoundingBoxConstraint where arbitrary = arbitraryGeoBoundingBoxConstraint
356+makeArbitrary ''GeoFilterType
357+instance Arbitrary GeoFilterType where arbitrary = arbitraryGeoFilterType
358+makeArbitrary ''GeoBoundingBox
359+instance Arbitrary GeoBoundingBox where arbitrary = arbitraryGeoBoundingBox
360+makeArbitrary ''LatLon
361+instance Arbitrary LatLon where arbitrary = arbitraryLatLon
362+makeArbitrary ''RangeExecution
363+instance Arbitrary RangeExecution where arbitrary = arbitraryRangeExecution
364+makeArbitrary ''RegexpFlag
365+instance Arbitrary RegexpFlag where arbitrary = arbitraryRegexpFlag
366+makeArbitrary ''BoolMatch
367+instance Arbitrary BoolMatch where arbitrary = arbitraryBoolMatch
368+makeArbitrary ''Term
369+instance Arbitrary Term where arbitrary = arbitraryTerm
370+makeArbitrary ''IndexSettings
371+instance Arbitrary IndexSettings where arbitrary = arbitraryIndexSettings
372+makeArbitrary ''UpdatableIndexSetting
373+instance Arbitrary UpdatableIndexSetting where
374+ arbitrary = arbitraryUpdatableIndexSetting
375+makeArbitrary ''Bytes
376+instance Arbitrary Bytes where arbitrary = arbitraryBytes
377+makeArbitrary ''AllocationPolicy
378+instance Arbitrary AllocationPolicy where arbitrary = arbitraryAllocationPolicy
379+makeArbitrary ''InitialShardCount
380+instance Arbitrary InitialShardCount where arbitrary = arbitraryInitialShardCount
381+makeArbitrary ''FSType
382+instance Arbitrary FSType where arbitrary = arbitraryFSType
383+makeArbitrary ''CompoundFormat
384+instance Arbitrary CompoundFormat where arbitrary = arbitraryCompoundFormat
385+makeArbitrary ''FsSnapshotRepo
386+instance Arbitrary FsSnapshotRepo where arbitrary = arbitraryFsSnapshotRepo
387+makeArbitrary ''SnapshotRepoName
388+instance Arbitrary SnapshotRepoName where arbitrary = arbitrarySnapshotRepoName
389+makeArbitrary ''TemplateQueryInline
390+instance Arbitrary TemplateQueryInline where arbitrary = arbitraryTemplateQueryInline
391+makeArbitrary ''DirectGeneratorSuggestModeTypes
392+instance Arbitrary DirectGeneratorSuggestModeTypes where arbitrary = arbitraryDirectGeneratorSuggestModeTypes
393+makeArbitrary ''DirectGenerators
394+instance Arbitrary DirectGenerators where arbitrary = arbitraryDirectGenerators
395+makeArbitrary ''PhraseSuggesterCollate
396+instance Arbitrary PhraseSuggesterCollate where arbitrary = arbitraryPhraseSuggesterCollate
397+makeArbitrary ''PhraseSuggesterHighlighter
398+instance Arbitrary PhraseSuggesterHighlighter where arbitrary = arbitraryPhraseSuggesterHighlighter
399+makeArbitrary ''Size
400+instance Arbitrary Size where arbitrary = arbitrarySize
401+makeArbitrary ''PhraseSuggester
402+instance Arbitrary PhraseSuggester where arbitrary = arbitraryPhraseSuggester
403+makeArbitrary ''SuggestType
404+instance Arbitrary SuggestType where arbitrary = arbitrarySuggestType
405+makeArbitrary ''Suggest
406+instance Arbitrary Suggest where arbitrary = arbitrarySuggest
407+
408+
409+makeArbitrary ''Script
410+instance Arbitrary Script where arbitrary = arbitraryScript
411+
412+newtype UpdatableIndexSetting' =
413+ UpdatableIndexSetting' UpdatableIndexSetting
414+ deriving (Show, Eq, ToJSON, FromJSON, ApproxEq, Typeable)
415+
416+instance Arbitrary UpdatableIndexSetting' where
417+ arbitrary = do
418+ settings <- arbitrary
419+ return $ UpdatableIndexSetting' $ case settings of
420+ RoutingAllocationInclude xs ->
421+ RoutingAllocationInclude (dropDuplicateAttrNames xs)
422+ RoutingAllocationExclude xs ->
423+ RoutingAllocationExclude (dropDuplicateAttrNames xs)
424+ RoutingAllocationRequire xs ->
425+ RoutingAllocationRequire (dropDuplicateAttrNames xs)
426+ x -> x
427+ where
428+ dropDuplicateAttrNames =
429+ NE.fromList . L.nubBy sameAttrName . NE.toList
430+ sameAttrName a b =
431+ nodeAttrFilterName a == nodeAttrFilterName b
432+ -- shrink (UpdatableIndexSetting' x) = map UpdatableIndexSetting' (shrink x)
tests/V1/Test/Highlights.hsnew file+32
@@ -0,0 +1,32 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Highlights where
4+
5+import Test.Common
6+import Test.Import
7+
8+import qualified Data.Map as M
9+
10+initHighlights :: Text -> BH IO (Either EsError (Maybe HitHighlight))
11+initHighlights fieldName = do
12+ _ <- insertData
13+ _ <- insertOther
14+ let query = QueryMatchQuery $ mkMatchQuery (FieldName fieldName) (QueryString "haskell")
15+ let testHighlight = Highlights Nothing [FieldHighlight (FieldName fieldName) Nothing]
16+ let search = mkHighlightSearch (Just query) testHighlight
17+ searchTweetHighlight search
18+
19+spec :: Spec
20+spec =
21+ describe "Highlights API" $ do
22+ it "returns highlight from query when there should be one" $ withTestEnv $ do
23+ myHighlight <- initHighlights "message"
24+ liftIO $
25+ myHighlight `shouldBe`
26+ Right (Just (M.fromList [("message", ["Use <em>haskell</em>!"])]))
27+
28+ it "doesn't return highlight from a query when it shouldn't" $ withTestEnv $ do
29+ myHighlight <- initHighlights "user"
30+ liftIO $
31+ myHighlight `shouldBe`
32+ Right Nothing
tests/V1/Test/Import.hsnew file+58
@@ -0,0 +1,58 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Import
4+ ( module X
5+ , module Test.Import
6+ ) where
7+
8+
9+import Control.Applicative as X
10+import Control.Exception as X (evaluate)
11+import Control.Monad as X
12+import Control.Monad.Catch as X
13+import Control.Monad.Reader as X
14+import Data.Aeson as X
15+import Data.Aeson.TH as X
16+import Data.Aeson.Types as X (parseEither)
17+import Data.Maybe as X
18+import Data.List.NonEmpty as X (NonEmpty(..))
19+import Data.Monoid as X
20+import Data.Ord as X (comparing)
21+import Data.Proxy as X
22+import Data.Text as X (Text)
23+import Data.Time.Calendar as X (Day(..), fromGregorian)
24+import Data.Time.Clock as X
25+import Data.Typeable as X
26+import Database.V1.Bloodhound as X hiding (key)
27+import Lens.Micro as X
28+import Lens.Micro.Aeson as X
29+import Network.HTTP.Client as X hiding (Proxy, fileSize)
30+import System.IO.Temp as X
31+import System.PosixCompat.Files as X
32+import Test.Hspec as X
33+import Test.Hspec.QuickCheck as X (prop)
34+import Test.QuickCheck as X hiding (Result, Success)
35+import Test.QuickCheck.Property.Monoid as X (T (..), eq, prop_Monoid)
36+import Text.Pretty.Simple as X (pPrint)
37+
38+import qualified Data.List as L
39+
40+noDuplicates :: Eq a => [a] -> Bool
41+noDuplicates xs = L.nub xs == xs
42+
43+getSource :: EsResult a -> Maybe a
44+getSource = fmap _source . foundResult
45+
46+grabFirst :: Either EsError (SearchResult a) -> Either EsError a
47+grabFirst r =
48+ case fmap (hitSource . head . hits . searchHits) r of
49+ (Left e) -> Left e
50+ (Right Nothing) -> Left (EsError 500 "Source was missing")
51+ (Right (Just x)) -> Right x
52+
53+when' :: Monad m => m Bool -> m () -> m ()
54+when' b f = b >>= \x -> when x f
55+
56+headMay :: [a] -> Maybe a
57+headMay (x : _) = Just x
58+headMay _ = Nothing
tests/V1/Test/Indices.hsnew file+78
@@ -0,0 +1,78 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Indices where
4+
5+import Test.Common
6+import Test.Import
7+
8+import qualified Data.List as L
9+import qualified Data.List.NonEmpty as NE
10+
11+spec :: Spec
12+spec = do
13+ describe "Index create/delete API" $ do
14+ it "creates and then deletes the requested index" $ withTestEnv $ do
15+ -- priming state.
16+ _ <- deleteExampleIndex
17+ resp <- createExampleIndex
18+ deleteResp <- deleteExampleIndex
19+ liftIO $ do
20+ validateStatus resp 200
21+ validateStatus deleteResp 200
22+
23+ describe "Index aliases" $ do
24+ let aname = IndexAliasName (IndexName "bloodhound-tests-twitter-1-alias")
25+ let alias = IndexAlias (testIndex) aname
26+ let create = IndexAliasCreate Nothing Nothing
27+ let action = AddAlias alias create
28+ it "handles the simple case of aliasing an existing index" $ do
29+ withTestEnv $ do
30+ resetIndex
31+ resp <- updateIndexAliases (action :| [])
32+ liftIO $ validateStatus resp 200
33+ let cleanup = withTestEnv (updateIndexAliases (RemoveAlias alias :| []))
34+ (do aliases <- withTestEnv getIndexAliases
35+ let expected = IndexAliasSummary alias create
36+ case aliases of
37+ Right (IndexAliasesSummary summs) ->
38+ L.find ((== alias) . indexAliasSummaryAlias) summs `shouldBe` Just expected
39+ Left e -> expectationFailure ("Expected an IndexAliasesSummary but got " <> show e)) `finally` cleanup
40+
41+ describe "Index Listing" $ do
42+ it "returns a list of index names" $ withTestEnv $ do
43+ _ <- createExampleIndex
44+ ixns <- listIndices
45+ liftIO (ixns `shouldContain` [testIndex])
46+
47+ describe "Index Settings" $ do
48+ it "persists settings" $ withTestEnv $ do
49+ _ <- deleteExampleIndex
50+ _ <- createExampleIndex
51+ let updates = BlocksWrite False :| []
52+ updateResp <- updateIndexSettings updates testIndex
53+ liftIO $ validateStatus updateResp 200
54+ getResp <- getIndexSettings testIndex
55+ liftIO $
56+ getResp `shouldBe` Right (IndexSettingsSummary
57+ testIndex
58+ (IndexSettings (ShardCount 1) (ReplicaCount 0))
59+ (NE.toList updates))
60+
61+ it "allows total fields to be set" $ when' (atleast es50) $ withTestEnv $ do
62+ _ <- deleteExampleIndex
63+ _ <- createExampleIndex
64+ let updates = FailOnMergeFailure True :| []
65+ updateResp <- updateIndexSettings updates testIndex
66+ liftIO $ validateStatus updateResp 200
67+ getResp <- getIndexSettings testIndex
68+ liftIO $
69+ getResp `shouldBe` Right (IndexSettingsSummary
70+ testIndex
71+ (IndexSettings (ShardCount 1) (ReplicaCount 0))
72+ (NE.toList updates))
73+
74+ describe "Index Optimization" $ do
75+ it "returns a successful response upon completion" $ withTestEnv $ do
76+ _ <- createExampleIndex
77+ resp <- optimizeIndex (IndexList (testIndex :| [])) defaultIndexOptimizationSettings
78+ liftIO $ validateStatus resp 200
tests/V1/Test/JSON.hsnew file+202
@@ -0,0 +1,202 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+module Test.JSON (spec) where
5+
6+import Test.Import
7+
8+import qualified Data.ByteString.Lazy.Char8 as BL8
9+import qualified Data.List as L
10+import Data.List.NonEmpty (NonEmpty(..))
11+import qualified Data.List.NonEmpty as NE
12+import qualified Data.HashMap.Strict as HM
13+import qualified Data.Text as T
14+import qualified Data.Vector as V
15+
16+import Test.ApproxEq
17+import Test.Generators
18+
19+propJSON :: forall a
20+ . ( Arbitrary a
21+ , ToJSON a
22+ , FromJSON a
23+ , Show a
24+ , Eq a
25+ , Typeable a
26+ )
27+ => Proxy a -> Spec
28+propJSON _ = prop testName $ \(a :: a) ->
29+ let jsonStr = "via " <> BL8.unpack (encode a)
30+ in counterexample jsonStr (parseEither parseJSON (toJSON a)
31+ === Right a)
32+ where testName = show ty <> " FromJSON/ToJSON roundtrips"
33+ ty = typeOf (undefined :: a)
34+
35+propApproxJSON :: forall a
36+ . ( Arbitrary a
37+ , ToJSON a
38+ , FromJSON a
39+ , Show a
40+ , ApproxEq a
41+ , Typeable a
42+ )
43+ => Proxy a -> Spec
44+propApproxJSON _ = prop testName $ \(a :: a) ->
45+ let jsonStr = "via " <> BL8.unpack (encode a)
46+ in counterexample jsonStr (parseEither parseJSON (toJSON a)
47+ ==~ Right a)
48+ where testName = show ty <> " FromJSON/ToJSON roundtrips"
49+ ty = typeOf (undefined :: a)
50+
51+spec :: Spec
52+spec = do
53+ describe "ToJSON RegexpFlags" $ do
54+ it "generates the correct JSON for AllRegexpFlags" $
55+ toJSON AllRegexpFlags `shouldBe` String "ALL"
56+
57+ it "generates the correct JSON for NoRegexpFlags" $
58+ toJSON NoRegexpFlags `shouldBe` String "NONE"
59+
60+ it "generates the correct JSON for SomeRegexpFlags" $
61+ let flags = AnyString :| [ Automaton
62+ , Complement
63+ , Empty
64+ , Intersection
65+ , Interval ]
66+ in toJSON (SomeRegexpFlags flags) `shouldBe` String "ANYSTRING|AUTOMATON|COMPLEMENT|EMPTY|INTERSECTION|INTERVAL"
67+
68+ prop "removes duplicates from flags" $ \(flags :: RegexpFlags) ->
69+ let String str = toJSON flags
70+ flagStrs = T.splitOn "|" str
71+ in noDuplicates flagStrs
72+
73+ describe "omitNulls" $ do
74+ it "checks that omitNulls drops list elements when it should" $
75+ let dropped = omitNulls $ [ "test1" .= (toJSON ([] :: [Int]))
76+ , "test2" .= (toJSON ("some value" :: Text))]
77+ in dropped `shouldBe` Object (HM.fromList [("test2", String "some value")])
78+
79+ it "checks that omitNulls doesn't drop list elements when it shouldn't" $
80+ let notDropped = omitNulls $ [ "test1" .= (toJSON ([1] :: [Int]))
81+ , "test2" .= (toJSON ("some value" :: Text))]
82+ in notDropped `shouldBe` Object (HM.fromList [ ("test1", Array (V.fromList [Number 1.0]))
83+ , ("test2", String "some value")])
84+ it "checks that omitNulls drops non list elements when it should" $
85+ let dropped = omitNulls $ [ "test1" .= (toJSON Null)
86+ , "test2" .= (toJSON ("some value" :: Text))]
87+ in dropped `shouldBe` Object (HM.fromList [("test2", String "some value")])
88+ it "checks that omitNulls doesn't drop non list elements when it shouldn't" $
89+ let notDropped = omitNulls $ [ "test1" .= (toJSON (1 :: Int))
90+ , "test2" .= (toJSON ("some value" :: Text))]
91+ in notDropped `shouldBe` Object (HM.fromList [ ("test1", Number 1.0)
92+ , ("test2", String "some value")])
93+
94+ describe "Exact isomorphism JSON instances" $ do
95+ propJSON (Proxy :: Proxy Version)
96+ propJSON (Proxy :: Proxy IndexName)
97+ propJSON (Proxy :: Proxy MappingName)
98+ propJSON (Proxy :: Proxy DocId)
99+ propJSON (Proxy :: Proxy IndexAliasRouting)
100+ propJSON (Proxy :: Proxy RoutingValue)
101+ propJSON (Proxy :: Proxy ShardCount)
102+ propJSON (Proxy :: Proxy ReplicaCount)
103+ propJSON (Proxy :: Proxy TemplateName)
104+ propJSON (Proxy :: Proxy TemplatePattern)
105+ propJSON (Proxy :: Proxy QueryString)
106+ propJSON (Proxy :: Proxy FieldName)
107+ propJSON (Proxy :: Proxy CacheName)
108+ propJSON (Proxy :: Proxy CacheKey)
109+ propJSON (Proxy :: Proxy Existence)
110+ propJSON (Proxy :: Proxy CutoffFrequency)
111+ propJSON (Proxy :: Proxy Analyzer)
112+ propJSON (Proxy :: Proxy MaxExpansions)
113+ propJSON (Proxy :: Proxy Lenient)
114+ propJSON (Proxy :: Proxy Tiebreaker)
115+ propJSON (Proxy :: Proxy Boost)
116+ propJSON (Proxy :: Proxy BoostTerms)
117+ propJSON (Proxy :: Proxy MinimumMatch)
118+ propJSON (Proxy :: Proxy DisableCoord)
119+ propJSON (Proxy :: Proxy IgnoreTermFrequency)
120+ propJSON (Proxy :: Proxy MinimumTermFrequency)
121+ propJSON (Proxy :: Proxy MaxQueryTerms)
122+ propJSON (Proxy :: Proxy Fuzziness)
123+ propJSON (Proxy :: Proxy PrefixLength)
124+ propJSON (Proxy :: Proxy TypeName)
125+ propJSON (Proxy :: Proxy PercentMatch)
126+ propJSON (Proxy :: Proxy StopWord)
127+ propJSON (Proxy :: Proxy QueryPath)
128+ propJSON (Proxy :: Proxy AllowLeadingWildcard)
129+ propJSON (Proxy :: Proxy LowercaseExpanded)
130+ propJSON (Proxy :: Proxy EnablePositionIncrements)
131+ propJSON (Proxy :: Proxy AnalyzeWildcard)
132+ propJSON (Proxy :: Proxy GeneratePhraseQueries)
133+ propJSON (Proxy :: Proxy Locale)
134+ propJSON (Proxy :: Proxy MaxWordLength)
135+ propJSON (Proxy :: Proxy MinWordLength)
136+ propJSON (Proxy :: Proxy PhraseSlop)
137+ propJSON (Proxy :: Proxy MinDocFrequency)
138+ propJSON (Proxy :: Proxy MaxDocFrequency)
139+ propJSON (Proxy :: Proxy Filter)
140+ propJSON (Proxy :: Proxy Query)
141+ propJSON (Proxy :: Proxy SimpleQueryStringQuery)
142+ propJSON (Proxy :: Proxy FieldOrFields)
143+ propJSON (Proxy :: Proxy SimpleQueryFlag)
144+ propJSON (Proxy :: Proxy RegexpQuery)
145+ propJSON (Proxy :: Proxy QueryStringQuery)
146+ propJSON (Proxy :: Proxy RangeQuery)
147+ propJSON (Proxy :: Proxy PrefixQuery)
148+ propJSON (Proxy :: Proxy NestedQuery)
149+ propJSON (Proxy :: Proxy MoreLikeThisFieldQuery)
150+ propJSON (Proxy :: Proxy MoreLikeThisQuery)
151+ propJSON (Proxy :: Proxy IndicesQuery)
152+ propJSON (Proxy :: Proxy HasParentQuery)
153+ propJSON (Proxy :: Proxy HasChildQuery)
154+ propJSON (Proxy :: Proxy FuzzyQuery)
155+ propJSON (Proxy :: Proxy FuzzyLikeFieldQuery)
156+ propJSON (Proxy :: Proxy FuzzyLikeThisQuery)
157+ propJSON (Proxy :: Proxy DisMaxQuery)
158+ propJSON (Proxy :: Proxy CommonTermsQuery)
159+ propJSON (Proxy :: Proxy CommonMinimumMatch)
160+ propJSON (Proxy :: Proxy BoostingQuery)
161+ propJSON (Proxy :: Proxy BoolQuery)
162+ propJSON (Proxy :: Proxy MatchQuery)
163+ propJSON (Proxy :: Proxy MultiMatchQueryType)
164+ propJSON (Proxy :: Proxy BooleanOperator)
165+ propJSON (Proxy :: Proxy ZeroTermsQuery)
166+ propJSON (Proxy :: Proxy MatchQueryType)
167+ propJSON (Proxy :: Proxy AliasRouting)
168+ propJSON (Proxy :: Proxy IndexAliasCreate)
169+ propJSON (Proxy :: Proxy SearchAliasRouting)
170+ propJSON (Proxy :: Proxy ScoreType)
171+ propJSON (Proxy :: Proxy Distance)
172+ propJSON (Proxy :: Proxy DistanceUnit)
173+ propJSON (Proxy :: Proxy DistanceType)
174+ propJSON (Proxy :: Proxy OptimizeBbox)
175+ propJSON (Proxy :: Proxy GeoBoundingBoxConstraint)
176+ propJSON (Proxy :: Proxy GeoFilterType)
177+ propJSON (Proxy :: Proxy GeoBoundingBox)
178+ propJSON (Proxy :: Proxy LatLon)
179+ propJSON (Proxy :: Proxy RangeExecution)
180+ prop "RegexpFlags FromJSON/ToJSON roundtrips, removing dups " $ \rfs ->
181+ let expected = case rfs of
182+ SomeRegexpFlags fs -> SomeRegexpFlags (NE.fromList (L.nub (NE.toList fs)))
183+ x -> x
184+ in parseEither parseJSON (toJSON rfs) === Right expected
185+ propJSON (Proxy :: Proxy BoolMatch)
186+ propJSON (Proxy :: Proxy Term)
187+ propJSON (Proxy :: Proxy MultiMatchQuery)
188+ propJSON (Proxy :: Proxy IndexSettings)
189+ propJSON (Proxy :: Proxy CompoundFormat)
190+ propJSON (Proxy :: Proxy TemplateQueryInline)
191+ propJSON (Proxy :: Proxy Suggest)
192+ propJSON (Proxy :: Proxy DirectGenerators)
193+ propJSON (Proxy :: Proxy DirectGeneratorSuggestModeTypes)
194+
195+ describe "Approximate isomorphism JSON instances" $ do
196+ propApproxJSON (Proxy :: Proxy UpdatableIndexSetting')
197+ propApproxJSON (Proxy :: Proxy ReplicaCount)
198+ propApproxJSON (Proxy :: Proxy ReplicaBounds)
199+ propApproxJSON (Proxy :: Proxy Bytes)
200+ propApproxJSON (Proxy :: Proxy AllocationPolicy)
201+ propApproxJSON (Proxy :: Proxy InitialShardCount)
202+ propApproxJSON (Proxy :: Proxy FSType)
tests/V1/Test/Query.hsnew file+115
@@ -0,0 +1,115 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Query where
4+
5+import Test.Common
6+import Test.Import
7+
8+import qualified Data.HashMap.Strict as HM
9+
10+spec :: Spec
11+spec =
12+ describe "query API" $ do
13+ it "returns document for term query and identity filter" $ withTestEnv $ do
14+ _ <- insertData
15+ let query = TermQuery (Term "user" "bitemyapp") Nothing
16+ let filter' = IdentityFilter
17+ let search = mkSearch (Just query) (Just filter')
18+ myTweet <- searchTweet search
19+ liftIO $
20+ myTweet `shouldBe` Right exampleTweet
21+
22+ it "handles constant score queries" $ withTestEnv $ do
23+ _ <- insertData
24+ let query = TermsQuery "user" ("bitemyapp" :| [])
25+ let cfQuery = ConstantScoreQuery query (Boost 1.0)
26+ let filter' = IdentityFilter
27+ let search = mkSearch (Just cfQuery) (Just filter')
28+ myTweet <- searchTweet search
29+ liftIO $
30+ myTweet `shouldBe` Right exampleTweet
31+
32+ it "returns document for terms query and identity filter" $ withTestEnv $ do
33+ _ <- insertData
34+ let query = TermsQuery "user" ("bitemyapp" :| [])
35+ let filter' = IdentityFilter
36+ let search = mkSearch (Just query) (Just filter')
37+ myTweet <- searchTweet search
38+ liftIO $
39+ myTweet `shouldBe` Right exampleTweet
40+
41+ it "returns document for match query" $ withTestEnv $ do
42+ _ <- insertData
43+ let query = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
44+ let search = mkSearch (Just query) Nothing
45+ myTweet <- searchTweet search
46+ liftIO $
47+ myTweet `shouldBe` Right exampleTweet
48+
49+ it "returns document for multi-match query" $ withTestEnv $ do
50+ _ <- insertData
51+ let flds = [FieldName "user", FieldName "message"]
52+ let query = QueryMultiMatchQuery $ mkMultiMatchQuery flds (QueryString "bitemyapp")
53+ let search = mkSearch (Just query) Nothing
54+ myTweet <- searchTweet search
55+ liftIO $
56+ myTweet `shouldBe` Right exampleTweet
57+
58+ it "returns document for multi-match query with a custom tiebreaker" $ withTestEnv $ do
59+ _ <- insertData
60+ let tiebreaker = Just $ Tiebreaker 0.3
61+ flds = [FieldName "user", FieldName "message"]
62+ multiQuery' = mkMultiMatchQuery flds (QueryString "bitemyapp")
63+ query = QueryMultiMatchQuery $ multiQuery' { multiMatchQueryTiebreaker = tiebreaker }
64+ search = mkSearch (Just query) Nothing
65+ myTweet <- searchTweet search
66+ liftIO $
67+ myTweet `shouldBe` Right exampleTweet
68+
69+ it "returns document for bool query" $ withTestEnv $ do
70+ _ <- insertData
71+ let innerQuery = QueryMatchQuery $
72+ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
73+ let query = QueryBoolQuery $
74+ mkBoolQuery [innerQuery] [] []
75+ let search = mkSearch (Just query) Nothing
76+ myTweet <- searchTweet search
77+ liftIO $
78+ myTweet `shouldBe` Right exampleTweet
79+
80+ it "returns document for boosting query" $ withTestEnv $ do
81+ _ <- insertData
82+ let posQuery = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
83+ let negQuery = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "notmyapp")
84+ let query = QueryBoostingQuery $ BoostingQuery posQuery negQuery (Boost 0.2)
85+ let search = mkSearch (Just query) Nothing
86+ myTweet <- searchTweet search
87+ liftIO $
88+ myTweet `shouldBe` Right exampleTweet
89+
90+ it "returns document for common terms query" $ withTestEnv $ do
91+ _ <- insertData
92+ let query = QueryCommonTermsQuery $
93+ CommonTermsQuery (FieldName "user")
94+ (QueryString "bitemyapp")
95+ (CutoffFrequency 0.0001)
96+ Or Or Nothing Nothing Nothing Nothing
97+ let search = mkSearch (Just query) Nothing
98+ myTweet <- searchTweet search
99+ liftIO $
100+ myTweet `shouldBe` Right exampleTweet
101+
102+ it "returns document for for inline template query" $ withTestEnv $ do
103+ _ <- insertData
104+ let innerQuery = QueryMatchQuery $
105+ mkMatchQuery (FieldName "{{userKey}}")
106+ (QueryString "{{bitemyappKey}}")
107+ templateParams = TemplateQueryKeyValuePairs $ HM.fromList
108+ [ ("userKey", "user")
109+ , ("bitemyappKey", "bitemyapp")
110+ ]
111+ templateQuery = QueryTemplateQueryInline $
112+ TemplateQueryInline innerQuery templateParams
113+ search = mkSearch (Just templateQuery) Nothing
114+ myTweet <- searchTweet search
115+ liftIO $ myTweet `shouldBe` Right exampleTweet
tests/V1/Test/Snapshots.hsnew file+201
@@ -0,0 +1,201 @@
1+{-# LANGUAGE RecordWildCards #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Test.Snapshots (spec) where
5+
6+import Test.Common
7+import Test.Import
8+
9+import Data.Maybe (fromMaybe)
10+import qualified Data.List as L
11+import qualified Data.HashMap.Strict as HM
12+import qualified Data.Text as T
13+import qualified Data.Vector as V
14+import qualified Network.HTTP.Types.Method as NHTM
15+import qualified Network.URI as URI
16+
17+import Test.Generators ()
18+
19+spec :: Spec
20+spec = do
21+ describe "FsSnapshotRepo" $
22+ prop "SnapshotRepo laws" $ \fsr ->
23+ fromGSnapshotRepo (toGSnapshotRepo fsr) === Right (fsr :: FsSnapshotRepo)
24+
25+ describe "Snapshot repos" $ do
26+ it "always parses all snapshot repos API" $ when' canSnapshot $ withTestEnv $ do
27+ res <- getSnapshotRepos AllSnapshotRepos
28+ liftIO $ case res of
29+ Left e -> expectationFailure ("Expected a right but got Left " <> show e)
30+ Right _ -> return ()
31+
32+ it "finds an existing list of repos" $ when' canSnapshot $ withTestEnv $ do
33+ let r1n = SnapshotRepoName "bloodhound-repo1"
34+ let r2n = SnapshotRepoName "bloodhound-repo2"
35+ withSnapshotRepo r1n $ \r1 ->
36+ withSnapshotRepo r2n $ \r2 -> do
37+ repos <- getSnapshotRepos (SnapshotRepoList (ExactRepo r1n :| [ExactRepo r2n]))
38+ liftIO $ case repos of
39+ Right xs -> do
40+ let srt = L.sortBy (comparing gSnapshotRepoName)
41+ srt xs `shouldBe` srt [r1, r2]
42+ Left e -> expectationFailure (show e)
43+
44+ it "creates and updates with updateSnapshotRepo" $ when' canSnapshot $ withTestEnv $ do
45+ let r1n = SnapshotRepoName "bloodhound-repo1"
46+ withSnapshotRepo r1n $ \r1 -> do
47+ let Just (String dir) = HM.lookup "location" (gSnapshotRepoSettingsObject (gSnapshotRepoSettings r1))
48+ let noCompression = FsSnapshotRepo r1n (T.unpack dir) False Nothing Nothing Nothing
49+ resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings noCompression
50+ liftIO (validateStatus resp 200)
51+ Right [roundtrippedNoCompression] <- getSnapshotRepos (SnapshotRepoList (ExactRepo r1n :| []))
52+ liftIO (roundtrippedNoCompression `shouldBe` toGSnapshotRepo noCompression)
53+
54+ -- verify came around in 1.4 it seems
55+ it "can verify existing repos" $ when' canSnapshot $ when' (atleast es14) $ withTestEnv $ do
56+ let r1n = SnapshotRepoName "bloodhound-repo1"
57+ withSnapshotRepo r1n $ \_ -> do
58+ res <- verifySnapshotRepo r1n
59+ liftIO $ case res of
60+ Right (SnapshotVerification vs)
61+ | null vs -> expectationFailure "Expected nonempty set of verifying nodes"
62+ | otherwise -> return ()
63+ Left e -> expectationFailure (show e)
64+
65+ describe "Snapshots" $ do
66+ it "always parses all snapshots API" $ when' canSnapshot $ withTestEnv $ do
67+ let r1n = SnapshotRepoName "bloodhound-repo1"
68+ withSnapshotRepo r1n $ \_ -> do
69+ res <- getSnapshots r1n AllSnapshots
70+ liftIO $ case res of
71+ Left e -> expectationFailure ("Expected a right but got Left " <> show e)
72+ Right _ -> return ()
73+
74+ it "can parse a snapshot that it created" $ when' canSnapshot $ withTestEnv $ do
75+ let r1n = SnapshotRepoName "bloodhound-repo1"
76+ withSnapshotRepo r1n $ \_ -> do
77+ let s1n = SnapshotName "example-snapshot"
78+ withSnapshot r1n s1n $ do
79+ res <- getSnapshots r1n (SnapshotList (ExactSnap s1n :| []))
80+ liftIO $ case res of
81+ Right [snap]
82+ | snapInfoState snap == SnapshotSuccess &&
83+ snapInfoName snap == s1n -> return ()
84+ | otherwise -> expectationFailure (show snap)
85+ Right [] -> expectationFailure "There were no snapshots"
86+ Right snaps -> expectationFailure ("Expected 1 snapshot but got" <> show (length snaps))
87+ Left e -> expectationFailure (show e)
88+
89+ describe "Snapshot restore" $ do
90+ it "can restore a snapshot that we create" $ when' canSnapshot $ withTestEnv $ do
91+ let r1n = SnapshotRepoName "bloodhound-repo1"
92+ withSnapshotRepo r1n $ \_ -> do
93+ let s1n = SnapshotName "example-snapshot"
94+ withSnapshot r1n s1n $ do
95+ let settings = defaultSnapshotRestoreSettings { snapRestoreWaitForCompletion = True }
96+ -- have to close an index to restore it
97+ resp1 <- closeIndex testIndex
98+ liftIO (validateStatus resp1 200)
99+ resp2 <- restoreSnapshot r1n s1n settings
100+ liftIO (validateStatus resp2 200)
101+
102+ it "can restore and rename" $ when' canSnapshot $ withTestEnv $ do
103+ let r1n = SnapshotRepoName "bloodhound-repo1"
104+ withSnapshotRepo r1n $ \_ -> do
105+ let s1n = SnapshotName "example-snapshot"
106+ withSnapshot r1n s1n $ do
107+ let pat = RestoreRenamePattern "bloodhound-tests-twitter-(\\d+)"
108+ let replace = RRTLit "restored-" :| [RRSubWholeMatch]
109+ let expectedIndex = IndexName "restored-bloodhound-tests-twitter-1"
110+ oldEnoughForOverrides <- liftIO (atleast es15)
111+ let overrides = RestoreIndexSettings { restoreOverrideReplicas = Just (ReplicaCount 0) }
112+ let settings = defaultSnapshotRestoreSettings { snapRestoreWaitForCompletion = True
113+ , snapRestoreRenamePattern = Just pat
114+ , snapRestoreRenameReplacement = Just replace
115+ , snapRestoreIndexSettingsOverrides = if oldEnoughForOverrides
116+ then Just overrides
117+ else Nothing
118+ }
119+ -- have to close an index to restore it
120+ let go = do
121+ resp <- restoreSnapshot r1n s1n settings
122+ liftIO (validateStatus resp 200)
123+ exists <- indexExists expectedIndex
124+ liftIO (exists `shouldBe` True)
125+ go `finally` deleteIndex expectedIndex
126+
127+-- | Get configured repo paths for snapshotting. Note that by default
128+-- this is not enabled and if we are over es 1.5, we won't be able to
129+-- test snapshotting. Note that this can and should be part of the
130+-- client functionality in a much less ad-hoc incarnation.
131+getRepoPaths :: IO [FilePath]
132+getRepoPaths = withTestEnv $ do
133+ bhe <- getBHEnv
134+ let Server s = bhServer bhe
135+ let tUrl = s <> "/" <> "_nodes"
136+ initReq <- parseRequest (URI.escapeURIString URI.isAllowedInURI (T.unpack tUrl))
137+ let req = setRequestIgnoreStatus $ initReq { method = NHTM.methodGet }
138+ Right (Object o) <- parseEsResponse =<< liftIO (httpLbs req (bhManager bhe))
139+ return $ fromMaybe mempty $ do
140+ Object nodes <- HM.lookup "nodes" o
141+ Object firstNode <- snd <$> headMay (HM.toList nodes)
142+ Object settings <- HM.lookup "settings" firstNode
143+ Object path <- HM.lookup "path" settings
144+ Array repo <- HM.lookup "repo" path
145+ return [ T.unpack t | String t <- V.toList repo]
146+
147+-- | 1.5 and earlier don't care about repo paths
148+canSnapshot :: IO Bool
149+canSnapshot = do
150+ caresAboutRepos <- atleast es16
151+ repoPaths <- getRepoPaths
152+ return (not caresAboutRepos || not (null repoPaths))
153+
154+withSnapshotRepo
155+ :: ( MonadMask m
156+ , MonadBH m
157+ )
158+ => SnapshotRepoName
159+ -> (GenericSnapshotRepo -> m a)
160+ -> m a
161+withSnapshotRepo srn@(SnapshotRepoName n) f = do
162+ repoPaths <- liftIO getRepoPaths
163+ -- we'll use the first repo path if available, otherwise system temp
164+ -- dir. Note that this will fail on ES > 1.6, so be sure you use
165+ -- @when' canSnapshot@.
166+ case repoPaths of
167+ (firstRepoPath:_) -> withTempDirectory firstRepoPath (T.unpack n) $ \dir -> bracket (alloc dir) free f
168+ [] -> withSystemTempDirectory (T.unpack n) $ \dir -> bracket (alloc dir) free f
169+ where
170+ alloc dir = do
171+ liftIO (setFileMode dir mode)
172+ let repo = FsSnapshotRepo srn "bloodhound-tests-backups" True Nothing Nothing Nothing
173+ resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings repo
174+ liftIO (validateStatus resp 200)
175+ return (toGSnapshotRepo repo)
176+ mode = ownerModes `unionFileModes` groupModes `unionFileModes` otherModes
177+ free GenericSnapshotRepo {..} = do
178+ resp <- deleteSnapshotRepo gSnapshotRepoName
179+ liftIO (validateStatus resp 200)
180+
181+
182+withSnapshot
183+ :: ( MonadMask m
184+ , MonadBH m
185+ )
186+ => SnapshotRepoName
187+ -> SnapshotName
188+ -> m a
189+ -> m a
190+withSnapshot srn sn = bracket_ alloc free
191+ where
192+ alloc = do
193+ resp <- createSnapshot srn sn createSettings
194+ liftIO (validateStatus resp 200)
195+ -- We'll make this synchronous for testing purposes
196+ createSettings = defaultSnapshotCreateSettings { snapWaitForCompletion = True
197+ , snapIndices = Just (IndexList (testIndex :| []))
198+ -- We don't actually need to back up any data
199+ }
200+ free =
201+ deleteSnapshot srn sn
tests/V1/Test/Sorting.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Sorting where
4+
5+import Test.Common
6+import Test.Import
7+
8+spec :: Spec
9+spec =
10+ describe "sorting" $
11+ it "returns documents in the right order" $ withTestEnv $ do
12+ _ <- insertData
13+ _ <- insertOther
14+ let sortSpec = DefaultSortSpec $ mkSort (FieldName "age") Ascending
15+ let search = Search Nothing
16+ Nothing (Just [sortSpec]) Nothing Nothing
17+ False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
18+ Nothing
19+ result <- searchTweets search
20+ let myTweet = grabFirst result
21+ liftIO $
22+ myTweet `shouldBe` Right otherTweet
tests/V1/Test/SourceFiltering.hsnew file+38
@@ -0,0 +1,38 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.SourceFiltering where
4+
5+import Test.Common
6+import Test.Import
7+
8+import qualified Data.HashMap.Strict as HM
9+
10+spec :: Spec
11+spec =
12+ describe "Source filtering" $ do
13+
14+ it "doesn't include source when sources are disabled" $ withTestEnv $
15+ searchExpectSource
16+ NoSource
17+ (Left (EsError 500 "Source was missing"))
18+
19+ it "includes a source" $ withTestEnv $
20+ searchExpectSource
21+ (SourcePatterns (PopPattern (Pattern "message")))
22+ (Right (Object (HM.fromList [("message", String "Use haskell!")])))
23+
24+ it "includes sources" $ withTestEnv $
25+ searchExpectSource
26+ (SourcePatterns (PopPatterns [Pattern "user", Pattern "message"]))
27+ (Right (Object (HM.fromList [("user",String "bitemyapp"),("message", String "Use haskell!")])))
28+
29+ it "includes source patterns" $ withTestEnv $
30+ searchExpectSource
31+ (SourcePatterns (PopPattern (Pattern "*ge")))
32+ (Right (Object (HM.fromList [("age", Number 10000),("message", String "Use haskell!")])))
33+
34+ it "excludes source patterns" $ withTestEnv $
35+ searchExpectSource
36+ (SourceIncludeExclude (Include [])
37+ (Exclude [Pattern "l*", Pattern "*ge", Pattern "postDate", Pattern "extra"]))
38+ (Right (Object (HM.fromList [("user",String "bitemyapp")])))
tests/V1/Test/Suggest.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Suggest where
4+
5+import Test.Common
6+import Test.Import
7+
8+spec :: Spec
9+spec =
10+ describe "Suggest" $
11+ it "returns a search suggestion using the phrase suggester" $ withTestEnv $ do
12+ _ <- insertData
13+ let phraseSuggester = mkPhraseSuggester (FieldName "message")
14+ namedSuggester = Suggest "Use haskel" "suggest_name" (SuggestTypePhraseSuggester phraseSuggester)
15+ search' = mkSearch Nothing Nothing
16+ search = search' { suggestBody = Just namedSuggester }
17+ expectedText = Just "use haskell"
18+ resp <- searchByIndex testIndex search
19+ parsed <- parseEsResponse resp :: BH IO (Either EsError (SearchResult Tweet))
20+ case parsed of
21+ Left e -> liftIO $ expectationFailure ("Expected an search suggestion but got " <> show e)
22+ Right sr -> liftIO $ (suggestOptionsText . head . suggestResponseOptions . head . nsrResponses <$> suggest sr) `shouldBe` expectedText
tests/V1/Test/Templates.hsnew file+26
@@ -0,0 +1,26 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Test.Templates where
4+
5+import Test.Common
6+import Test.Import
7+
8+spec :: Spec
9+spec =
10+ describe "template API" $ do
11+ it "can create a template" $ withTestEnv $ do
12+ let idxTpl = IndexTemplate (TemplatePattern "tweet-*") (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) [toJSON TweetMapping]
13+ resp <- putTemplate idxTpl (TemplateName "tweet-tpl")
14+ liftIO $ validateStatus resp 200
15+
16+ it "can detect if a template exists" $ withTestEnv $ do
17+ exists <- templateExists (TemplateName "tweet-tpl")
18+ liftIO $ exists `shouldBe` True
19+
20+ it "can delete a template" $ withTestEnv $ do
21+ resp <- deleteTemplate (TemplateName "tweet-tpl")
22+ liftIO $ validateStatus resp 200
23+
24+ it "can detect if a template doesn't exist" $ withTestEnv $ do
25+ exists <- templateExists (TemplateName "tweet-tpl")
26+ liftIO $ exists `shouldBe` False
tests/V1/tests.hs+37−1887
@@ -1,9 +1,5 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2−{-# LANGUAGE DefaultSignatures #-}
3−{-# LANGUAGE DeriveDataTypeable #-}
4−{-# LANGUAGE DeriveGeneric #-}
5{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
6−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
8{-# LANGUAGE RecordWildCards #-}
4{-# LANGUAGE RecordWildCards #-}
9{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE ScopedTypeVariables #-}
@@ -15,972 +11,40 @@
15#if __GLASGOW_HASKELL__ >= 802
11#if __GLASGOW_HASKELL__ >= 802
16{-# LANGUAGE MonoLocalBinds #-}
12{-# LANGUAGE MonoLocalBinds #-}
17#endif
13#endif
18−
19module Main where
14module Main where
20
15
21−import Control.Applicative
16+import Test.Common
22−import Control.Error
17+import Test.Import
23−import Control.Exception (evaluate)
24−import Control.Monad
25−import Control.Monad.Catch
26−import Control.Monad.Reader
27−import Data.Aeson
28−import Data.Aeson.Types (parseEither)
29−import qualified Data.ByteString.Lazy.Char8 as BL8
30−import qualified Data.HashMap.Strict as HM
31−import Data.List (nub)
32−import qualified Data.List as L
33−import Data.List.NonEmpty (NonEmpty (..))
34−import qualified Data.List.NonEmpty as NE
35−import qualified Data.Map.Strict as M
36−import Data.Monoid
37−import Data.Ord (comparing)
38−import Data.Proxy
39−import Data.Text (Text)
40−import qualified Data.Text as T
41−import Data.Time.Calendar (Day (..), fromGregorian)
42−import Data.Time.Clock (NominalDiffTime, UTCTime (..),
43− secondsToDiffTime)
44−import Data.Typeable
45−import qualified Data.Vector as V
46−import qualified Data.Version as Vers
47−import Database.V1.Bloodhound
48−import GHC.Generics as G
49−import Network.HTTP.Client hiding (Proxy)
50−import qualified Network.HTTP.Types.Method as NHTM
51−import qualified Network.HTTP.Types.Status as NHTS
52−import qualified Network.URI as URI
53−import Prelude hiding (filter)
54−import System.IO.Temp
55−import System.PosixCompat.Files
56−import Test.Hspec
57−import Test.QuickCheck.Property.Monoid (T (..), eq, prop_Monoid)
58−
59−import Test.Hspec.QuickCheck (prop)
60−import Test.QuickCheck
61−
62−import qualified Generics.SOP as SOP
63−import qualified Generics.SOP.GGP as SOP
64−
65−testServer :: Server
66−testServer = Server "http://localhost:9200"
67−testIndex :: IndexName
68−testIndex = IndexName "bloodhound-tests-twitter-1"
69−testMapping :: MappingName
70−testMapping = MappingName "tweet"
71−
72−withTestEnv :: BH IO a -> IO a
73−withTestEnv = withBH defaultManagerSettings testServer
74−
75−validateStatus :: Show body => Response body -> Int -> Expectation
76−validateStatus resp expected =
77− if actual == expected
78− then return ()
79− else expectationFailure ("Expected " <> show expected <> " but got " <> show actual <> ": " <> show body)
80− where
81− actual = NHTS.statusCode (responseStatus resp)
82− body = responseBody resp
83−
84−createExampleIndex :: (MonadBH m) => m Reply
85−createExampleIndex = createIndex (IndexSettings (ShardCount 1) (ReplicaCount 0)) testIndex
86−deleteExampleIndex :: (MonadBH m) => m Reply
87−deleteExampleIndex = deleteIndex testIndex
88−
89−es13 :: Vers.Version
90−es13 = Vers.Version [1, 3, 0] []
91−
92−es12 :: Vers.Version
93−es12 = Vers.Version [1, 2, 0] []
94−
95−es11 :: Vers.Version
96−es11 = Vers.Version [1, 1, 0] []
97−
98−es14 :: Vers.Version
99−es14 = Vers.Version [1, 4, 0] []
100−
101−es15 :: Vers.Version
102−es15 = Vers.Version [1, 5, 0] []
103−
104−es16 :: Vers.Version
105−es16 = Vers.Version [1, 6, 0] []
106−
107−es20 :: Vers.Version
108−es20 = Vers.Version [2, 0, 0] []
109−
110−getServerVersion :: IO (Maybe Vers.Version)
111−getServerVersion = fmap extractVersion <$> withTestEnv getStatus
112− where
113− extractVersion = versionNumber . number . version
114−
115−-- | Get configured repo paths for snapshotting. Note that by default
116−-- this is not enabled and if we are over es 1.5, we won't be able to
117−-- test snapshotting. Note that this can and should be part of the
118−-- client functionality in a much less ad-hoc incarnation.
119−getRepoPaths :: IO [FilePath]
120−getRepoPaths = withTestEnv $ do
121− bhe <- getBHEnv
122− let Server s = bhServer bhe
123− let tUrl = s <> "/" <> "_nodes"
124− initReq <- parseRequest (URI.escapeURIString URI.isAllowedInURI (T.unpack tUrl))
125− let req = setRequestIgnoreStatus $ initReq { method = NHTM.methodGet }
126− Right (Object o) <- parseEsResponse =<< liftIO (httpLbs req (bhManager bhe))
127− return $ fromMaybe mempty $ do
128− Object nodes <- HM.lookup "nodes" o
129− Object firstNode <- snd <$> headMay (HM.toList nodes)
130− Object settings <- HM.lookup "settings" firstNode
131− Object path <- HM.lookup "path" settings
132− Array repo <- HM.lookup "repo" path
133− return [ T.unpack t | String t <- V.toList repo]
134−
135−-- | 1.5 and earlier don't care about repo paths
136−canSnapshot :: IO Bool
137−canSnapshot = do
138− caresAboutRepos <- atleast es16
139− repoPaths <- getRepoPaths
140− return (not caresAboutRepos || not (null (repoPaths)))
141−
142−atleast :: Vers.Version -> IO Bool
143−atleast v = getServerVersion >>= \x -> return $ x >= Just v
144−
145−atmost :: Vers.Version -> IO Bool
146−atmost v = getServerVersion >>= \x -> return $ x <= Just v
147−
148−is :: Vers.Version -> IO Bool
149−is v = getServerVersion >>= \x -> return $ x == Just v
150−
151−when' :: Monad m => m Bool -> m () -> m ()
152−when' b f = b >>= \x -> when x f
153−
154−(==~) :: (ApproxEq a) => a -> a -> Property
155−a ==~ b = counterexample (showApproxEq a ++ " !=~ " ++ showApproxEq b) (a =~ b)
156−
157−propJSON :: forall a. (Arbitrary a, ToJSON a, FromJSON a, Show a, ApproxEq a, Typeable a) => Proxy a -> Spec
158−propJSON _ = prop testName $ \(a :: a) ->
159− let jsonStr = "via " <> BL8.unpack (encode a)
160− in counterexample jsonStr (parseEither parseJSON (toJSON a) ==~ Right a)
161− where testName = show ty <> " FromJSON/ToJSON roundtrips"
162− ty = typeOf (undefined :: a)
163−
164−data Location = Location { lat :: Double
165− , lon :: Double } deriving (Eq, Generic, Show)
166−
167−data Tweet = Tweet { user :: Text
168− , postDate :: UTCTime
169− , message :: Text
170− , age :: Int
171− , location :: Location
172− , extra :: Maybe Text }
173− deriving (Eq, Generic, Show)
174−
175−instance ToJSON Tweet where
176− toJSON = genericToJSON defaultOptions
177−instance FromJSON Tweet where
178− parseJSON = genericParseJSON defaultOptions
179−instance ToJSON Location where
180− toJSON = genericToJSON defaultOptions
181−instance FromJSON Location where
182− parseJSON = genericParseJSON defaultOptions
183−
184−data ParentMapping = ParentMapping deriving (Eq, Show)
185−
186−instance ToJSON ParentMapping where
187− toJSON ParentMapping =
188− object ["properties" .=
189− object [ "user" .= object ["type" .= ("string" :: Text)]
190− -- Serializing the date as a date is breaking other tests, mysteriously.
191− -- , "postDate" .= object [ "type" .= ("date" :: Text)
192− -- , "format" .= ("YYYY-MM-dd`T`HH:mm:ss.SSSZZ" :: Text)]
193− , "message" .= object ["type" .= ("string" :: Text)]
194− , "age" .= object ["type" .= ("integer" :: Text)]
195− , "location" .= object ["type" .= ("geo_point" :: Text)]
196− ]]
197−
198−data ChildMapping = ChildMapping deriving (Eq, Show)
199−
200−instance ToJSON ChildMapping where
201− toJSON ChildMapping =
202− object ["_parent" .= object ["type" .= ("parent" :: Text)]
203− , "properties" .=
204− object [ "user" .= object ["type" .= ("string" :: Text)]
205− -- Serializing the date as a date is breaking other tests, mysteriously.
206− -- , "postDate" .= object [ "type" .= ("date" :: Text)
207− -- , "format" .= ("YYYY-MM-dd`T`HH:mm:ss.SSSZZ" :: Text)]
208− , "message" .= object ["type" .= ("string" :: Text)]
209− , "age" .= object ["type" .= ("integer" :: Text)]
210− , "location" .= object ["type" .= ("geo_point" :: Text)]
211− ]]
212−
213−data TweetMapping = TweetMapping deriving (Eq, Show)
214−
215−instance ToJSON TweetMapping where
216− toJSON TweetMapping =
217− object ["properties" .=
218− object [ "user" .= object ["type" .= ("string" :: Text)]
219− -- Serializing the date as a date is breaking other tests, mysteriously.
220− -- , "postDate" .= object [ "type" .= ("date" :: Text)
221− -- , "format" .= ("YYYY-MM-dd`T`HH:mm:ss.SSSZZ" :: Text)]
222− , "message" .= object ["type" .= ("string" :: Text)]
223− , "age" .= object ["type" .= ("integer" :: Text)]
224− , "location" .= object ["type" .= ("geo_point" :: Text)]
225− ]]
226−
227−exampleTweet :: Tweet
228−exampleTweet = Tweet { user = "bitemyapp"
229− , postDate = UTCTime
230− (ModifiedJulianDay 55000)
231− (secondsToDiffTime 10)
232− , message = "Use haskell!"
233− , age = 10000
234− , location = Location 40.12 (-71.34)
235− , extra = Nothing }
236−
237−tweetWithExtra :: Tweet
238−tweetWithExtra = Tweet { user = "bitemyapp"
239− , postDate = UTCTime
240− (ModifiedJulianDay 55000)
241− (secondsToDiffTime 10)
242− , message = "Use haskell!"
243− , age = 10000
244− , location = Location 40.12 (-71.34)
245− , extra = Just "blah blah" }
246−
247−newAge :: Int
248−newAge = 31337
249−
250−newUser :: Text
251−newUser = "someotherapp"
252−
253−tweetPatch :: Value
254−tweetPatch =
255− object [ "age" .= newAge
256− , "user" .= newUser
257− ]
258−
259−patchedTweet :: Tweet
260−patchedTweet = exampleTweet{age = newAge, user = newUser}
261−
262−otherTweet :: Tweet
263−otherTweet = Tweet { user = "notmyapp"
264− , postDate = UTCTime
265− (ModifiedJulianDay 55000)
266− (secondsToDiffTime 11)
267− , message = "Use haskell!"
268− , age = 1000
269− , location = Location 40.12 (-71.34)
270− , extra = Nothing }
271−
272−resetIndex :: BH IO ()
273−resetIndex = do
274− _ <- deleteExampleIndex
275− _ <- createExampleIndex
276− _ <- putMapping testIndex testMapping TweetMapping
277− return ()
278−
279−insertData :: BH IO Reply
280−insertData = do
281− resetIndex
282− insertData' defaultIndexDocumentSettings
283−
284−insertData' :: IndexDocumentSettings -> BH IO Reply
285−insertData' ids = do
286− r <- indexDocument testIndex testMapping ids exampleTweet (DocId "1")
287− _ <- refreshIndex testIndex
288− return r
289−
290−updateData :: BH IO Reply
291−updateData = do
292− r <- updateDocument testIndex testMapping defaultIndexDocumentSettings tweetPatch (DocId "1")
293− _ <- refreshIndex testIndex
294− return r
295−
296−insertOther :: BH IO ()
297−insertOther = do
298− _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings otherTweet (DocId "2")
299− _ <- refreshIndex testIndex
300− return ()
301−
302−insertExtra :: BH IO ()
303−insertExtra = do
304− _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings tweetWithExtra (DocId "4")
305− _ <- refreshIndex testIndex
306− return ()
307−
308−insertWithSpaceInId :: BH IO ()
309−insertWithSpaceInId = do
310− _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings exampleTweet (DocId "Hello World")
311− _ <- refreshIndex testIndex
312− return ()
313−
314−searchTweet :: Search -> BH IO (Either EsError Tweet)
315−searchTweet search = do
316− result <- searchTweets search
317− let myTweet :: Either EsError Tweet
318− myTweet = grabFirst result
319− return myTweet
320−
321−searchTweets :: Search -> BH IO (Either EsError (SearchResult Tweet))
322−searchTweets search = parseEsResponse =<< searchByIndex testIndex search
323−
324−searchExpectNoResults :: Search -> BH IO ()
325−searchExpectNoResults search = do
326− result <- searchTweets search
327− let emptyHits = fmap (hits . searchHits) result
328− liftIO $
329− emptyHits `shouldBe` Right []
330−
331−searchExpectAggs :: Search -> BH IO ()
332−searchExpectAggs search = do
333− reply <- searchByIndex testIndex search
334− let isEmpty x = return (M.null x)
335− let result = decode (responseBody reply) :: Maybe (SearchResult Tweet)
336− liftIO $
337− (result >>= aggregations >>= isEmpty) `shouldBe` Just False
338−
339−searchValidBucketAgg :: (BucketAggregation a, FromJSON a, Show a) =>
340− Search -> Text -> (Text -> AggregationResults -> Maybe (Bucket a)) -> BH IO ()
341−searchValidBucketAgg search aggKey extractor = do
342− reply <- searchByIndex testIndex search
343− let bucketDocs = docCount . head . buckets
344− let result = decode (responseBody reply) :: Maybe (SearchResult Tweet)
345− let count = result >>= aggregations >>= extractor aggKey >>= \x -> return (bucketDocs x)
346− liftIO $
347− count `shouldBe` Just 1
348−
349−searchTermsAggHint :: [ExecutionHint] -> BH IO ()
350−searchTermsAggHint hints = do
351− let terms hint = TermsAgg $ (mkTermsAggregation "user") { termExecutionHint = Just hint }
352− let search hint = mkAggregateSearch Nothing $ mkAggregations "users" $ terms hint
353− forM_ hints $ searchExpectAggs . search
354− forM_ hints (\x -> searchValidBucketAgg (search x) "users" toTerms)
355−
356−searchTweetHighlight :: Search -> BH IO (Either EsError (Maybe HitHighlight))
357−searchTweetHighlight search = do
358− result <- searchTweets search
359− let myHighlight = fmap (hitHighlight . head . hits . searchHits) result
360− return myHighlight
361−
362−searchExpectSource :: Source -> Either EsError Value -> BH IO ()
363−searchExpectSource src expected = do
364− _ <- insertData
365− let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
366− let search = (mkSearch (Just query) Nothing) { source = Just src }
367− reply <- searchByIndex testIndex search
368− result <- parseEsResponse reply
369− let value = grabFirst result
370− liftIO $
371− value `shouldBe` expected
372−
373−withSnapshotRepo
374− :: ( MonadMask m
375− , MonadBH m
376− )
377− => SnapshotRepoName
378− -> (GenericSnapshotRepo -> m a)
379− -> m a
380−withSnapshotRepo srn@(SnapshotRepoName n) f = do
381− repoPaths <- liftIO getRepoPaths
382− -- we'll use the first repo path if available, otherwise system temp
383− -- dir. Note that this will fail on ES > 1.6, so be sure you use
384− -- @when' canSnapshot@.
385− case repoPaths of
386− (firstRepoPath:_) -> withTempDirectory firstRepoPath (T.unpack n) $ \dir -> bracket (alloc dir) free f
387− [] -> withSystemTempDirectory (T.unpack n) $ \dir -> bracket (alloc dir) free f
388− where
389− alloc dir = do
390− liftIO (setFileMode dir mode)
391− let repo = FsSnapshotRepo srn "bloodhound-tests-backups" True Nothing Nothing Nothing
392− resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings repo
393− liftIO (validateStatus resp 200)
394− return (toGSnapshotRepo repo)
395− mode = ownerModes `unionFileModes` groupModes `unionFileModes` otherModes
396− free GenericSnapshotRepo {..} = do
397− resp <- deleteSnapshotRepo gSnapshotRepoName
398− liftIO (validateStatus resp 200)
399−
400−
401−withSnapshot
402− :: ( MonadMask m
403− , MonadBH m
404− )
405− => SnapshotRepoName
406− -> SnapshotName
407− -> m a
408− -> m a
409−withSnapshot srn sn = bracket_ alloc free
410− where
411− alloc = do
412− resp <- createSnapshot srn sn createSettings
413− liftIO (validateStatus resp 200)
414− -- We'll make this synchronous for testing purposes
415− createSettings = defaultSnapshotCreateSettings { snapWaitForCompletion = True
416− , snapIndices = Just (IndexList (testIndex :| []))
417− -- We don't actually need to back up any data
418− }
419− free = do
420− deleteSnapshot srn sn
421−
422−
423−
424−data BulkTest = BulkTest { name :: Text } deriving (Eq, Generic, Show)
425−instance FromJSON BulkTest where
426− parseJSON = genericParseJSON defaultOptions
427−instance ToJSON BulkTest where
428− toJSON = genericToJSON defaultOptions
429−
430−class GApproxEq f where
431− gApproxEq :: f a -> f a -> Bool
432−
433−-- | Unit type
434−instance GApproxEq U1 where
435− gApproxEq U1 U1 = True
436−
437−-- | Sum type, ensure same constructors, recurse
438−instance (GApproxEq a, GApproxEq b) => GApproxEq (a :+: b) where
439− gApproxEq (L1 a) (L1 b) = gApproxEq a b
440− gApproxEq (R1 a) (R1 b) = gApproxEq a b
441− gApproxEq _ _ = False
442−
443−-- | Product type, ensure each field is approx eq
444−instance (GApproxEq a, GApproxEq b) => GApproxEq (a :*: b) where
445− gApproxEq (a1 :*: b1) (a2 :*: b2) = gApproxEq a1 a2 && gApproxEq b1 b2
446−
447−-- | Value type, actually check the values for approx equality
448−instance (ApproxEq a) => GApproxEq (K1 i a) where
449− gApproxEq (K1 a) (K1 b) = a =~ b
450−
451−instance (GApproxEq f) => GApproxEq (M1 i t f) where
452− gApproxEq (M1 a) (M1 b) = gApproxEq a b
453−
454−-- | Typeclass for "equal where it matters". Use this to specify
455−-- less-strict equivalence for things such as lists that can wind up
456−-- in an unpredictable order
457−class ApproxEq a where
458− (=~) :: a -> a -> Bool
459− default (=~) :: (Generic a, GApproxEq (Rep a)) => a -> a -> Bool
460− a =~ b = gApproxEq (G.from a) (G.from b)
461−
462− showApproxEq :: a -> String
463− default showApproxEq :: (Show a) => a -> String
464− showApproxEq = show
465−
466−instance ApproxEq NominalDiffTime where (=~) = (==)
467−instance ApproxEq UTCTime where (=~) = (==)
468−instance ApproxEq Text where (=~) = (==)
469−instance ApproxEq Bool where (=~) = (==)
470−instance ApproxEq Int where (=~) = (==)
471−instance ApproxEq Double where (=~) = (==)
472−instance (ApproxEq a, Show a) => ApproxEq (NonEmpty a)
473−instance (ApproxEq a, Show a) => ApproxEq (Maybe a)
474−instance ApproxEq GeoPoint
475−instance ApproxEq Regexp
476−instance ApproxEq RangeValue
477−instance ApproxEq LessThan
478−instance ApproxEq LessThanEq
479−instance ApproxEq LessThanD
480−instance ApproxEq LessThanEqD
481−instance ApproxEq GreaterThan
482−instance ApproxEq GreaterThanEq
483−instance ApproxEq GreaterThanD
484−instance ApproxEq GreaterThanEqD
485−instance ApproxEq MinimumMatchHighLow
486−instance ApproxEq RegexpFlag
487−instance ApproxEq RegexpFlags
488−instance ApproxEq NullValue
489−instance ApproxEq Version
490−instance ApproxEq VersionNumber
491−instance ApproxEq DistanceRange
492−instance ApproxEq IndexName
493−instance ApproxEq MappingName
494−instance ApproxEq DocId
495−instance ApproxEq IndexAliasRouting
496−instance ApproxEq RoutingValue
497−instance ApproxEq ShardCount
498−instance ApproxEq ReplicaCount
499−instance ApproxEq TemplateName
500−instance ApproxEq TemplatePattern
501−instance ApproxEq QueryString
502−instance ApproxEq FieldName
503−instance ApproxEq CacheName
504−instance ApproxEq CacheKey
505−instance ApproxEq Existence
506−instance ApproxEq CutoffFrequency
507−instance ApproxEq Analyzer
508−instance ApproxEq Lenient
509−instance ApproxEq Tiebreaker
510−instance ApproxEq Boost
511−instance ApproxEq BoostTerms
512−instance ApproxEq MaxExpansions
513−instance ApproxEq MinimumMatch
514−instance ApproxEq DisableCoord
515−instance ApproxEq IgnoreTermFrequency
516−instance ApproxEq MinimumTermFrequency
517−instance ApproxEq MaxQueryTerms
518−instance ApproxEq Fuzziness
519−instance ApproxEq PrefixLength
520−instance ApproxEq TypeName
521−instance ApproxEq PercentMatch
522−instance ApproxEq StopWord
523−instance ApproxEq QueryPath
524−instance ApproxEq AllowLeadingWildcard
525−instance ApproxEq LowercaseExpanded
526−instance ApproxEq EnablePositionIncrements
527−instance ApproxEq AnalyzeWildcard
528−instance ApproxEq GeneratePhraseQueries
529−instance ApproxEq Locale
530−instance ApproxEq MaxWordLength
531−instance ApproxEq MinWordLength
532−instance ApproxEq PhraseSlop
533−instance ApproxEq MinDocFrequency
534−instance ApproxEq MaxDocFrequency
535−instance ApproxEq Filter
536−instance ApproxEq Query
537−instance ApproxEq SimpleQueryStringQuery
538−instance ApproxEq FieldOrFields
539−instance ApproxEq SimpleQueryFlag
540−instance ApproxEq RegexpQuery
541−instance ApproxEq QueryStringQuery
542−instance ApproxEq RangeQuery
543−instance ApproxEq PrefixQuery
544−instance ApproxEq NestedQuery
545−instance ApproxEq MoreLikeThisFieldQuery
546−instance ApproxEq MoreLikeThisQuery
547−instance ApproxEq IndicesQuery
548−instance ApproxEq HasParentQuery
549−instance ApproxEq HasChildQuery
550−instance ApproxEq FuzzyQuery
551−instance ApproxEq FuzzyLikeFieldQuery
552−instance ApproxEq FuzzyLikeThisQuery
553−instance ApproxEq FilteredQuery
554−instance ApproxEq DisMaxQuery
555−instance ApproxEq CommonTermsQuery
556−instance ApproxEq CommonMinimumMatch
557−instance ApproxEq BoostingQuery
558−instance ApproxEq BoolQuery
559−instance ApproxEq MatchQuery
560−instance ApproxEq MultiMatchQueryType
561−instance ApproxEq BooleanOperator
562−instance ApproxEq ZeroTermsQuery
563−instance ApproxEq MatchQueryType
564−instance ApproxEq AliasRouting
565−instance ApproxEq IndexAliasCreate
566−instance ApproxEq SearchAliasRouting
567−instance ApproxEq ScoreType
568−instance ApproxEq Distance
569−instance ApproxEq DistanceUnit
570−instance ApproxEq DistanceType
571−instance ApproxEq OptimizeBbox
572−instance ApproxEq GeoBoundingBoxConstraint
573−instance ApproxEq GeoFilterType
574−instance ApproxEq GeoBoundingBox
575−instance ApproxEq LatLon
576−instance ApproxEq RangeExecution
577−instance ApproxEq FSType
578−instance ApproxEq CompoundFormat
579−instance ApproxEq InitialShardCount
580−instance ApproxEq Bytes
581−instance ApproxEq ReplicaBounds
582−instance ApproxEq Term
583−instance ApproxEq BoolMatch
584−instance ApproxEq MultiMatchQuery
585−instance ApproxEq IndexSettings
586−instance ApproxEq AllocationPolicy
587−instance ApproxEq Char where
588− (=~) = (==)
589−instance ApproxEq Vers.Version where
590− (=~) = (==)
591−instance (ApproxEq a, Show a) => ApproxEq [a] where
592− as =~ bs = and (zipWith (=~) as bs)
593−instance (ApproxEq l, ApproxEq r) => ApproxEq (Either l r) where
594− Left a =~ Left b = a =~ b
595− Right a =~ Right b = a =~ b
596− _ =~ _ = False
597− showApproxEq (Left x) = "Left " <> showApproxEq x
598− showApproxEq (Right x) = "Right " <> showApproxEq x
599−instance ApproxEq NodeAttrFilter
600−instance ApproxEq NodeAttrName
601−instance ApproxEq BuildHash
602−instance ApproxEq TemplateQueryKeyValuePairs where
603− (=~) = (==)
604−instance ApproxEq TemplateQueryInline
605−instance ApproxEq Size
606−instance ApproxEq PhraseSuggesterHighlighter
607−instance ApproxEq PhraseSuggesterCollate
608−instance ApproxEq PhraseSuggester
609−instance ApproxEq SuggestType
610−instance ApproxEq Suggest
611−instance ApproxEq DirectGenerators
612−instance ApproxEq DirectGeneratorSuggestModeTypes
613−
614−-- | Due to the way nodeattrfilters get serialized here, they may come
615−-- out in a different order, but they are morally equivalent
616−instance ApproxEq UpdatableIndexSetting where
617− RoutingAllocationInclude a =~ RoutingAllocationInclude b =
618− NE.sort a =~ NE.sort b
619− RoutingAllocationExclude a =~ RoutingAllocationExclude b =
620− NE.sort a =~ NE.sort b
621− RoutingAllocationRequire a =~ RoutingAllocationRequire b =
622− NE.sort a =~ NE.sort b
623− a =~ b = a == b
624− showApproxEq (RoutingAllocationInclude xs) = show (RoutingAllocationInclude (NE.sort xs))
625− showApproxEq (RoutingAllocationExclude xs) = show (RoutingAllocationExclude (NE.sort xs))
626− showApproxEq (RoutingAllocationRequire xs) = show (RoutingAllocationRequire (NE.sort xs))
627− showApproxEq x = show x
628
18
19+import Prelude
629
20
630−noDuplicates :: Eq a => [a] -> Bool
21+import qualified Test.Aggregation as Aggregation
631−noDuplicates xs = nub xs == xs
22+import qualified Test.BulkAPI as Bulk
632−
23+import qualified Test.Documents as Documents
633−instance Arbitrary NominalDiffTime where
24+import qualified Test.Highlights as Highlights
634− arbitrary = fromInteger <$> arbitrary
25+import qualified Test.Indices as Indices
635−
26+import qualified Test.JSON as JSON
636−#if !MIN_VERSION_QuickCheck(2,8,0)
27+import qualified Test.Query as Query
637−instance (Arbitrary k, Ord k, Arbitrary v) => Arbitrary (M.Map k v) where
28+import qualified Test.Snapshots as Snapshots
638− arbitrary = M.fromList <$> arbitrary
29+import qualified Test.Sorting as Sorting
639−#endif
30+import qualified Test.SourceFiltering as SourceFiltering
640−
31+import qualified Test.Suggest as Suggest
641−instance Arbitrary Text where
32+import qualified Test.Templates as Templates
642− arbitrary = T.pack <$> arbitrary
643−
644−instance Arbitrary UTCTime where
645− arbitrary = UTCTime
646− <$> arbitrary
647− <*> (fromRational . toRational <$> choose (0::Double, 86400))
648−
649−instance Arbitrary Day where
650− arbitrary = ModifiedJulianDay <$> (2000 +) <$> arbitrary
651− shrink = (ModifiedJulianDay <$>) . shrink . toModifiedJulianDay
652−
653−#if !MIN_VERSION_QuickCheck(2,9,0)
654−instance Arbitrary a => Arbitrary (NonEmpty a) where
655− arbitrary = liftA2 (:|) arbitrary arbitrary
656−#endif
657−
658−arbitraryScore :: Gen Score
659−arbitraryScore = fmap getPositive <$> arbitrary
660−
661−instance (Arbitrary a, Typeable a) => Arbitrary (Hit a) where
662− arbitrary = Hit <$> arbitrary
663− <*> arbitrary
664− <*> arbitrary
665− <*> arbitraryScore
666− <*> arbitrary
667− <*> arbitrary
668− shrink = genericShrink
669−
670−
671−instance (Arbitrary a, Typeable a) => Arbitrary (SearchHits a) where
672− arbitrary = reduceSize $ do
673− tot <- getPositive <$> arbitrary
674− score <- arbitraryScore
675− hs <- arbitrary
676− return $ SearchHits tot score hs
677− shrink = genericShrink
678−
679−reduceSize :: Gen a -> Gen a
680−reduceSize f = sized $ \n -> resize (n `div` 2) f
681−
682−getSource :: EsResult a -> Maybe a
683−getSource = fmap _source . foundResult
684−
685−grabFirst :: Either EsError (SearchResult a) -> Either EsError a
686−grabFirst r =
687− case fmap (hitSource . head . hits . searchHits) r of
688− (Left e) -> Left e
689− (Right Nothing) -> Left (EsError 500 "Source was missing")
690− (Right (Just x)) -> Right x
691−
692−-------------------------------------------------------------------------------
693−arbitraryAlphaNum :: Gen Char
694−arbitraryAlphaNum = oneof [choose ('a', 'z')
695− ,choose ('A','Z')
696− , choose ('0', '9')]
697−
698−instance Arbitrary RoutingValue where
699− arbitrary = RoutingValue . T.pack <$> listOf1 arbitraryAlphaNum
700−
701−instance Arbitrary AliasRouting where
702− arbitrary = oneof [allAlias
703− ,one
704− ,theOther
705− ,both]
706− where one = GranularAliasRouting
707− <$> (Just <$> arbitrary)
708− <*> pure Nothing
709− theOther = GranularAliasRouting Nothing
710− <$> (Just <$> arbitrary)
711− both = GranularAliasRouting
712− <$> (Just <$> arbitrary)
713− <*> (Just <$> arbitrary)
714− allAlias = AllAliasRouting <$> arbitrary
715− shrink = genericShrink
716−
717−
718−instance Arbitrary FieldName where
719− arbitrary = FieldName . T.pack <$> listOf1 arbitraryAlphaNum
720− shrink = genericShrink
721−
722−
723−#if MIN_VERSION_base(4,10,0)
724−-- Test.QuickCheck.Modifiers
725−
726−qcNonEmptyToNonEmpty :: NonEmptyList a -> NonEmpty a
727−qcNonEmptyToNonEmpty (NonEmpty (a : xs)) = (a :| xs)
728−qcNonEmptyToNonEmpty (NonEmpty []) = error "NonEmpty was empty!"
729−
730−instance Arbitrary a => Arbitrary (NonEmpty a) where
731− arbitrary = qcNonEmptyToNonEmpty <$> arbitrary
732−#endif
733−
734−instance Arbitrary RegexpFlags where
735− arbitrary = oneof [ pure AllRegexpFlags
736− , pure NoRegexpFlags
737− , SomeRegexpFlags <$> genUniqueFlags
738− ]
739− where genUniqueFlags = NE.fromList . nub <$> listOf1 arbitrary
740− shrink = genericShrink
741−
742−
743−instance Arbitrary IndexAliasCreate where
744− arbitrary = IndexAliasCreate <$> arbitrary <*> reduceSize arbitrary
745− shrink = genericShrink
746−
747−instance Arbitrary Query where
748− arbitrary = reduceSize $ oneof [ TermQuery <$> arbitrary <*> arbitrary
749− , TermsQuery <$> arbitrary <*> arbitrary
750− , QueryMatchQuery <$> arbitrary
751− , QueryMultiMatchQuery <$> arbitrary
752− , QueryBoolQuery <$> arbitrary
753− , QueryBoostingQuery <$> arbitrary
754− , QueryCommonTermsQuery <$> arbitrary
755− , ConstantScoreFilter <$> arbitrary <*> arbitrary
756− , ConstantScoreQuery <$> arbitrary <*> arbitrary
757− , QueryDisMaxQuery <$> arbitrary
758− , QueryFilteredQuery <$> arbitrary
759− , QueryFuzzyLikeThisQuery <$> arbitrary
760− , QueryFuzzyLikeFieldQuery <$> arbitrary
761− , QueryFuzzyQuery <$> arbitrary
762− , QueryHasChildQuery <$> arbitrary
763− , QueryHasParentQuery <$> arbitrary
764− , IdsQuery <$> arbitrary <*> arbitrary
765− , QueryIndicesQuery <$> arbitrary
766− , MatchAllQuery <$> arbitrary
767− , QueryMoreLikeThisQuery <$> arbitrary
768− , QueryMoreLikeThisFieldQuery <$> arbitrary
769− , QueryNestedQuery <$> arbitrary
770− , QueryPrefixQuery <$> arbitrary
771− , QueryQueryStringQuery <$> arbitrary
772− , QuerySimpleQueryStringQuery <$> arbitrary
773− , QueryRangeQuery <$> arbitrary
774− , QueryRegexpQuery <$> arbitrary
775− , QueryTemplateQueryInline <$> arbitrary
776− ]
777− shrink = genericShrink
778−
779−instance Arbitrary Filter where
780− arbitrary = reduceSize $ oneof [ AndFilter <$> arbitrary <*> arbitrary
781− , OrFilter <$> arbitrary <*> arbitrary
782− , NotFilter <$> arbitrary <*> arbitrary
783− , pure IdentityFilter
784− , BoolFilter <$> arbitrary
785− , ExistsFilter <$> arbitrary
786− , GeoBoundingBoxFilter <$> arbitrary
787− , GeoDistanceFilter <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
788− , GeoDistanceRangeFilter <$> arbitrary <*> arbitrary
789− , GeoPolygonFilter <$> arbitrary <*> arbitrary
790− , IdsFilter <$> arbitrary <*> arbitrary
791− , LimitFilter <$> arbitrary
792− , MissingFilter <$> arbitrary <*> arbitrary <*> arbitrary
793− , PrefixFilter <$> arbitrary <*> arbitrary <*> arbitrary
794− , QueryFilter <$> arbitrary <*> arbitrary
795− , RangeFilter <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
796− , RegexpFilter <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
797− , TermFilter <$> arbitrary <*> arbitrary]
798− shrink = genericShrink
799−
800−instance Arbitrary ReplicaBounds where
801− arbitrary = oneof [ replicasBounded
802− , replicasLowerBounded
803− , pure ReplicasUnbounded
804− ]
805− where replicasBounded = do Positive a <- arbitrary
806− Positive b <- arbitrary
807− return (ReplicasBounded a b)
808− replicasLowerBounded = do Positive a <- arbitrary
809− return (ReplicasLowerBounded a)
810−
811−instance Arbitrary NodeAttrName where
812− arbitrary = NodeAttrName . T.pack <$> listOf1 arbitraryAlphaNum
813−
814−
815−instance Arbitrary NodeAttrFilter where
816− arbitrary = do
817− n <- arbitrary
818− s:ss <- listOf1 (listOf1 arbitraryAlphaNum)
819− let ts = T.pack <$> s :| ss
820− return (NodeAttrFilter n ts)
821− shrink = genericShrink
822−
823−instance Arbitrary VersionNumber where
824− arbitrary = mk . fmap getPositive . getNonEmpty <$> arbitrary
825− where
826− mk versions = VersionNumber (Vers.Version versions [])
827−
828−instance Arbitrary TemplateQueryKeyValuePairs where
829− arbitrary = TemplateQueryKeyValuePairs . HM.fromList <$> arbitrary
830− shrink (TemplateQueryKeyValuePairs x) = map (TemplateQueryKeyValuePairs . HM.fromList) . shrink $ HM.toList x
831−
832−instance Arbitrary IndexName where arbitrary = sopArbitrary; shrink = genericShrink
833−instance Arbitrary MappingName where arbitrary = sopArbitrary; shrink = genericShrink
834−instance Arbitrary DocId where arbitrary = sopArbitrary; shrink = genericShrink
835−instance Arbitrary Version where arbitrary = sopArbitrary; shrink = genericShrink
836−instance Arbitrary BuildHash where arbitrary = sopArbitrary; shrink = genericShrink
837−instance Arbitrary IndexAliasRouting where arbitrary = sopArbitrary; shrink = genericShrink
838−instance Arbitrary ShardCount where arbitrary = sopArbitrary; shrink = genericShrink
839−instance Arbitrary ReplicaCount where arbitrary = sopArbitrary; shrink = genericShrink
840−instance Arbitrary TemplateName where arbitrary = sopArbitrary; shrink = genericShrink
841−instance Arbitrary TemplatePattern where arbitrary = sopArbitrary; shrink = genericShrink
842−instance Arbitrary QueryString where arbitrary = sopArbitrary; shrink = genericShrink
843−instance Arbitrary CacheName where arbitrary = sopArbitrary; shrink = genericShrink
844−instance Arbitrary CacheKey where arbitrary = sopArbitrary; shrink = genericShrink
845−instance Arbitrary Existence where arbitrary = sopArbitrary; shrink = genericShrink
846−instance Arbitrary CutoffFrequency where arbitrary = sopArbitrary; shrink = genericShrink
847−instance Arbitrary Analyzer where arbitrary = sopArbitrary; shrink = genericShrink
848−instance Arbitrary MaxExpansions where arbitrary = sopArbitrary; shrink = genericShrink
849−instance Arbitrary Lenient where arbitrary = sopArbitrary; shrink = genericShrink
850−instance Arbitrary Tiebreaker where arbitrary = sopArbitrary; shrink = genericShrink
851−instance Arbitrary Boost where arbitrary = sopArbitrary; shrink = genericShrink
852−instance Arbitrary BoostTerms where arbitrary = sopArbitrary; shrink = genericShrink
853−instance Arbitrary MinimumMatch where arbitrary = sopArbitrary; shrink = genericShrink
854−instance Arbitrary DisableCoord where arbitrary = sopArbitrary; shrink = genericShrink
855−instance Arbitrary IgnoreTermFrequency where arbitrary = sopArbitrary; shrink = genericShrink
856−instance Arbitrary MinimumTermFrequency where arbitrary = sopArbitrary; shrink = genericShrink
857−instance Arbitrary MaxQueryTerms where arbitrary = sopArbitrary; shrink = genericShrink
858−instance Arbitrary Fuzziness where arbitrary = sopArbitrary; shrink = genericShrink
859−instance Arbitrary PrefixLength where arbitrary = sopArbitrary; shrink = genericShrink
860−instance Arbitrary TypeName where arbitrary = sopArbitrary; shrink = genericShrink
861−instance Arbitrary PercentMatch where arbitrary = sopArbitrary; shrink = genericShrink
862−instance Arbitrary StopWord where arbitrary = sopArbitrary; shrink = genericShrink
863−instance Arbitrary QueryPath where arbitrary = sopArbitrary; shrink = genericShrink
864−instance Arbitrary AllowLeadingWildcard where arbitrary = sopArbitrary; shrink = genericShrink
865−instance Arbitrary LowercaseExpanded where arbitrary = sopArbitrary; shrink = genericShrink
866−instance Arbitrary EnablePositionIncrements where arbitrary = sopArbitrary; shrink = genericShrink
867−instance Arbitrary AnalyzeWildcard where arbitrary = sopArbitrary; shrink = genericShrink
868−instance Arbitrary GeneratePhraseQueries where arbitrary = sopArbitrary; shrink = genericShrink
869−instance Arbitrary Locale where arbitrary = sopArbitrary; shrink = genericShrink
870−instance Arbitrary MaxWordLength where arbitrary = sopArbitrary; shrink = genericShrink
871−instance Arbitrary MinWordLength where arbitrary = sopArbitrary; shrink = genericShrink
872−instance Arbitrary PhraseSlop where arbitrary = sopArbitrary; shrink = genericShrink
873−instance Arbitrary MinDocFrequency where arbitrary = sopArbitrary; shrink = genericShrink
874−instance Arbitrary MaxDocFrequency where arbitrary = sopArbitrary; shrink = genericShrink
875−instance Arbitrary Regexp where arbitrary = sopArbitrary; shrink = genericShrink
876−instance Arbitrary SimpleQueryStringQuery where arbitrary = sopArbitrary; shrink = genericShrink
877−instance Arbitrary FieldOrFields where arbitrary = sopArbitrary; shrink = genericShrink
878−instance Arbitrary SimpleQueryFlag where arbitrary = sopArbitrary; shrink = genericShrink
879−instance Arbitrary RegexpQuery where arbitrary = sopArbitrary; shrink = genericShrink
880−instance Arbitrary QueryStringQuery where arbitrary = sopArbitrary; shrink = genericShrink
881−instance Arbitrary RangeQuery where arbitrary = sopArbitrary; shrink = genericShrink
882−instance Arbitrary RangeValue where arbitrary = sopArbitrary; shrink = genericShrink
883−instance Arbitrary PrefixQuery where arbitrary = sopArbitrary; shrink = genericShrink
884−instance Arbitrary NestedQuery where arbitrary = sopArbitrary; shrink = genericShrink
885−instance Arbitrary MoreLikeThisFieldQuery where arbitrary = sopArbitrary; shrink = genericShrink
886−instance Arbitrary MoreLikeThisQuery where arbitrary = sopArbitrary; shrink = genericShrink
887−instance Arbitrary IndicesQuery where arbitrary = sopArbitrary; shrink = genericShrink
888−instance Arbitrary HasParentQuery where arbitrary = sopArbitrary; shrink = genericShrink
889−instance Arbitrary HasChildQuery where arbitrary = sopArbitrary; shrink = genericShrink
890−instance Arbitrary FuzzyQuery where arbitrary = sopArbitrary; shrink = genericShrink
891−instance Arbitrary FuzzyLikeFieldQuery where arbitrary = sopArbitrary; shrink = genericShrink
892−instance Arbitrary FuzzyLikeThisQuery where arbitrary = sopArbitrary; shrink = genericShrink
893−instance Arbitrary FilteredQuery where arbitrary = sopArbitrary; shrink = genericShrink
894−instance Arbitrary DisMaxQuery where arbitrary = sopArbitrary; shrink = genericShrink
895−instance Arbitrary CommonTermsQuery where arbitrary = sopArbitrary; shrink = genericShrink
896−instance Arbitrary DistanceRange where arbitrary = sopArbitrary; shrink = genericShrink
897−instance Arbitrary MultiMatchQuery where arbitrary = sopArbitrary; shrink = genericShrink
898−instance Arbitrary LessThanD where arbitrary = sopArbitrary; shrink = genericShrink
899−instance Arbitrary LessThanEqD where arbitrary = sopArbitrary; shrink = genericShrink
900−instance Arbitrary GreaterThanD where arbitrary = sopArbitrary; shrink = genericShrink
901−instance Arbitrary GreaterThanEqD where arbitrary = sopArbitrary; shrink = genericShrink
902−instance Arbitrary LessThan where arbitrary = sopArbitrary; shrink = genericShrink
903−instance Arbitrary LessThanEq where arbitrary = sopArbitrary; shrink = genericShrink
904−instance Arbitrary GreaterThan where arbitrary = sopArbitrary; shrink = genericShrink
905−instance Arbitrary GreaterThanEq where arbitrary = sopArbitrary; shrink = genericShrink
906−instance Arbitrary GeoPoint where
907− arbitrary = GeoPoint <$> (arbitrary `suchThat` reasonableFieldName) <*> arbitrary
908− where
909− -- These are problematic for geopoint for obvious reasons
910− reasonableFieldName (FieldName "from") = False
911− reasonableFieldName (FieldName "to") = False
912− reasonableFieldName _ = True
913− shrink = genericShrink
914−instance Arbitrary NullValue where arbitrary = sopArbitrary; shrink = genericShrink
915−instance Arbitrary MinimumMatchHighLow where arbitrary = sopArbitrary; shrink = genericShrink
916−instance Arbitrary CommonMinimumMatch where arbitrary = sopArbitrary; shrink = genericShrink
917−instance Arbitrary BoostingQuery where arbitrary = sopArbitrary; shrink = genericShrink
918−instance Arbitrary BoolQuery where arbitrary = sopArbitrary; shrink = genericShrink
919−instance Arbitrary MatchQuery where arbitrary = sopArbitrary; shrink = genericShrink
920−instance Arbitrary MultiMatchQueryType where arbitrary = sopArbitrary; shrink = genericShrink
921−instance Arbitrary BooleanOperator where arbitrary = sopArbitrary; shrink = genericShrink
922−instance Arbitrary ZeroTermsQuery where arbitrary = sopArbitrary; shrink = genericShrink
923−instance Arbitrary MatchQueryType where arbitrary = sopArbitrary; shrink = genericShrink
924−instance Arbitrary SearchAliasRouting where arbitrary = sopArbitrary; shrink = genericShrink
925−instance Arbitrary ScoreType where arbitrary = sopArbitrary; shrink = genericShrink
926−instance Arbitrary Distance where arbitrary = sopArbitrary; shrink = genericShrink
927−instance Arbitrary DistanceUnit where arbitrary = sopArbitrary; shrink = genericShrink
928−instance Arbitrary DistanceType where arbitrary = sopArbitrary; shrink = genericShrink
929−instance Arbitrary OptimizeBbox where arbitrary = sopArbitrary; shrink = genericShrink
930−instance Arbitrary GeoBoundingBoxConstraint where arbitrary = sopArbitrary; shrink = genericShrink
931−instance Arbitrary GeoFilterType where arbitrary = sopArbitrary; shrink = genericShrink
932−instance Arbitrary GeoBoundingBox where arbitrary = sopArbitrary; shrink = genericShrink
933−instance Arbitrary LatLon where arbitrary = sopArbitrary; shrink = genericShrink
934−instance Arbitrary RangeExecution where arbitrary = sopArbitrary; shrink = genericShrink
935−instance Arbitrary RegexpFlag where arbitrary = sopArbitrary; shrink = genericShrink
936−instance Arbitrary BoolMatch where arbitrary = sopArbitrary; shrink = genericShrink
937−instance Arbitrary Term where arbitrary = sopArbitrary; shrink = genericShrink
938−instance Arbitrary IndexSettings where arbitrary = sopArbitrary; shrink = genericShrink
939−instance Arbitrary UpdatableIndexSetting where arbitrary = sopArbitrary; shrink = genericShrink
940−instance Arbitrary Bytes where arbitrary = sopArbitrary; shrink = genericShrink
941−instance Arbitrary AllocationPolicy where arbitrary = sopArbitrary; shrink = genericShrink
942−instance Arbitrary InitialShardCount where arbitrary = sopArbitrary; shrink = genericShrink
943−instance Arbitrary FSType where arbitrary = sopArbitrary; shrink = genericShrink
944−instance Arbitrary CompoundFormat where arbitrary = sopArbitrary; shrink = genericShrink
945−instance Arbitrary FsSnapshotRepo where arbitrary = sopArbitrary; shrink = genericShrink
946−instance Arbitrary SnapshotRepoName where arbitrary = sopArbitrary; shrink = genericShrink
947−instance Arbitrary TemplateQueryInline where arbitrary = sopArbitrary; shrink = genericShrink
948−instance Arbitrary PhraseSuggesterCollate where arbitrary = sopArbitrary; shrink = genericShrink
949−instance Arbitrary PhraseSuggesterHighlighter where arbitrary = sopArbitrary; shrink = genericShrink
950−instance Arbitrary Size where arbitrary = sopArbitrary; shrink = genericShrink
951−instance Arbitrary PhraseSuggester where arbitrary = sopArbitrary; shrink = genericShrink
952−instance Arbitrary SuggestType where arbitrary = sopArbitrary; shrink = genericShrink
953−instance Arbitrary Suggest where arbitrary = sopArbitrary; shrink = genericShrink
954−instance Arbitrary DirectGenerators where arbitrary = sopArbitrary; shrink = genericShrink
955−instance Arbitrary DirectGeneratorSuggestModeTypes where arbitrary = sopArbitrary; shrink = genericShrink
956−
957−newtype UpdatableIndexSetting' = UpdatableIndexSetting' UpdatableIndexSetting
958− deriving (Show, Eq, ToJSON, FromJSON, ApproxEq, Typeable)
959−
960−instance Arbitrary UpdatableIndexSetting' where
961− arbitrary = do
962− settings <- arbitrary
963− return $ UpdatableIndexSetting' $ case settings of
964− RoutingAllocationInclude xs -> RoutingAllocationInclude (dropDuplicateAttrNames xs)
965− RoutingAllocationExclude xs -> RoutingAllocationExclude (dropDuplicateAttrNames xs)
966− RoutingAllocationRequire xs -> RoutingAllocationRequire (dropDuplicateAttrNames xs)
967− x -> x
968− where
969− dropDuplicateAttrNames = NE.fromList . L.nubBy sameAttrName . NE.toList
970− sameAttrName a b = nodeAttrFilterName a == nodeAttrFilterName b
971
33
972main :: IO ()
34main :: IO ()
973main = hspec $ do
35main = hspec $ do
974−
36+ Aggregation.spec
975− describe "index create/delete API" $ do
37+ Bulk.spec
976− it "creates and then deletes the requested index" $ withTestEnv $ do
38+ Documents.spec
977− -- priming state.
39+ Highlights.spec
978− _ <- deleteExampleIndex
40+ Indices.spec
979− resp <- createExampleIndex
41+ JSON.spec
980− deleteResp <- deleteExampleIndex
42+ Query.spec
981− liftIO $ do
43+ Snapshots.spec
982− validateStatus resp 200
44+ Sorting.spec
983− validateStatus deleteResp 200
45+ SourceFiltering.spec
46+ Suggest.spec
47+ Templates.spec
984
48
985 describe "error parsing" $ do
49 describe "error parsing" $ do
986 it "can parse EsErrors for < 2.0" $ when' (atmost es16) $ withTestEnv $ do
50 it "can parse EsErrors for < 2.0" $ when' (atmost es16) $ withTestEnv $ do
@@ -993,619 +57,11 @@ main = hspec $ do
993 let errorResp = eitherDecode (responseBody res)
57 let errorResp = eitherDecode (responseBody res)
994 liftIO (errorResp `shouldBe` Right (EsError 404 "no such index"))
58 liftIO (errorResp `shouldBe` Right (EsError 404 "no such index"))
995
59
996− describe "document API" $ do
60+ describe "Monoid (SearchHits a)" $
997− it "indexes, updates, gets, and then deletes the generated document" $ withTestEnv $ do
998− _ <- insertData
999− _ <- updateData
1000− docInserted <- getDocument testIndex testMapping (DocId "1")
1001− let newTweet = eitherDecode
1002− (responseBody docInserted) :: Either String (EsResult Tweet)
1003− liftIO $ (fmap getSource newTweet `shouldBe` Right (Just patchedTweet))
1004−
1005− it "indexes, gets, and then deletes the generated document with a DocId containing a space" $ withTestEnv $ do
1006− _ <- insertWithSpaceInId
1007− docInserted <- getDocument testIndex testMapping (DocId "Hello World")
1008− let newTweet = eitherDecode
1009− (responseBody docInserted) :: Either String (EsResult Tweet)
1010− liftIO $ (fmap getSource newTweet `shouldBe` Right (Just exampleTweet))
1011−
1012− it "produces a parseable result when looking up a bogus document" $ withTestEnv $ do
1013− doc <- getDocument testIndex testMapping (DocId "bogus")
1014− let noTweet = eitherDecode
1015− (responseBody doc) :: Either String (EsResult Tweet)
1016− liftIO $ fmap foundResult noTweet `shouldBe` Right Nothing
1017−
1018− it "can use optimistic concurrency control" $ withTestEnv $ do
1019− let ev = ExternalDocVersion minBound
1020− let cfg = defaultIndexDocumentSettings { idsVersionControl = ExternalGT ev }
1021− resetIndex
1022− res <- insertData' cfg
1023− liftIO $ isCreated res `shouldBe` True
1024− res' <- insertData' cfg
1025− liftIO $ isVersionConflict res' `shouldBe` True
1026−
1027− it "indexes two documents in a parent/child relationship and checks that the child exists" $ withTestEnv $ do
1028− resetIndex
1029− _ <- putMapping testIndex (MappingName "child") ChildMapping
1030− _ <- putMapping testIndex (MappingName "parent") ParentMapping
1031− _ <- indexDocument testIndex (MappingName "parent") defaultIndexDocumentSettings exampleTweet (DocId "1")
1032− let parent = (Just . DocumentParent . DocId) "1"
1033− ids = IndexDocumentSettings NoVersionControl parent
1034− _ <- indexDocument testIndex (MappingName "child") ids otherTweet (DocId "2")
1035− _ <- refreshIndex testIndex
1036− exists <- documentExists testIndex (MappingName "child") parent (DocId "2")
1037− liftIO $ exists `shouldBe` True
1038−
1039− describe "template API" $ do
1040− it "can create a template" $ withTestEnv $ do
1041− let idxTpl = IndexTemplate (TemplatePattern "tweet-*") (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) [toJSON TweetMapping]
1042− resp <- putTemplate idxTpl (TemplateName "tweet-tpl")
1043− liftIO $ validateStatus resp 200
1044−
1045− it "can detect if a template exists" $ withTestEnv $ do
1046− exists <- templateExists (TemplateName "tweet-tpl")
1047− liftIO $ exists `shouldBe` True
1048−
1049− it "can delete a template" $ withTestEnv $ do
1050− resp <- deleteTemplate (TemplateName "tweet-tpl")
1051− liftIO $ validateStatus resp 200
1052−
1053− it "can detect if a template doesn't exist" $ withTestEnv $ do
1054− exists <- templateExists (TemplateName "tweet-tpl")
1055− liftIO $ exists `shouldBe` False
1056−
1057− describe "bulk API" $ do
1058− it "inserts all documents we request" $ withTestEnv $ do
1059− _ <- insertData
1060− let firstTest = BulkTest "blah"
1061− let secondTest = BulkTest "bloo"
1062− let firstDoc = BulkIndex testIndex
1063− testMapping (DocId "2") (toJSON firstTest)
1064− let secondDoc = BulkCreate testIndex
1065− testMapping (DocId "3") (toJSON secondTest)
1066− let stream = V.fromList [firstDoc, secondDoc]
1067− _ <- bulk stream
1068− _ <- refreshIndex testIndex
1069− fDoc <- getDocument testIndex testMapping (DocId "2")
1070− sDoc <- getDocument testIndex testMapping (DocId "3")
1071− let maybeFirst = eitherDecode $ responseBody fDoc :: Either String (EsResult BulkTest)
1072− let maybeSecond = eitherDecode $ responseBody sDoc :: Either String (EsResult BulkTest)
1073− liftIO $ do
1074− fmap getSource maybeFirst `shouldBe` Right (Just firstTest)
1075− fmap getSource maybeSecond `shouldBe` Right (Just secondTest)
1076−
1077−
1078− describe "query API" $ do
1079− it "returns document for term query and identity filter" $ withTestEnv $ do
1080− _ <- insertData
1081− let query = TermQuery (Term "user" "bitemyapp") Nothing
1082− let filter = IdentityFilter <&&> IdentityFilter
1083− let search = mkSearch (Just query) (Just filter)
1084− myTweet <- searchTweet search
1085− liftIO $
1086− myTweet `shouldBe` Right exampleTweet
1087−
1088− it "handles constant score queries" $ withTestEnv $ do
1089− _ <- insertData
1090− let query = TermsQuery "user" ("bitemyapp" :| [])
1091− let cfQuery = ConstantScoreQuery query (Boost 1.0)
1092− let filter = IdentityFilter
1093− let search = mkSearch (Just cfQuery) (Just filter)
1094− myTweet <- searchTweet search
1095− liftIO $
1096− myTweet `shouldBe` Right exampleTweet
1097− it "handles constant score filters" $ withTestEnv $ do
1098− _ <- insertData
1099− let query = TermsQuery "user" ("bitemyapp" :| [])
1100− let cfFilter = ConstantScoreFilter IdentityFilter (Boost 1.0)
1101− let boolQuery = mkBoolQuery [query, cfFilter] [] []
1102− let search = mkSearch (Just (QueryBoolQuery boolQuery)) Nothing
1103− myTweet <- searchTweet search
1104− liftIO $
1105− myTweet `shouldBe` Right exampleTweet
1106−
1107−
1108− it "returns document for terms query and identity filter" $ withTestEnv $ do
1109− _ <- insertData
1110− let query = TermsQuery "user" ("bitemyapp" :| [])
1111− let filter = IdentityFilter <&&> IdentityFilter
1112− let search = mkSearch (Just query) (Just filter)
1113− myTweet <- searchTweet search
1114− liftIO $
1115− myTweet `shouldBe` Right exampleTweet
1116−
1117− it "returns document for match query" $ withTestEnv $ do
1118− _ <- insertData
1119− let query = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
1120− let search = mkSearch (Just query) Nothing
1121− myTweet <- searchTweet search
1122− liftIO $
1123− myTweet `shouldBe` Right exampleTweet
1124−
1125− it "returns document for multi-match query" $ withTestEnv $ do
1126− _ <- insertData
1127− let flds = [FieldName "user", FieldName "message"]
1128− let query = QueryMultiMatchQuery $ mkMultiMatchQuery flds (QueryString "bitemyapp")
1129− let search = mkSearch (Just query) Nothing
1130− myTweet <- searchTweet search
1131− liftIO $
1132− myTweet `shouldBe` Right exampleTweet
1133−
1134− it "returns document for multi-match query with a custom tiebreaker" $ withTestEnv $ do
1135− _ <- insertData
1136− let tiebreaker = Just $ Tiebreaker 0.3
1137− flds = [FieldName "user", FieldName "message"]
1138− multiQuery' = mkMultiMatchQuery flds (QueryString "bitemyapp")
1139− query = QueryMultiMatchQuery $ multiQuery' { multiMatchQueryTiebreaker = tiebreaker }
1140− search = mkSearch (Just query) Nothing
1141− myTweet <- searchTweet search
1142− liftIO $
1143− myTweet `shouldBe` Right exampleTweet
1144−
1145− it "returns document for bool query" $ withTestEnv $ do
1146− _ <- insertData
1147− let innerQuery = QueryMatchQuery $
1148− mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
1149− let query = QueryBoolQuery $
1150− mkBoolQuery [innerQuery] [] []
1151− let search = mkSearch (Just query) Nothing
1152− myTweet <- searchTweet search
1153− liftIO $
1154− myTweet `shouldBe` Right exampleTweet
1155−
1156− it "returns document for boosting query" $ withTestEnv $ do
1157− _ <- insertData
1158− let posQuery = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "bitemyapp")
1159− let negQuery = QueryMatchQuery $ mkMatchQuery (FieldName "user") (QueryString "notmyapp")
1160− let query = QueryBoostingQuery $ BoostingQuery posQuery negQuery (Boost 0.2)
1161− let search = mkSearch (Just query) Nothing
1162− myTweet <- searchTweet search
1163− liftIO $
1164− myTweet `shouldBe` Right exampleTweet
1165−
1166− it "returns document for common terms query" $ withTestEnv $ do
1167− _ <- insertData
1168− let query = QueryCommonTermsQuery $
1169− CommonTermsQuery (FieldName "user")
1170− (QueryString "bitemyapp")
1171− (CutoffFrequency 0.0001)
1172− Or Or Nothing Nothing Nothing Nothing
1173− let search = mkSearch (Just query) Nothing
1174− myTweet <- searchTweet search
1175− liftIO $
1176− myTweet `shouldBe` Right exampleTweet
1177−
1178− it "returns document for for inline template query" $ withTestEnv $ do
1179− _ <- insertData
1180− let innerQuery = QueryMatchQuery $
1181− mkMatchQuery (FieldName "{{userKey}}")
1182− (QueryString "{{bitemyappKey}}")
1183− templateParams = TemplateQueryKeyValuePairs $ HM.fromList
1184− [ ("userKey", "user")
1185− , ("bitemyappKey", "bitemyapp")
1186− ]
1187− templateQuery = QueryTemplateQueryInline $
1188− TemplateQueryInline innerQuery templateParams
1189− search = mkSearch (Just templateQuery) Nothing
1190− myTweet <- searchTweet search
1191− liftIO $ myTweet `shouldBe` Right exampleTweet
1192−
1193−
1194− describe "sorting" $ do
1195− it "returns documents in the right order" $ withTestEnv $ do
1196− _ <- insertData
1197− _ <- insertOther
1198− let sortSpec = DefaultSortSpec $ mkSort (FieldName "age") Ascending
1199− let search = Search Nothing
1200− (Just IdentityFilter) (Just [sortSpec]) Nothing Nothing
1201− False (From 0) (Size 10) SearchTypeQueryThenFetch Nothing Nothing
1202− Nothing
1203− result <- searchTweets search
1204− let myTweet = grabFirst result
1205− liftIO $
1206− myTweet `shouldBe` Right otherTweet
1207−
1208−
1209− describe "filtering API" $ do
1210− it "returns document for composed boolmatch and identity" $ withTestEnv $ do
1211− _ <- insertData
1212− let queryFilter = BoolFilter (MustMatch (Term "user" "bitemyapp") False)
1213− <&&> IdentityFilter
1214− let search = mkSearch Nothing (Just queryFilter)
1215− myTweet <- searchTweet search
1216− liftIO $
1217− myTweet `shouldBe` Right exampleTweet
1218−
1219− it "returns document for term filter" $ withTestEnv $ do
1220− _ <- insertData
1221− let termFilter = TermFilter (Term "user" "bitemyapp") False
1222− let search = mkSearch Nothing (Just termFilter)
1223− myTweet <- searchTweet search
1224− liftIO $
1225− myTweet `shouldBe` Right exampleTweet
1226−
1227− it "returns document for existential filter" $ withTestEnv $ do
1228− _ <- insertData
1229− let search = mkSearch Nothing (Just (ExistsFilter (FieldName "user")))
1230− myTweet <- searchTweet search
1231− liftIO $
1232− myTweet `shouldBe` Right exampleTweet
1233−
1234− it "returns document for geo boundingbox filter" $ withTestEnv $ do
1235− _ <- insertData
1236− let box = GeoBoundingBox (LatLon 40.73 (-74.1)) (LatLon 40.10 (-71.12))
1237− let bbConstraint = GeoBoundingBoxConstraint (FieldName "tweet.location") box False GeoFilterMemory
1238− let geoFilter = GeoBoundingBoxFilter bbConstraint
1239− let search = mkSearch Nothing (Just geoFilter)
1240− myTweet <- searchTweet search
1241− liftIO $
1242− myTweet `shouldBe` Right exampleTweet
1243−
1244− it "doesn't return document for nonsensical boundingbox filter" $ withTestEnv $ do
1245− _ <- insertData
1246− let box = GeoBoundingBox (LatLon 0.73 (-4.1)) (LatLon 0.10 (-1.12))
1247− let bbConstraint = GeoBoundingBoxConstraint (FieldName "tweet.location") box False GeoFilterMemory
1248− let geoFilter = GeoBoundingBoxFilter bbConstraint
1249− let search = mkSearch Nothing (Just geoFilter)
1250− searchExpectNoResults search
1251−
1252− it "returns document for geo distance filter" $ withTestEnv $ do
1253− _ <- insertData
1254− let geoPoint = GeoPoint (FieldName "tweet.location") (LatLon 40.12 (-71.34))
1255− let distance = Distance 10.0 Miles
1256− let optimizeBbox = OptimizeGeoFilterType GeoFilterMemory
1257− let geoFilter = GeoDistanceFilter geoPoint distance SloppyArc optimizeBbox False
1258− let search = mkSearch Nothing (Just geoFilter)
1259− myTweet <- searchTweet search
1260− liftIO $
1261− myTweet `shouldBe` Right exampleTweet
1262−
1263− it "returns document for geo distance range filter" $ withTestEnv $ do
1264− _ <- insertData
1265− let geoPoint = GeoPoint (FieldName "tweet.location") (LatLon 40.12 (-71.34))
1266− let distanceRange = DistanceRange (Distance 0.0 Miles) (Distance 10.0 Miles)
1267− let geoFilter = GeoDistanceRangeFilter geoPoint distanceRange
1268− let search = mkSearch Nothing (Just geoFilter)
1269− myTweet <- searchTweet search
1270− liftIO $
1271− myTweet `shouldBe` Right exampleTweet
1272−
1273− it "doesn't return document for wild geo distance range filter" $ withTestEnv $ do
1274− _ <- insertData
1275− let geoPoint = GeoPoint (FieldName "tweet.location") (LatLon 40.12 (-71.34))
1276− let distanceRange = DistanceRange (Distance 100.0 Miles) (Distance 1000.0 Miles)
1277− let geoFilter = GeoDistanceRangeFilter geoPoint distanceRange
1278− let search = mkSearch Nothing (Just geoFilter)
1279− searchExpectNoResults search
1280−
1281− it "returns document for geo polygon filter" $ withTestEnv $ do
1282− _ <- insertData
1283− let points = [LatLon 40.0 (-70.00),
1284− LatLon 40.0 (-72.00),
1285− LatLon 41.0 (-70.00),
1286− LatLon 41.0 (-72.00)]
1287− let geoFilter = GeoPolygonFilter (FieldName "tweet.location") points
1288− let search = mkSearch Nothing (Just geoFilter)
1289− myTweet <- searchTweet search
1290− liftIO $
1291− myTweet `shouldBe` Right exampleTweet
1292−
1293− it "doesn't return document for bad geo polygon filter" $ withTestEnv $ do
1294− _ <- insertData
1295− let points = [LatLon 40.0 (-70.00),
1296− LatLon 40.0 (-71.00),
1297− LatLon 41.0 (-70.00),
1298− LatLon 41.0 (-71.00)]
1299− let geoFilter = GeoPolygonFilter (FieldName "tweet.location") points
1300− let search = mkSearch Nothing (Just geoFilter)
1301− searchExpectNoResults search
1302−
1303− it "returns document for ids filter" $ withTestEnv $ do
1304− _ <- insertData
1305− let filter = IdsFilter (MappingName "tweet") [DocId "1"]
1306− let search = mkSearch Nothing (Just filter)
1307− myTweet <- searchTweet search
1308− liftIO $
1309− myTweet `shouldBe` Right exampleTweet
1310−
1311− it "returns document for Double range filter" $ withTestEnv $ do
1312− _ <- insertData
1313− let filter = RangeFilter (FieldName "age")
1314− (RangeDoubleGtLt (GreaterThan 1000.0) (LessThan 100000.0))
1315− RangeExecutionIndex False
1316− let search = mkSearch Nothing (Just filter)
1317− myTweet <- searchTweet search
1318− liftIO $
1319− myTweet `shouldBe` Right exampleTweet
1320−
1321− it "returns document for UTCTime date filter" $ withTestEnv $ do
1322− _ <- insertData
1323− let filter = RangeFilter (FieldName "postDate")
1324− (RangeDateGtLt
1325− (GreaterThanD (UTCTime
1326− (ModifiedJulianDay 54000)
1327− (secondsToDiffTime 0)))
1328− (LessThanD (UTCTime
1329− (ModifiedJulianDay 55000)
1330− (secondsToDiffTime 11))))
1331− RangeExecutionIndex False
1332− let search = mkSearch Nothing (Just filter)
1333− myTweet <- searchTweet search
1334− liftIO $
1335− myTweet `shouldBe` Right exampleTweet
1336−
1337− it "returns document for regexp filter" $ withTestEnv $ do
1338− _ <- insertData
1339− let filter = RegexpFilter (FieldName "user") (Regexp "bite.*app")
1340− AllRegexpFlags (CacheName "test") False (CacheKey "key")
1341− let search = mkSearch Nothing (Just filter)
1342− myTweet <- searchTweet search
1343− liftIO $
1344− myTweet `shouldBe` Right exampleTweet
1345−
1346− it "doesn't return document for non-matching regexp filter" $ withTestEnv $ do
1347− _ <- insertData
1348− let filter = RegexpFilter (FieldName "user")
1349− (Regexp "boy") AllRegexpFlags
1350− (CacheName "test") False (CacheKey "key")
1351− let search = mkSearch Nothing (Just filter)
1352− searchExpectNoResults search
1353−
1354− it "returns document for query filter, uncached" $ withTestEnv $ do
1355− _ <- insertData
1356− let filter = QueryFilter (TermQuery (Term "user" "bitemyapp") Nothing) True
1357− search = mkSearch Nothing (Just filter)
1358− myTweet <- searchTweet search
1359− liftIO $ myTweet `shouldBe` Right exampleTweet
1360−
1361− it "returns document for query filter, cached" $ withTestEnv $ do
1362− _ <- insertData
1363− let filter = QueryFilter (TermQuery (Term "user" "bitemyapp") Nothing) False
1364− search = mkSearch Nothing (Just filter)
1365− myTweet <- searchTweet search
1366− liftIO $ myTweet `shouldBe` Right exampleTweet
1367−
1368− describe "Aggregation API" $ do
1369− it "returns term aggregation results" $ withTestEnv $ do
1370− _ <- insertData
1371− let terms = TermsAgg $ mkTermsAggregation "user"
1372− let search = mkAggregateSearch Nothing $ mkAggregations "users" terms
1373− searchExpectAggs search
1374− searchValidBucketAgg search "users" toTerms
1375−
1376− it "return sub-aggregation results" $ withTestEnv $ do
1377− _ <- insertData
1378− let subaggs = mkAggregations "age_agg" . TermsAgg $ mkTermsAggregation "age"
1379− agg = TermsAgg $ (mkTermsAggregation "user") { termAggs = Just subaggs}
1380− search = mkAggregateSearch Nothing $ mkAggregations "users" agg
1381− reply <- searchByIndex testIndex search
1382− let result = decode (responseBody reply) :: Maybe (SearchResult Tweet)
1383− usersAggResults = result >>= aggregations >>= toTerms "users"
1384− subAggResults = usersAggResults >>= (listToMaybe . buckets) >>= termsAggs >>= toTerms "age_agg"
1385− subAddResultsExists = isJust subAggResults
1386− liftIO $ (subAddResultsExists) `shouldBe` True
1387−
1388− it "returns cardinality aggregation results" $ withTestEnv $ do
1389− _ <- insertData
1390− let cardinality = CardinalityAgg $ mkCardinalityAggregation $ FieldName "user"
1391− let search = mkAggregateSearch Nothing $ mkAggregations "users" cardinality
1392− let search' = search { Database.V1.Bloodhound.from = From 0, size = Size 0 }
1393− searchExpectAggs search'
1394− let docCountPair k n = (k, object ["value" .= Number n])
1395− res <- searchTweets search'
1396− liftIO $
1397− fmap aggregations res `shouldBe` Right (Just (M.fromList [ docCountPair "users" 1]))
1398−
1399− it "can give collection hint parameters to term aggregations" $ when' (atleast es13) $ withTestEnv $ do
1400− _ <- insertData
1401− let terms = TermsAgg $ (mkTermsAggregation "user") { termCollectMode = Just BreadthFirst }
1402− let search = mkAggregateSearch Nothing $ mkAggregations "users" terms
1403− searchExpectAggs search
1404− searchValidBucketAgg search "users" toTerms
1405−
1406− -- One of these fails with 1.7.3
1407− it "can give execution hint parameters to term aggregations" $ when' (atmost es11) $ withTestEnv $ do
1408− _ <- insertData
1409− searchTermsAggHint [Map, Ordinals]
1410−
1411− it "can give execution hint parameters to term aggregations" $ when' (is es12) $ withTestEnv $ do
1412− _ <- insertData
1413− searchTermsAggHint [GlobalOrdinals, GlobalOrdinalsHash, GlobalOrdinalsLowCardinality, Map, Ordinals]
1414−
1415− it "can give execution hint parameters to term aggregations" $ when' (atleast es12) $ withTestEnv $ do
1416− _ <- insertData
1417− searchTermsAggHint [GlobalOrdinals, GlobalOrdinalsHash, GlobalOrdinalsLowCardinality, Map]
1418− -- One of the above.
1419−
1420− it "can execute value_count aggregations" $ withTestEnv $ do
1421− _ <- insertData
1422− _ <- insertOther
1423− let ags = mkAggregations "user_count" (ValueCountAgg (FieldValueCount (FieldName "user"))) <>
1424− mkAggregations "bogus_count" (ValueCountAgg (FieldValueCount (FieldName "bogus")))
1425− let search = mkAggregateSearch Nothing ags
1426− let docCountPair k n = (k, object ["value" .= Number n])
1427− res <- searchTweets search
1428− liftIO $
1429− fmap aggregations res `shouldBe` Right (Just (M.fromList [ docCountPair "user_count" 2
1430− , docCountPair "bogus_count" 0
1431− ]))
1432−
1433− it "can execute filter aggregations" $ withTestEnv $ do
1434− _ <- insertData
1435− _ <- insertOther
1436− let ags = mkAggregations "bitemyapps" (FilterAgg (FilterAggregation (TermFilter (Term "user" "bitemyapp") defaultCache) Nothing)) <>
1437− mkAggregations "notmyapps" (FilterAgg (FilterAggregation (TermFilter (Term "user" "notmyapp") defaultCache) Nothing))
1438− let search = mkAggregateSearch Nothing ags
1439− let docCountPair k n = (k, object ["doc_count" .= Number n])
1440− res <- searchTweets search
1441− liftIO $
1442− fmap aggregations res `shouldBe` Right (Just (M.fromList [ docCountPair "bitemyapps" 1
1443− , docCountPair "notmyapps" 1
1444− ]))
1445− it "can execute date_range aggregations" $ withTestEnv $ do
1446− let now = fromGregorian 2015 3 14
1447− let ltAMonthAgo = UTCTime (fromGregorian 2015 3 1) 0
1448− let ltAWeekAgo = UTCTime (fromGregorian 2015 3 10) 0
1449− let oldDoc = exampleTweet { postDate = ltAMonthAgo }
1450− let newDoc = exampleTweet { postDate = ltAWeekAgo }
1451− _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings oldDoc (DocId "1")
1452− _ <- indexDocument testIndex testMapping defaultIndexDocumentSettings newDoc (DocId "2")
1453− _ <- refreshIndex testIndex
1454− let thisMonth = DateRangeFrom (DateMathExpr (DMDate now) [SubtractTime 1 DMMonth])
1455− let thisWeek = DateRangeFrom (DateMathExpr (DMDate now) [SubtractTime 1 DMWeek])
1456− let agg = DateRangeAggregation (FieldName "postDate") Nothing (thisMonth :| [thisWeek])
1457− let ags = mkAggregations "date_ranges" (DateRangeAgg agg)
1458− let search = mkAggregateSearch Nothing ags
1459− res <- searchTweets search
1460− liftIO $ hitsTotal . searchHits <$> res `shouldBe` Right 2
1461− let bucks = do magrs <- fmapL show (aggregations <$> res)
1462− agrs <- note "no aggregations returned" magrs
1463− rawBucks <- note "no date_ranges aggregation" $ M.lookup "date_ranges" agrs
1464− parseEither parseJSON rawBucks
1465− let fromMonthT = UTCTime (fromGregorian 2015 2 14) 0
1466− let fromWeekT = UTCTime (fromGregorian 2015 3 7) 0
1467− liftIO $ buckets <$> bucks `shouldBe` Right [ DateRangeResult "2015-02-14T00:00:00.000Z-*"
1468− (Just fromMonthT)
1469− (Just "2015-02-14T00:00:00.000Z")
1470− Nothing
1471− Nothing
1472− 2
1473− Nothing
1474− , DateRangeResult "2015-03-07T00:00:00.000Z-*"
1475− (Just fromWeekT)
1476− (Just "2015-03-07T00:00:00.000Z")
1477− Nothing
1478− Nothing
1479− 1
1480− Nothing
1481− ]
1482−
1483− it "returns date histogram aggregation results" $ withTestEnv $ do
1484− _ <- insertData
1485− let histogram = DateHistogramAgg $ mkDateHistogram (FieldName "postDate") Minute
1486− let search = mkAggregateSearch Nothing (mkAggregations "byDate" histogram)
1487− searchExpectAggs search
1488− searchValidBucketAgg search "byDate" toDateHistogram
1489−
1490− it "returns date histogram using fractional date" $ withTestEnv $ do
1491− _ <- insertData
1492− let periods = [Year, Quarter, Month, Week, Day, Hour, Minute, Second]
1493− let fractionals = map (FractionalInterval 1.5) [Weeks, Days, Hours, Minutes, Seconds]
1494− let intervals = periods ++ fractionals
1495− let histogram = mkDateHistogram (FieldName "postDate")
1496− let search interval = mkAggregateSearch Nothing $ mkAggregations "byDate" $ DateHistogramAgg (histogram interval)
1497− let expect interval = searchExpectAggs (search interval)
1498− let valid interval = searchValidBucketAgg (search interval) "byDate" toDateHistogram
1499− forM_ intervals expect
1500− forM_ intervals valid
1501−
1502− it "can execute missing aggregations" $ withTestEnv $ do
1503− _ <- insertData
1504− _ <- insertExtra
1505− let ags = mkAggregations "missing_agg" (MissingAgg (MissingAggregation "extra"))
1506− let search = mkAggregateSearch Nothing ags
1507− let docCountPair k n = (k, object ["doc_count" .= Number n])
1508− res <- searchTweets search
1509− liftIO $
1510− fmap aggregations res `shouldBe` Right (Just (M.fromList [docCountPair "missing_agg" 1]))
1511−
1512− describe "Highlights API" $ do
1513−
1514− it "returns highlight from query when there should be one" $ withTestEnv $ do
1515− _ <- insertData
1516− _ <- insertOther
1517− let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
1518− let testHighlight = Highlights Nothing [FieldHighlight (FieldName "message") Nothing]
1519−
1520− let search = mkHighlightSearch (Just query) testHighlight
1521− myHighlight <- searchTweetHighlight search
1522− liftIO $
1523− myHighlight `shouldBe` Right (Just (M.fromList [("message",["Use <em>haskell</em>!"])]))
1524−
1525− it "doesn't return highlight from a query when it shouldn't" $ withTestEnv $ do
1526− _ <- insertData
1527− _ <- insertOther
1528− let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
1529− let testHighlight = Highlights Nothing [FieldHighlight (FieldName "user") Nothing]
1530−
1531− let search = mkHighlightSearch (Just query) testHighlight
1532− myHighlight <- searchTweetHighlight search
1533− liftIO $
1534− myHighlight `shouldBe` Right Nothing
1535−
1536− describe "Source filtering" $ do
1537−
1538− it "doesn't include source when sources are disabled" $ withTestEnv $ do
1539− searchExpectSource
1540− NoSource
1541− (Left (EsError 500 "Source was missing"))
1542−
1543− it "includes a source" $ withTestEnv $ do
1544− searchExpectSource
1545− (SourcePatterns (PopPattern (Pattern "message")))
1546− (Right (Object (HM.fromList [("message", String "Use haskell!")])))
1547−
1548− it "includes sources" $ withTestEnv $ do
1549− searchExpectSource
1550− (SourcePatterns (PopPatterns [Pattern "user", Pattern "message"]))
1551− (Right (Object (HM.fromList [("user",String "bitemyapp"),("message", String "Use haskell!")])))
1552−
1553− it "includes source patterns" $ withTestEnv $ do
1554− searchExpectSource
1555− (SourcePatterns (PopPattern (Pattern "*ge")))
1556− (Right (Object (HM.fromList [("age", Number 10000),("message", String "Use haskell!")])))
1557−
1558− it "excludes source patterns" $ withTestEnv $ do
1559− searchExpectSource
1560− (SourceIncludeExclude (Include [])
1561− (Exclude [Pattern "l*", Pattern "*ge", Pattern "postDate", Pattern "extra"]))
1562− (Right (Object (HM.fromList [("user",String "bitemyapp")])))
1563−
1564− describe "ToJSON RegexpFlags" $ do
1565− it "generates the correct JSON for AllRegexpFlags" $
1566− toJSON AllRegexpFlags `shouldBe` String "ALL"
1567−
1568− it "generates the correct JSON for NoRegexpFlags" $
1569− toJSON NoRegexpFlags `shouldBe` String "NONE"
1570−
1571− it "generates the correct JSON for SomeRegexpFlags" $
1572− let flags = AnyString :| [ Automaton
1573− , Complement
1574− , Empty
1575− , Intersection
1576− , Interval ]
1577− in toJSON (SomeRegexpFlags flags) `shouldBe` String "ANYSTRING|AUTOMATON|COMPLEMENT|EMPTY|INTERSECTION|INTERVAL"
1578−
1579− prop "removes duplicates from flags" $ \(flags :: RegexpFlags) ->
1580− let String str = toJSON flags
1581− flagStrs = T.splitOn "|" str
1582− in noDuplicates flagStrs
1583−
1584− describe "omitNulls" $ do
1585− it "checks that omitNulls drops list elements when it should" $
1586− let dropped = omitNulls $ [ "test1" .= (toJSON ([] :: [Int]))
1587− , "test2" .= (toJSON ("some value" :: Text))]
1588− in dropped `shouldBe` Object (HM.fromList [("test2", String "some value")])
1589−
1590− it "checks that omitNulls doesn't drop list elements when it shouldn't" $
1591− let notDropped = omitNulls $ [ "test1" .= (toJSON ([1] :: [Int]))
1592− , "test2" .= (toJSON ("some value" :: Text))]
1593− in notDropped `shouldBe` Object (HM.fromList [ ("test1", Array (V.fromList [Number 1.0]))
1594− , ("test2", String "some value")])
1595− it "checks that omitNulls drops non list elements when it should" $
1596− let dropped = omitNulls $ [ "test1" .= (toJSON Null)
1597− , "test2" .= (toJSON ("some value" :: Text))]
1598− in dropped `shouldBe` Object (HM.fromList [("test2", String "some value")])
1599− it "checks that omitNulls doesn't drop non list elements when it shouldn't" $
1600− let notDropped = omitNulls $ [ "test1" .= (toJSON (1 :: Int))
1601− , "test2" .= (toJSON ("some value" :: Text))]
1602− in notDropped `shouldBe` Object (HM.fromList [ ("test1", Number 1.0)
1603− , ("test2", String "some value")])
1604− describe "Monoid (SearchHits a)" $ do
1605 prop "abides the monoid laws" $ eq $
61 prop "abides the monoid laws" $ eq $
1606 prop_Monoid (T :: T (SearchHits ()))
62 prop_Monoid (T :: T (SearchHits ()))
1607
63
1608− describe "mkDocVersion" $ do
64+ describe "mkDocVersion" $
1609 prop "can never construct an out of range docVersion" $ \i ->
65 prop "can never construct an out of range docVersion" $ \i ->
1610 let res = mkDocVersion i
66 let res = mkDocVersion i
1611 in case res of
67 in case res of
@@ -1614,113 +70,7 @@ main = hspec $ do
1614 (dv <= maxBound) .&&.
70 (dv <= maxBound) .&&.
1615 docVersionNumber dv === i
71 docVersionNumber dv === i
1616
72
1617− describe "FsSnapshotRepo" $ do
73+ describe "getNodesInfo" $
1618− prop "SnapshotRepo laws" $ \fsr ->
1619− fromGSnapshotRepo (toGSnapshotRepo fsr) === Right (fsr :: FsSnapshotRepo)
1620−
1621− describe "snapshot repos" $ do
1622− it "always parses all snapshot repos API" $ when' canSnapshot $ withTestEnv $ do
1623− res <- getSnapshotRepos AllSnapshotRepos
1624− liftIO $ case res of
1625− Left e -> expectationFailure ("Expected a right but got Left " <> show e)
1626− Right _ -> return ()
1627−
1628− it "finds an existing list of repos" $ when' canSnapshot $ withTestEnv $ do
1629− let r1n = SnapshotRepoName "bloodhound-repo1"
1630− let r2n = SnapshotRepoName "bloodhound-repo2"
1631− withSnapshotRepo r1n $ \r1 ->
1632− withSnapshotRepo r2n $ \r2 -> do
1633− repos <- getSnapshotRepos (SnapshotRepoList (ExactRepo r1n :| [ExactRepo r2n]))
1634− liftIO $ case repos of
1635− Right xs -> do
1636− let srt = L.sortBy (comparing gSnapshotRepoName)
1637− srt xs `shouldBe` srt [r1, r2]
1638− Left e -> expectationFailure (show e)
1639−
1640− it "creates and updates with updateSnapshotRepo" $ when' canSnapshot $ withTestEnv $ do
1641− let r1n = SnapshotRepoName "bloodhound-repo1"
1642− withSnapshotRepo r1n $ \r1 -> do
1643− let Just (String dir) = HM.lookup "location" (gSnapshotRepoSettingsObject (gSnapshotRepoSettings r1))
1644− let noCompression = FsSnapshotRepo r1n (T.unpack dir) False Nothing Nothing Nothing
1645− resp <- updateSnapshotRepo defaultSnapshotRepoUpdateSettings noCompression
1646− liftIO (validateStatus resp 200)
1647− Right [roundtrippedNoCompression] <- getSnapshotRepos (SnapshotRepoList (ExactRepo r1n :| []))
1648− liftIO (roundtrippedNoCompression `shouldBe` toGSnapshotRepo noCompression)
1649−
1650− -- verify came around in 1.4 it seems
1651− it "can verify existing repos" $ when' canSnapshot $ when' (atleast es14) $ withTestEnv $ do
1652− let r1n = SnapshotRepoName "bloodhound-repo1"
1653− withSnapshotRepo r1n $ \_ -> do
1654− res <- verifySnapshotRepo r1n
1655− liftIO $ case res of
1656− Right (SnapshotVerification vs)
1657− | null vs -> expectationFailure "Expected nonempty set of verifying nodes"
1658− | otherwise -> return ()
1659− Left e -> expectationFailure (show e)
1660−
1661− describe "snapshots" $ do
1662− it "always parses all snapshots API" $ when' canSnapshot $ withTestEnv $ do
1663− let r1n = SnapshotRepoName "bloodhound-repo1"
1664− withSnapshotRepo r1n $ \_ -> do
1665− res <- getSnapshots r1n AllSnapshots
1666− liftIO $ case res of
1667− Left e -> expectationFailure ("Expected a right but got Left " <> show e)
1668− Right _ -> return ()
1669−
1670− it "can parse a snapshot that it created" $ when' canSnapshot $ withTestEnv $ do
1671− let r1n = SnapshotRepoName "bloodhound-repo1"
1672− withSnapshotRepo r1n $ \_ -> do
1673− let s1n = SnapshotName "example-snapshot"
1674− withSnapshot r1n s1n $ do
1675− res <- getSnapshots r1n (SnapshotList (ExactSnap s1n :| []))
1676− liftIO $ case res of
1677− Right [snap]
1678− | snapInfoState snap == SnapshotSuccess &&
1679− snapInfoName snap == s1n -> return ()
1680− | otherwise -> expectationFailure (show snap)
1681− Right [] -> expectationFailure "There were no snapshots"
1682− Right snaps -> expectationFailure ("Expected 1 snapshot but got" <> show (length snaps))
1683− Left e -> expectationFailure (show e)
1684−
1685− describe "snapshot restore" $ do
1686− it "can restore a snapshot that we create" $ when' canSnapshot $ withTestEnv $ do
1687− let r1n = SnapshotRepoName "bloodhound-repo1"
1688− withSnapshotRepo r1n $ \_ -> do
1689− let s1n = SnapshotName "example-snapshot"
1690− withSnapshot r1n s1n $ do
1691− let settings = defaultSnapshotRestoreSettings { snapRestoreWaitForCompletion = True }
1692− -- have to close an index to restore it
1693− resp1 <- closeIndex testIndex
1694− liftIO (validateStatus resp1 200)
1695− resp2 <- restoreSnapshot r1n s1n settings
1696− liftIO (validateStatus resp2 200)
1697−
1698− it "can restore and rename" $ when' canSnapshot $ withTestEnv $ do
1699− let r1n = SnapshotRepoName "bloodhound-repo1"
1700− withSnapshotRepo r1n $ \_ -> do
1701− let s1n = SnapshotName "example-snapshot"
1702− withSnapshot r1n s1n $ do
1703− let pat = RestoreRenamePattern "bloodhound-tests-twitter-(\\d+)"
1704− let replace = RRTLit "restored-" :| [RRSubWholeMatch]
1705− let expectedIndex = IndexName "restored-bloodhound-tests-twitter-1"
1706− oldEnoughForOverrides <- liftIO (atleast es15)
1707− let overrides = RestoreIndexSettings { restoreOverrideReplicas = Just (ReplicaCount 0) }
1708− let settings = defaultSnapshotRestoreSettings { snapRestoreWaitForCompletion = True
1709− , snapRestoreRenamePattern = Just pat
1710− , snapRestoreRenameReplacement = Just replace
1711− , snapRestoreIndexSettingsOverrides = if oldEnoughForOverrides
1712− then Just overrides
1713− else Nothing
1714− }
1715− -- have to close an index to restore it
1716− let go = do
1717− resp <- restoreSnapshot r1n s1n settings
1718− liftIO (validateStatus resp 200)
1719− exists <- indexExists expectedIndex
1720− liftIO (exists `shouldBe` True)
1721− go `finally` deleteIndex expectedIndex
1722−
1723− describe "getNodesInfo" $ do
1724 it "fetches the responding node when LocalNode is used" $ withTestEnv $ do
74 it "fetches the responding node when LocalNode is used" $ withTestEnv $ do
1725 res <- getNodesInfo LocalNode
75 res <- getNodesInfo LocalNode
1726 liftIO $ case res of
76 liftIO $ case res of
@@ -1730,7 +80,7 @@ main = hspec $ do
1730 Right NodesInfo {..} -> length nodesInfo `shouldBe` 1
80 Right NodesInfo {..} -> length nodesInfo `shouldBe` 1
1731 Left e -> expectationFailure ("Expected NodesInfo but got " <> show e)
81 Left e -> expectationFailure ("Expected NodesInfo but got " <> show e)
1732
82
1733− describe "getNodesStats" $ do
83+ describe "getNodesStats" $
1734 it "fetches the responding node when LocalNode is used" $ withTestEnv $ do
84 it "fetches the responding node when LocalNode is used" $ withTestEnv $ do
1735 res <- getNodesStats LocalNode
85 res <- getNodesStats LocalNode
1736 liftIO $ case res of
86 liftIO $ case res of
@@ -1740,7 +90,7 @@ main = hspec $ do
1740 Right NodesStats {..} -> length nodesStats `shouldBe` 1
90 Right NodesStats {..} -> length nodesStats `shouldBe` 1
1741 Left e -> expectationFailure ("Expected NodesStats but got " <> show e)
91 Left e -> expectationFailure ("Expected NodesStats but got " <> show e)
1742
92
1743− describe "Enum DocVersion" $ do
93+ describe "Enum DocVersion" $
1744 it "follows the laws of Enum, Bounded" $ do
94 it "follows the laws of Enum, Bounded" $ do
1745 evaluate (succ maxBound :: DocVersion) `shouldThrow` anyErrorCall
95 evaluate (succ maxBound :: DocVersion) `shouldThrow` anyErrorCall
1746 evaluate (pred minBound :: DocVersion) `shouldThrow` anyErrorCall
96 evaluate (pred minBound :: DocVersion) `shouldThrow` anyErrorCall
@@ -1750,11 +100,14 @@ main = hspec $ do
1750 enumFrom (pred maxBound :: DocVersion) `shouldBe` [pred maxBound, maxBound]
100 enumFrom (pred maxBound :: DocVersion) `shouldBe` [pred maxBound, maxBound]
1751 enumFromThen minBound (pred maxBound :: DocVersion) `shouldBe` [minBound, pred maxBound]
101 enumFromThen minBound (pred maxBound :: DocVersion) `shouldBe` [minBound, pred maxBound]
1752
102
1753− describe "scan&scroll API" $ do
103+ describe "Scan & Scroll API" $
1754 it "returns documents using the scan&scroll API" $ withTestEnv $ do
104 it "returns documents using the scan&scroll API" $ withTestEnv $ do
1755 _ <- insertData
105 _ <- insertData
1756 _ <- insertOther
106 _ <- insertOther
1757− let search = (mkSearch (Just $ MatchAllQuery Nothing) Nothing) { size = (Size 1) }
107+ let search =
108+ (mkSearch
109+ (Just $ MatchAllQuery Nothing) Nothing)
110+ { size = Size 1 }
1758 regular_search <- searchTweet search
111 regular_search <- searchTweet search
1759 scan_search' <- scanSearch testIndex testMapping search :: BH IO [Hit Tweet]
112 scan_search' <- scanSearch testIndex testMapping search :: BH IO [Hit Tweet]
1760 let scan_search = map hitSource scan_search'
113 let scan_search = map hitSource scan_search'
@@ -1762,206 +115,3 @@ main = hspec $ do
1762 regular_search `shouldBe` Right exampleTweet -- Check that the size restrtiction is being honored
115 regular_search `shouldBe` Right exampleTweet -- Check that the size restrtiction is being honored
1763 liftIO $
116 liftIO $
1764 scan_search `shouldMatchList` [Just exampleTweet, Just otherTweet]
117 scan_search `shouldMatchList` [Just exampleTweet, Just otherTweet]
1765−
1766− describe "index aliases" $ do
1767− it "handles the simple case of aliasing an existing index" $ do
1768− let alias = IndexAlias (testIndex) (IndexAliasName (IndexName "bloodhound-tests-twitter-1-alias"))
1769− let create = IndexAliasCreate Nothing Nothing
1770− let action = AddAlias alias create
1771−
1772− withTestEnv $ do
1773− resetIndex
1774− resp <- updateIndexAliases (action :| [])
1775− liftIO $ validateStatus resp 200
1776− let cleanup = withTestEnv (updateIndexAliases (RemoveAlias alias :| []))
1777− (do aliases <- withTestEnv getIndexAliases
1778− let expected = IndexAliasSummary alias create
1779− case aliases of
1780− Right (IndexAliasesSummary summs) ->
1781− L.find ((== alias) . indexAliasSummaryAlias) summs `shouldBe` Just expected
1782− Left e -> expectationFailure ("Expected an IndexAliasesSummary but got " <> show e)) `finally` cleanup
1783−
1784− it "handles an alias with routing and a filter" $ do
1785− let alias = IndexAlias (testIndex) (IndexAliasName (IndexName "bloodhound-tests-twitter-1-alias"))
1786− let sar = SearchAliasRouting (RoutingValue "search val" :| [])
1787− let iar = IndexAliasRouting (RoutingValue "index val")
1788− let routing = GranularAliasRouting (Just sar) (Just iar)
1789− let filter = LimitFilter 42
1790− let create = IndexAliasCreate (Just routing) (Just filter)
1791− let action = AddAlias alias create
1792−
1793− withTestEnv $ do
1794− resetIndex
1795− resp <- updateIndexAliases (action :| [])
1796− liftIO $ validateStatus resp 200
1797− let cleanup = withTestEnv (updateIndexAliases (RemoveAlias alias :| []))
1798− (do aliases <- withTestEnv getIndexAliases
1799− let expected = IndexAliasSummary alias create
1800− case aliases of
1801− Right (IndexAliasesSummary summs) ->
1802− L.find ((== alias) . indexAliasSummaryAlias) summs `shouldBe` Just expected
1803− Left e -> expectationFailure ("Expected an IndexAliasesSummary but got " <> show e)) `finally` cleanup
1804−
1805− describe "Index Listing" $ do
1806− it "returns a list of index names" $ withTestEnv $ do
1807− _ <- createExampleIndex
1808− ixns <- listIndices
1809− liftIO (ixns `shouldContain` [testIndex])
1810−
1811− describe "Index Settings" $ do
1812− it "persists settings" $ withTestEnv $ do
1813− _ <- deleteExampleIndex
1814− _ <- createExampleIndex
1815− let updates = BlocksWrite False :| []
1816− updateResp <- updateIndexSettings updates testIndex
1817− liftIO $ validateStatus updateResp 200
1818− getResp <- getIndexSettings testIndex
1819− liftIO $
1820− getResp `shouldBe` Right (IndexSettingsSummary
1821− testIndex
1822− (IndexSettings (ShardCount 1) (ReplicaCount 0))
1823− (NE.toList updates))
1824−
1825− describe "Index Optimization" $ do
1826− it "returns a successful response upon completion" $ withTestEnv $ do
1827− _ <- createExampleIndex
1828− resp <- optimizeIndex (IndexList (testIndex :| [])) defaultIndexOptimizationSettings
1829− liftIO $ validateStatus resp 200
1830−
1831− describe "Suggest" $ do
1832− it "returns a search suggestion using the phrase suggester" $ withTestEnv $ do
1833− _ <- insertData
1834− let {- query = QueryMatchNoneQuery
1835− query = TermQuery (Term "user" "bitemyapp") Nothing -}
1836− let phraseSuggester = mkPhraseSuggester (FieldName "message")
1837− namedSuggester = Suggest "Use haskel" "suggest_name" (SuggestTypePhraseSuggester phraseSuggester)
1838− search' = mkSearch Nothing Nothing
1839− search = search' { suggestBody = Just namedSuggester }
1840− expectedText = Just "use haskell"
1841− resp <- searchByIndex testIndex search
1842− parsed <- parseEsResponse resp :: BH IO (Either EsError (SearchResult Tweet))
1843− case parsed of
1844− Left e -> liftIO $ expectationFailure ("Expected an search suggestion but got " <> show e)
1845− Right sr -> liftIO $ (suggestOptionsText . head . suggestResponseOptions . head . nsrResponses <$> suggest sr) `shouldBe` expectedText
1846−
1847− describe "JSON instances" $ do
1848− propJSON (Proxy :: Proxy Version)
1849− propJSON (Proxy :: Proxy IndexName)
1850− propJSON (Proxy :: Proxy MappingName)
1851− propJSON (Proxy :: Proxy DocId)
1852− propJSON (Proxy :: Proxy IndexAliasRouting)
1853− propJSON (Proxy :: Proxy RoutingValue)
1854− propJSON (Proxy :: Proxy ShardCount)
1855− propJSON (Proxy :: Proxy ReplicaCount)
1856− propJSON (Proxy :: Proxy TemplateName)
1857− propJSON (Proxy :: Proxy TemplatePattern)
1858− propJSON (Proxy :: Proxy QueryString)
1859− propJSON (Proxy :: Proxy FieldName)
1860− propJSON (Proxy :: Proxy CacheName)
1861− propJSON (Proxy :: Proxy CacheKey)
1862− propJSON (Proxy :: Proxy Existence)
1863− propJSON (Proxy :: Proxy CutoffFrequency)
1864− propJSON (Proxy :: Proxy Analyzer)
1865− propJSON (Proxy :: Proxy MaxExpansions)
1866− propJSON (Proxy :: Proxy Lenient)
1867− propJSON (Proxy :: Proxy Tiebreaker)
1868− propJSON (Proxy :: Proxy Boost)
1869− propJSON (Proxy :: Proxy BoostTerms)
1870− propJSON (Proxy :: Proxy MinimumMatch)
1871− propJSON (Proxy :: Proxy DisableCoord)
1872− propJSON (Proxy :: Proxy IgnoreTermFrequency)
1873− propJSON (Proxy :: Proxy MinimumTermFrequency)
1874− propJSON (Proxy :: Proxy MaxQueryTerms)
1875− propJSON (Proxy :: Proxy Fuzziness)
1876− propJSON (Proxy :: Proxy PrefixLength)
1877− propJSON (Proxy :: Proxy TypeName)
1878− propJSON (Proxy :: Proxy PercentMatch)
1879− propJSON (Proxy :: Proxy StopWord)
1880− propJSON (Proxy :: Proxy QueryPath)
1881− propJSON (Proxy :: Proxy AllowLeadingWildcard)
1882− propJSON (Proxy :: Proxy LowercaseExpanded)
1883− propJSON (Proxy :: Proxy EnablePositionIncrements)
1884− propJSON (Proxy :: Proxy AnalyzeWildcard)
1885− propJSON (Proxy :: Proxy GeneratePhraseQueries)
1886− propJSON (Proxy :: Proxy Locale)
1887− propJSON (Proxy :: Proxy MaxWordLength)
1888− propJSON (Proxy :: Proxy MinWordLength)
1889− propJSON (Proxy :: Proxy PhraseSlop)
1890− propJSON (Proxy :: Proxy MinDocFrequency)
1891− propJSON (Proxy :: Proxy MaxDocFrequency)
1892− propJSON (Proxy :: Proxy Filter)
1893− propJSON (Proxy :: Proxy Query)
1894− propJSON (Proxy :: Proxy SimpleQueryStringQuery)
1895− propJSON (Proxy :: Proxy FieldOrFields)
1896− propJSON (Proxy :: Proxy SimpleQueryFlag)
1897− propJSON (Proxy :: Proxy RegexpQuery)
1898− propJSON (Proxy :: Proxy QueryStringQuery)
1899− propJSON (Proxy :: Proxy RangeQuery)
1900− propJSON (Proxy :: Proxy PrefixQuery)
1901− propJSON (Proxy :: Proxy NestedQuery)
1902− propJSON (Proxy :: Proxy MoreLikeThisFieldQuery)
1903− propJSON (Proxy :: Proxy MoreLikeThisQuery)
1904− propJSON (Proxy :: Proxy IndicesQuery)
1905− propJSON (Proxy :: Proxy HasParentQuery)
1906− propJSON (Proxy :: Proxy HasChildQuery)
1907− propJSON (Proxy :: Proxy FuzzyQuery)
1908− propJSON (Proxy :: Proxy FuzzyLikeFieldQuery)
1909− propJSON (Proxy :: Proxy FuzzyLikeThisQuery)
1910− propJSON (Proxy :: Proxy FilteredQuery)
1911− propJSON (Proxy :: Proxy DisMaxQuery)
1912− propJSON (Proxy :: Proxy CommonTermsQuery)
1913− propJSON (Proxy :: Proxy CommonMinimumMatch)
1914− propJSON (Proxy :: Proxy BoostingQuery)
1915− propJSON (Proxy :: Proxy BoolQuery)
1916− propJSON (Proxy :: Proxy MatchQuery)
1917− propJSON (Proxy :: Proxy MultiMatchQueryType)
1918− propJSON (Proxy :: Proxy BooleanOperator)
1919− propJSON (Proxy :: Proxy ZeroTermsQuery)
1920− propJSON (Proxy :: Proxy MatchQueryType)
1921− propJSON (Proxy :: Proxy AliasRouting)
1922− propJSON (Proxy :: Proxy IndexAliasCreate)
1923− propJSON (Proxy :: Proxy SearchAliasRouting)
1924− propJSON (Proxy :: Proxy ScoreType)
1925− propJSON (Proxy :: Proxy Distance)
1926− propJSON (Proxy :: Proxy DistanceUnit)
1927− propJSON (Proxy :: Proxy DistanceType)
1928− propJSON (Proxy :: Proxy OptimizeBbox)
1929− propJSON (Proxy :: Proxy GeoBoundingBoxConstraint)
1930− propJSON (Proxy :: Proxy GeoFilterType)
1931− propJSON (Proxy :: Proxy GeoBoundingBox)
1932− propJSON (Proxy :: Proxy LatLon)
1933− propJSON (Proxy :: Proxy RangeExecution)
1934− prop "RegexpFlags FromJSON/ToJSON roundtrips, removing dups " $ \rfs ->
1935− let expected = case rfs of
1936− SomeRegexpFlags fs -> SomeRegexpFlags (NE.fromList (nub (NE.toList fs)))
1937− x -> x
1938− in parseEither parseJSON (toJSON rfs) === Right expected
1939− propJSON (Proxy :: Proxy BoolMatch)
1940− propJSON (Proxy :: Proxy Term)
1941− propJSON (Proxy :: Proxy MultiMatchQuery)
1942− propJSON (Proxy :: Proxy IndexSettings)
1943− propJSON (Proxy :: Proxy UpdatableIndexSetting')
1944− propJSON (Proxy :: Proxy ReplicaBounds)
1945− propJSON (Proxy :: Proxy Bytes)
1946− propJSON (Proxy :: Proxy AllocationPolicy)
1947− propJSON (Proxy :: Proxy InitialShardCount)
1948− propJSON (Proxy :: Proxy FSType)
1949− propJSON (Proxy :: Proxy CompoundFormat)
1950− propJSON (Proxy :: Proxy TemplateQueryInline)
1951− propJSON (Proxy :: Proxy Suggest)
1952− propJSON (Proxy :: Proxy DirectGenerators)
1953− propJSON (Proxy :: Proxy DirectGeneratorSuggestModeTypes)
1954−
1955−-- Temporary solution for lacking of generic derivation of Arbitrary
1956−-- We use generics-sop, as it's much more concise than directly using GHC.Generics
1957−--
1958−-- This will be unneeded after https://github.com/nick8325/quickcheck/pull/112
1959−-- is merged and released
1960−sopArbitrary :: forall a. (Generic a, SOP.GTo a, SOP.All SOP.SListI (SOP.GCode a), SOP.All2 Arbitrary (SOP.GCode a)) => Gen a
1961−sopArbitrary = fmap SOP.gto sopArbitrary'
1962−
1963−sopArbitrary' :: forall xss. (SOP.All SOP.SListI xss, SOP.All2 Arbitrary xss) => Gen (SOP.SOP SOP.I xss)
1964−sopArbitrary' = SOP.hsequence =<< elements (SOP.apInjs_POP $ SOP.hcpure p arbitrary)
1965− where
1966− p :: Proxy Arbitrary
1967− p = Proxy