@@ -1,7 +1,10 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE DeriveGeneric #-}
1{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7+-- {-# LANGUAGE NoMonomorphismRestriction #-}
5{-# LANGUAGE NamedFieldPuns #-}
8{-# LANGUAGE NamedFieldPuns #-}
6{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE RecordWildCards #-}
@@ -10,11 +13,11 @@
10-------------------------------------------------------------------------------
13-------------------------------------------------------------------------------
12-- Module : Database.Bloodhound.Types
15-- Module : Database.Bloodhound.Types
13−-- Copyright : (C) 2014, 2018 Chris Allen
16+-- Copyright : (C) 2014, 2015, 2016 Chris Allen
14-- License : BSD-style (see the file LICENSE)
17-- License : BSD-style (see the file LICENSE)
15-- Maintainer : Chris Allen <cma@bitemyapp.com
18-- Maintainer : Chris Allen <cma@bitemyapp.com
16-- Stability : provisional
19-- Stability : provisional
17−-- Portability : RecordWildCards
20+-- Portability : DeriveGeneric, RecordWildCards
19-- Data types for describing actions and data structures performed to interact
22-- Data types for describing actions and data structures performed to interact
20-- with Elasticsearch. The two main buckets your queries against Elasticsearch
23-- with Elasticsearch. The two main buckets your queries against Elasticsearch
@@ -44,13 +47,10 @@ module Database.Bloodhound.Types
44 , mkDateHistogram
47 , mkDateHistogram
45 , mkCardinalityAggregation
48 , mkCardinalityAggregation
46 , mkDocVersion
49 , mkDocVersion
48− , mkExtendedStatsAggregation
49 , docVersionNumber
50 , docVersionNumber
50 , toMissing
51 , toMissing
52 , toDateHistogram
53 , toDateHistogram
54 , omitNulls
54 , omitNulls
@@ -62,7 +62,6 @@ module Database.Bloodhound.Types
62 , MonadBH(..)
62 , MonadBH(..)
63 , Version(..)
63 , Version(..)
64 , VersionNumber(..)
64 , VersionNumber(..)
66 , BuildHash(..)
65 , BuildHash(..)
67 , Status(..)
66 , Status(..)
68 , Existence(..)
67 , Existence(..)
@@ -71,7 +70,6 @@ module Database.Bloodhound.Types
71 , UpdatableIndexSetting(..)
70 , UpdatableIndexSetting(..)
72 , IndexSettingsSummary(..)
71 , IndexSettingsSummary(..)
73 , AllocationPolicy(..)
72 , AllocationPolicy(..)
75 , ReplicaBounds(..)
73 , ReplicaBounds(..)
76 , Bytes(..)
74 , Bytes(..)
77 , gigabytes
75 , gigabytes
@@ -120,8 +118,8 @@ module Database.Bloodhound.Types
120 , Pattern(..)
118 , Pattern(..)
121 , ShardResult(..)
119 , ShardResult(..)
122 , Hit(..)
120 , Hit(..)
124 , Filter(..)
121 , Filter(..)
125 , BoolMatch(..)
123 , BoolMatch(..)
126 , Term(..)
124 , Term(..)
127 , GeoPoint(..)
125 , GeoPoint(..)
@@ -148,22 +146,13 @@ module Database.Bloodhound.Types
148 , RegexpFlags(..)
146 , RegexpFlags(..)
149 , RegexpFlag(..)
147 , RegexpFlag(..)
150 , FieldName(..)
148 , FieldName(..)
154 , Script(..)
149 , Script(..)
155− , ScriptLanguage(..)
161 , IndexName(..)
150 , IndexName(..)
162 , IndexSelection(..)
151 , IndexSelection(..)
163 , NodeSelection(..)
152 , NodeSelection(..)
164 , NodeSelector(..)
153 , NodeSelector(..)
165− , ForceMergeIndexSettings(..)
154+ , IndexOptimizationSettings(..)
166− , defaultForceMergeIndexSettings
155+ , defaultIndexOptimizationSettings
167 , TemplateName(..)
156 , TemplateName(..)
168 , TemplatePattern(..)
157 , TemplatePattern(..)
169 , MappingName(..)
158 , MappingName(..)
@@ -187,19 +176,8 @@ module Database.Bloodhound.Types
187 , BoolQuery(..)
176 , BoolQuery(..)
188 , BoostingQuery(..)
177 , BoostingQuery(..)
189 , CommonTermsQuery(..)
178 , CommonTermsQuery(..)
190− , FunctionScoreQuery(..)
193− , FunctionScoreFunctions(..)
194− , ComponentFunctionScoreFunction(..)
195− , FunctionScoreFunction(..)
198− , FieldValueFactor(..)
200− , FactorModifier(..)
201− , FactorMissingFieldValue(..)
202 , DisMaxQuery(..)
179 , DisMaxQuery(..)
203 , FuzzyLikeThisQuery(..)
181 , FuzzyLikeThisQuery(..)
204 , FuzzyLikeFieldQuery(..)
182 , FuzzyLikeFieldQuery(..)
205 , FuzzyQuery(..)
183 , FuzzyQuery(..)
@@ -215,16 +193,10 @@ module Database.Bloodhound.Types
215 , RangeQuery(..)
193 , RangeQuery(..)
216 , RegexpQuery(..)
194 , RegexpQuery(..)
217 , QueryString(..)
195 , QueryString(..)
218− , TemplateQueryInline(..)
219− , TemplateQueryKeyValuePairs(..)
221 , BooleanOperator(..)
196 , BooleanOperator(..)
222 , ZeroTermsQuery(..)
197 , ZeroTermsQuery(..)
223 , CutoffFrequency(..)
198 , CutoffFrequency(..)
224 , Analyzer(..)
199 , Analyzer(..)
228 , MaxExpansions(..)
200 , MaxExpansions(..)
229 , Lenient(..)
201 , Lenient(..)
230 , MatchQueryType(..)
202 , MatchQueryType(..)
@@ -348,18 +320,6 @@ module Database.Bloodhound.Types
348 , rrGroupRefNum
320 , rrGroupRefNum
349 , mkRRGroupRefNum
321 , mkRRGroupRefNum
350 , RestoreIndexSettings(..)
322 , RestoreIndexSettings(..)
353− , PhraseSuggester(..)
354− , PhraseSuggesterHighlighter(..)
355− , PhraseSuggesterCollate(..)
357− , SuggestOptions(..)
358− , SuggestResponse(..)
359− , NamedSuggestionResponse(..)
360− , DirectGenerators(..)
361− , mkDirectGenerators
362− , DirectGeneratorSuggestModeTypes (..)
364 , Aggregation(..)
324 , Aggregation(..)
365 , Aggregations
325 , Aggregations
@@ -372,7 +332,6 @@ module Database.Bloodhound.Types
372 , ValueCountAggregation(..)
332 , ValueCountAggregation(..)
373 , FilterAggregation(..)
333 , FilterAggregation(..)
374 , CardinalityAggregation(..)
334 , CardinalityAggregation(..)
375− , MaxAggregation(..)
376 , DateHistogramAggregation(..)
335 , DateHistogramAggregation(..)
377 , DateRangeAggregation(..)
336 , DateRangeAggregation(..)
378 , DateRangeAggRange(..)
337 , DateRangeAggRange(..)
@@ -380,9 +339,6 @@ module Database.Bloodhound.Types
380 , DateMathAnchor(..)
339 , DateMathAnchor(..)
381 , DateMathModifier(..)
340 , DateMathModifier(..)
382 , DateMathUnit(..)
341 , DateMathUnit(..)
383− , TopHitsAggregation(..)
384− , StatisticsAggregation(..)
387 , Highlights(..)
343 , Highlights(..)
388 , FieldHighlight(..)
344 , FieldHighlight(..)
@@ -400,32 +356,724 @@ module Database.Bloodhound.Types
400 , TermsResult(..)
356 , TermsResult(..)
401 , DateHistogramResult(..)
357 , DateHistogramResult(..)
402 , DateRangeResult(..)
358 , DateRangeResult(..)
405 , EsUsername(..)
360 , EsUsername(..)
406 , EsPassword(..)
361 , EsPassword(..)
408− , Analysis(..)
364+import Control.Applicative as A
409− , AnalyzerDefinition(..)
365+import Control.Arrow (first)
410− , TokenizerDefinition(..)
366+import Control.Monad.Catch
411− , TokenFilterDefinition(..)
367+import Control.Monad.Except
412− , CharFilterDefinition(..)
368+import Control.Monad.Reader
413− , Ngram(..)
369+import Control.Monad.State
414− , TokenChar(..)
370+import Control.Monad.Writer
415− , Shingle(..)
371+import Data.Aeson
416− , Language(..)
372+import Data.Aeson.Types (Pair, Parser, emptyObject,
417− ) where
373+ parseEither, parseMaybe)
418−
374+import qualified Data.ByteString.Lazy.Char8 as L
419−import Bloodhound.Import
375+import Data.Char
420−
376+import Data.Hashable (Hashable)
421−import Database.Bloodhound.Internal.Aggregation
377+import qualified Data.HashMap.Strict as HM
422−import Database.Bloodhound.Internal.Analysis
378+import Data.List (foldl', intercalate, nub)
423−import Database.Bloodhound.Internal.Client
379+import Data.List.NonEmpty (NonEmpty (..), toList)
424−import Database.Bloodhound.Internal.Highlight
380+import qualified Data.Map.Strict as M
425−import Database.Bloodhound.Internal.Newtypes
381+import Data.Maybe
426−import Database.Bloodhound.Internal.Query
382+import Data.Scientific (Scientific)
427−import Database.Bloodhound.Internal.Sort
383+import Data.Text (Text)
428−import Database.Bloodhound.Internal.Suggest
384+import qualified Data.Text as T
385+import Data.Time.Calendar
386+import Data.Time.Clock (NominalDiffTime, UTCTime)
387+import Data.Time.Clock.POSIX
388+import qualified Data.Traversable as DT
389+import Data.Typeable (Typeable)
390+import qualified Data.Vector as V
391+import qualified Data.Version as Vers
393+import GHC.Generics (Generic)
394+import Network.HTTP.Client
395+import qualified Network.HTTP.Types.Method as NHTM
396+import qualified Text.ParserCombinators.ReadP as RP
397+import qualified Text.Read as TR
399+import Database.Bloodhound.Types.Class
400+import Database.Bloodhound.Types.Internal
403+-- >>> :set -XOverloadedStrings
404+-- >>> import Data.Aeson
405+-- >>> import Database.Bloodhound
406+-- >>> let testServer = (Server "http://localhost:9200")
407+-- >>> let testIndex = IndexName "twitter"
408+-- >>> let testMapping = MappingName "tweet"
409+-- >>> let defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
411+-- defaultIndexSettings is exported by Database.Bloodhound as well
412+-- no trailing slashes in servers, library handles building the path.
414+-- | Create a 'BHEnv' with all optional fields defaulted. HTTP hook
415+-- will be a noop. You can use the exported fields to customize it further, e.g.:
417+-- >> (mkBHEnv myServer myManager) { bhRequestHook = customHook }
418+mkBHEnv :: Server -> Manager -> BHEnv
419+mkBHEnv s m = BHEnv s m return
421+newtype BH m a = BH {
422+ unBH :: ReaderT BHEnv m a
423+ } deriving ( Functor
437+instance MonadTrans BH where
440+instance (MonadReader r m) => MonadReader r (BH m) where
442+ local f (BH (ReaderT m)) = BH $ ReaderT $ \r ->
445+instance (Functor m, Applicative m, MonadIO m) => MonadBH (BH m) where
446+ getBHEnv = BH getBHEnv
448+runBH :: BHEnv -> BH m a -> m a
449+runBH e f = runReaderT (unBH f) e
451+{-| 'Version' is embedded in 'Status' -}
452+data Version = Version { number :: VersionNumber
453+ , build_hash :: BuildHash
454+ , build_timestamp :: UTCTime
455+ , build_snapshot :: Bool
456+ , lucene_version :: VersionNumber } deriving (Eq, Read, Show, Generic, Typeable)
458+-- | Traditional software versioning number
459+newtype VersionNumber = VersionNumber { versionNumber :: Vers.Version
460+ } deriving (Eq, Read, Show, Generic, Typeable, Ord)
462+{-| 'Status' is a data type for describing the JSON body returned by
463+ Elasticsearch when you query its status. This was deprecated in 1.2.0.
465+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html#indices-status>
468+data Status = Status { ok :: Maybe Bool
471+ , version :: Version
472+ , tagline :: Text } deriving (Eq, Read, Show, Generic)
474+{-| 'IndexSettings' is used to configure the shards and replicas when you create
475+ an Elasticsearch Index.
477+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html>
481+ IndexSettings { indexShards :: ShardCount
482+ , indexReplicas :: ReplicaCount } deriving (Eq, Read, Show, Generic, Typeable)
484+{-| 'defaultIndexSettings' is an 'IndexSettings' with 3 shards and 2 replicas. -}
485+defaultIndexSettings :: IndexSettings
486+defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
489+{-| 'IndexOptimizationSettings' is used to configure index optimization. See
490+ <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-optimize.html>
493+data IndexOptimizationSettings =
494+ IndexOptimizationSettings { maxNumSegments :: Maybe Int
495+ -- ^ Number of segments to optimize to. 1 will fully optimize the index. If omitted, the default behavior is to only optimize if the server deems it necessary.
496+ , onlyExpungeDeletes :: Bool
497+ -- ^ Should the optimize process only expunge segments with deletes in them? If the purpose of the optimization is to free disk space, this should be set to True.
498+ , flushAfterOptimize :: Bool
499+ -- ^ Should a flush be performed after the optimize.
500+ } deriving (Eq, Show, Generic, Typeable)
503+{-| 'defaultIndexOptimizationSettings' implements the default settings that
504+ ElasticSearch uses for index optimization. 'maxNumSegments' is Nothing,
505+ 'onlyExpungeDeletes' is False, and flushAfterOptimize is True.
507+defaultIndexOptimizationSettings :: IndexOptimizationSettings
508+defaultIndexOptimizationSettings = IndexOptimizationSettings Nothing False True
510+{-| 'UpdatableIndexSetting' are settings which may be updated after an index is created.
512+ <https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html>
514+data UpdatableIndexSetting = NumberOfReplicas ReplicaCount
515+ -- ^ The number of replicas each shard has.
516+ | AutoExpandReplicas ReplicaBounds
517+ | BlocksReadOnly Bool
518+ -- ^ Set to True to have the index read only. False to allow writes and metadata changes.
520+ -- ^ Set to True to disable read operations against the index.
522+ -- ^ Set to True to disable write operations against the index.
523+ | BlocksMetaData Bool
524+ -- ^ Set to True to disable metadata operations against the index.
525+ | RefreshInterval NominalDiffTime
526+ -- ^ The async refresh interval of a shard
527+ | IndexConcurrency Int
528+ | FailOnMergeFailure Bool
529+ | TranslogFlushThresholdOps Int
530+ -- ^ When to flush on operations.
531+ | TranslogFlushThresholdSize Bytes
532+ -- ^ When to flush based on translog (bytes) size.
533+ | TranslogFlushThresholdPeriod NominalDiffTime
534+ -- ^ When to flush based on a period of not flushing.
535+ | TranslogDisableFlush Bool
536+ -- ^ Disables flushing. Note, should be set for a short interval and then enabled.
537+ | CacheFilterMaxSize (Maybe Bytes)
538+ -- ^ The maximum size of filter cache (per segment in shard).
539+ | CacheFilterExpire (Maybe NominalDiffTime)
540+ -- ^ The expire after access time for filter cache.
541+ | GatewaySnapshotInterval NominalDiffTime
542+ -- ^ The gateway snapshot interval (only applies to shared gateways).
543+ | RoutingAllocationInclude (NonEmpty NodeAttrFilter)
544+ -- ^ A node matching any rule will be allowed to host shards from the index.
545+ | RoutingAllocationExclude (NonEmpty NodeAttrFilter)
546+ -- ^ A node matching any rule will NOT be allowed to host shards from the index.
547+ | RoutingAllocationRequire (NonEmpty NodeAttrFilter)
548+ -- ^ Only nodes matching all rules will be allowed to host shards from the index.
549+ | RoutingAllocationEnable AllocationPolicy
550+ -- ^ Enables shard allocation for a specific index.
551+ | RoutingAllocationShardsPerNode ShardCount
552+ -- ^ Controls the total number of shards (replicas and primaries) allowed to be allocated on a single node.
553+ | RecoveryInitialShards InitialShardCount
554+ -- ^ When using local gateway a particular shard is recovered only if there can be allocated quorum shards in the cluster.
555+ | GCDeletes NominalDiffTime
556+ | TTLDisablePurge Bool
557+ -- ^ Disables temporarily the purge of expired docs.
558+ | TranslogFSType FSType
559+ | IndexCompoundFormat CompoundFormat
560+ | IndexCompoundOnFlush Bool
561+ | WarmerEnabled Bool
562+ deriving (Eq, Show, Generic, Typeable)
564+data AllocationPolicy = AllocAll
565+ -- ^ Allows shard allocation for all shards.
567+ -- ^ Allows shard allocation only for primary shards.
569+ -- ^ Allows shard allocation only for primary shards for new indices.
571+ -- ^ No shard allocation is allowed
572+ deriving (Eq, Read, Show, Generic, Typeable)
574+data ReplicaBounds = ReplicasBounded Int Int
575+ | ReplicasLowerBounded Int
577+ deriving (Eq, Read, Show, Generic, Typeable)
579+-- | A measure of bytes used for various configurations. You may want
580+-- to use smart constructors like 'gigabytes' for larger values.
590+newtype Bytes = Bytes Int deriving (Eq, Read, Show, Generic, Typeable, Ord, ToJSON, FromJSON)
592+gigabytes :: Int -> Bytes
593+gigabytes n = megabytes (1000 * n)
596+megabytes :: Int -> Bytes
597+megabytes n = kilobytes (1000 * n)
600+kilobytes :: Int -> Bytes
601+kilobytes n = Bytes (1000 * n)
604+data FSType = FSSimple
605+ | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
607+data InitialShardCount = QuorumShards
608+ | QuorumMinus1Shards
611+ | ExplicitShards Int
612+ deriving (Eq, Read, Show, Generic, Typeable)
614+data NodeAttrFilter = NodeAttrFilter { nodeAttrFilterName :: NodeAttrName
615+ , nodeAttrFilterValues :: NonEmpty Text}
616+ deriving (Eq, Read, Show, Generic, Ord, Typeable)
618+newtype NodeAttrName = NodeAttrName Text deriving (Eq, Read, Show, Ord, Generic, Typeable)
620+data CompoundFormat = CompoundFileFormat Bool
621+ | MergeSegmentVsTotalIndex Double
622+ -- ^ percentage between 0 and 1 where 0 is false, 1 is true
623+ deriving (Eq, Read, Show, Generic, Typeable)
625+newtype NominalDiffTimeJSON = NominalDiffTimeJSON { ndtJSON :: NominalDiffTime }
627+data IndexSettingsSummary = IndexSettingsSummary { sSummaryIndexName :: IndexName
628+ , sSummaryFixedSettings :: IndexSettings
629+ , sSummaryUpdateable :: [UpdatableIndexSetting]}
630+ deriving (Eq, Show, Generic, Typeable)
632+{-| 'Reply' and 'Method' are type synonyms from 'Network.HTTP.Types.Method.Method' -}
633+type Reply = Network.HTTP.Client.Response L.ByteString
634+type Method = NHTM.Method
636+{-| 'OpenCloseIndex' is a sum type for opening and closing indices.
638+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html>
640+data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Read, Show, Generic, Typeable)
642+data FieldType = GeoPointType
648+ | ByteType deriving (Eq, Read, Show, Generic, Typeable)
650+data FieldDefinition =
651+ FieldDefinition { fieldType :: FieldType } deriving (Eq, Read, Show, Generic, Typeable)
653+{-| An 'IndexTemplate' defines a template that will automatically be
654+ applied to new indices created. The templates include both
655+ 'IndexSettings' and mappings, and a simple 'TemplatePattern' that
656+ controls if the template will be applied to the index created.
657+ Specify mappings as follows: @[toJSON TweetMapping, ...]@
659+ https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
662+ IndexTemplate { templatePattern :: TemplatePattern
663+ , templateSettings :: Maybe IndexSettings
664+ , templateMappings :: [Value]
668+ MappingField { mappingFieldName :: FieldName
669+ , fieldDefinition :: FieldDefinition } deriving (Eq, Read, Show, Generic, Typeable)
671+{-| Support for type reification of 'Mapping's is currently incomplete, for
672+ now the mapping API verbiage expects a 'ToJSON'able blob.
674+ Indexes have mappings, mappings are schemas for the documents contained in the
675+ index. I'd recommend having only one mapping per index, always having a mapping,
676+ and keeping different kinds of documents separated if possible.
678+data Mapping = Mapping { typeName :: TypeName
679+ , mappingFields :: [MappingField] } deriving (Eq, Read, Show, Generic, Typeable)
681+{-| 'BulkOperation' is a sum type for expressing the four kinds of bulk
682+ operation index, create, delete, and update. 'BulkIndex' behaves like an
683+ "upsert", 'BulkCreate' will fail if a document already exists at the DocId.
685+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk>
688+ BulkIndex IndexName MappingName DocId Value
689+ | BulkCreate IndexName MappingName DocId Value
690+ | BulkDelete IndexName MappingName DocId
691+ | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Read, Show, Generic, Typeable)
693+{-| 'EsResult' describes the standard wrapper JSON document that you see in
694+ successful Elasticsearch lookups or lookups that couldn't find the document.
696+data EsResult a = EsResult { _index :: Text
699+ , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Read, Show, Generic, Typeable)
701+{-| 'EsResultFound' contains the document and its metadata inside of an
702+ 'EsResult' when the document was successfully found.
704+data EsResultFound a = EsResultFound { _version :: DocVersion
705+ , _source :: a } deriving (Eq, Read, Show, Generic, Typeable)
707+{-| 'EsError' is the generic type that will be returned when there was a
708+ problem. If you can't parse the expected response, its a good idea to
711+data EsError = EsError { errorStatus :: Int
712+ , errorMessage :: Text } deriving (Eq, Read, Show, Generic, Typeable)
714+{-| 'EsProtocolException' will be thrown if Bloodhound cannot parse a response
715+returned by the ElasticSearch server. If you encounter this error, please
716+verify that your domain data types and FromJSON instances are working properly
717+(for example, the 'a' of '[Hit a]' in 'SearchResult.searchHits.hits'). If you're
718+sure that your mappings are correct, then this error may be an indication of an
719+incompatibility between Bloodhound and ElasticSearch. Please open a bug report
720+and be sure to include the exception body.
722+data EsProtocolException = EsProtocolException { esProtoExBody :: L.ByteString }
723+ deriving (Eq, Read, Show, Generic, Typeable)
725+instance Exception EsProtocolException
727+data IndexAlias = IndexAlias { srcIndex :: IndexName
728+ , indexAlias :: IndexAliasName } deriving (Eq, Read, Show, Generic, Typeable)
730+newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Read, Show, Generic, ToJSON)
732+data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
733+ | RemoveAlias IndexAlias deriving (Read, Show, Eq, Generic, Typeable)
735+data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
736+ , aliasCreateFilter :: Maybe Filter}
737+ deriving (Read, Show, Eq, Generic, Typeable)
739+data AliasRouting = AllAliasRouting RoutingValue
740+ | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
741+ deriving (Read, Show, Eq, Generic, Typeable)
743+newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Read, Show, Eq, Generic, Typeable)
745+newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
747+newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
749+newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Read, Show, Eq, Generic, Typeable)
751+{-| 'IndexAliasSummary' is a summary of an index alias configured for a server. -}
752+data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
753+ , indexAliasSummaryCreate :: IndexAliasCreate} deriving (Read, Show, Eq, Generic, Typeable)
755+{-| 'DocVersion' is an integer version number for a document between 1
756+and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
758+newtype DocVersion = DocVersion {
759+ docVersionNumber :: Int
760+ } deriving (Eq, Read, Show, Generic, Ord, ToJSON)
762+-- | Smart constructor for in-range doc version
763+mkDocVersion :: Int -> Maybe DocVersion
765+ | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
767+ | otherwise = Nothing
770+{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
771+own version numbers instead of ones from ES.
773+newtype ExternalDocVersion = ExternalDocVersion DocVersion
774+ deriving (Eq, Read, Show, Generic, Ord, Bounded, Enum, ToJSON)
776+{-| 'VersionControl' is specified when indexing documents as a
777+optimistic concurrency control.
779+data VersionControl = NoVersionControl
780+ -- ^ Don't send a version. This is a pure overwrite.
781+ | InternalVersion DocVersion
782+ -- ^ Use the default ES versioning scheme. Only
783+ -- index the document if the version is the same
784+ -- as the one specified. Only applicable to
785+ -- updates, as you should be getting Version from
787+ | ExternalGT ExternalDocVersion
788+ -- ^ Use your own version numbering. Only index
789+ -- the document if the version is strictly higher
790+ -- OR the document doesn't exist. The given
791+ -- version will be used as the new version number
792+ -- for the stored document. N.B. All updates must
793+ -- increment this number, meaning there is some
794+ -- global, external ordering of updates.
795+ | ExternalGTE ExternalDocVersion
796+ -- ^ Use your own version numbering. Only index
797+ -- the document if the version is equal or higher
798+ -- than the stored version. Will succeed if there
799+ -- is no existing document. The given version will
800+ -- be used as the new version number for the
801+ -- stored document. Use with care, as this could
802+ -- result in data loss.
803+ | ForceVersion ExternalDocVersion
804+ -- ^ The document will always be indexed and the
805+ -- given version will be the new version. This is
806+ -- typically used for correcting errors. Use with
807+ -- care, as this could result in data loss.
808+ deriving (Read, Show, Eq, Generic, Ord)
810+{-| 'DocumentParent' is used to specify a parent document.
812+newtype DocumentParent = DocumentParent DocId
813+ deriving (Eq, Read, Show, Generic, Typeable)
815+{-| 'IndexDocumentSettings' are special settings supplied when indexing
816+a document. For the best backwards compatiblity when new fields are
817+added, you should probably prefer to start with 'defaultIndexDocumentSettings'
819+data IndexDocumentSettings =
820+ IndexDocumentSettings { idsVersionControl :: VersionControl
821+ , idsParent :: Maybe DocumentParent
822+ } deriving (Eq, Read, Show, Generic, Typeable)
824+{-| Reasonable default settings. Chooses no version control and no parent.
826+defaultIndexDocumentSettings :: IndexDocumentSettings
827+defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl Nothing
829+{-| 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order
830+ dependent with later sorts acting as tie-breakers for earlier sorts.
832+type Sort = [SortSpec]
834+{-| The two main kinds of 'SortSpec' are 'DefaultSortSpec' and
835+ 'GeoDistanceSortSpec'. The latter takes a 'SortOrder', 'GeoPoint', and
836+ 'DistanceUnit' to express "nearness" to a single geographical point as a
839+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
841+data SortSpec = DefaultSortSpec DefaultSort
842+ | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Read, Show, Generic, Typeable)
844+{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
845+ 'mkSort' convenience function for when you want to specify only the most
848+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
851+ DefaultSort { sortFieldName :: FieldName
852+ , sortOrder :: SortOrder
854+ , ignoreUnmapped :: Bool
855+ , sortMode :: Maybe SortMode
856+ , missingSort :: Maybe Missing
857+ , nestedFilter :: Maybe Filter } deriving (Eq, Read, Show, Generic, Typeable)
859+{-| 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
860+ encoded into "asc" or "desc" when turned into JSON.
862+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
864+data SortOrder = Ascending
865+ | Descending deriving (Eq, Read, Show, Generic, Typeable)
867+{-| 'Missing' prescribes how to handle missing fields. A missing field can be
868+ sorted last, first, or using a custom value as a substitute.
870+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_missing_values>
872+data Missing = LastMissing
874+ | CustomMissing Text deriving (Eq, Read, Show, Generic, Typeable)
876+{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
878+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
880+data SortMode = SortMin
883+ | SortAvg deriving (Eq, Read, Show, Generic, Typeable)
885+{-| 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so
886+ that you can concisely describe the usual kind of 'SortSpec's you want.
888+mkSort :: FieldName -> SortOrder -> DefaultSort
889+mkSort fieldName sOrder = DefaultSort fieldName sOrder False Nothing Nothing Nothing
891+{-| 'Cache' is for telling ES whether it should cache a 'Filter' not.
892+ 'Query's cannot be cached.
894+type Cache = Bool -- caching on/off
895+defaultCache :: Cache
898+{-| 'PrefixValue' is used in 'PrefixQuery' as the main query component.
900+type PrefixValue = Text
902+{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
903+ JSON encoding baked in. Used all over the place.
905+data BooleanOperator = And | Or deriving (Eq, Read, Show, Generic, Typeable)
907+{-| 'ShardCount' is part of 'IndexSettings'
909+newtype ShardCount = ShardCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
911+{-| 'ReplicaCount' is part of 'IndexSettings'
913+newtype ReplicaCount = ReplicaCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
915+{-| 'IndexName' is used to describe which index to query/create/delete
917+newtype IndexName = IndexName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
919+{-| 'IndexSelection' is used for APIs which take a single index, a list of
920+ indexes, or the special @_all@ index.
922+--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.
923+data IndexSelection = IndexList (NonEmpty IndexName)
924+ | AllIndexes deriving (Eq, Generic, Show, Typeable)
926+{-| '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.
928+data NodeSelection = LocalNode
929+ -- ^ Whatever node receives this request
930+ | NodeList (NonEmpty NodeSelector)
931+ | AllNodes deriving (Eq, Generic, Show, Typeable)
934+-- | An exact match or pattern to identify a node. Note that All of
935+-- these options support wildcarding, so your node name, server, attr
936+-- name can all contain * characters to be a fuzzy match.
937+data NodeSelector = NodeByName NodeName
938+ | NodeByFullNodeId FullNodeId
940+ -- ^ e.g. 10.0.0.1 or even 10.0.0.*
941+ | NodeByAttribute NodeAttrName Text
942+ -- ^ NodeAttrName can be a pattern, e.g. rack*. The value can too.
943+ deriving (Eq, Generic, Show, Typeable)
945+{-| 'TemplateName' is used to describe which template to query/create/delete
947+newtype TemplateName = TemplateName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
949+{-| 'TemplatePattern' represents a pattern which is matched against index names
951+newtype TemplatePattern = TemplatePattern Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
953+{-| 'MappingName' is part of mappings which are how ES describes and schematizes
954+ the data in the indices.
956+newtype MappingName = MappingName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
958+{-| 'DocId' is a generic wrapper value for expressing unique Document IDs.
959+ Can be set by the user or created by ES itself. Often used in client
960+ functions for poking at specific documents.
962+newtype DocId = DocId Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
964+{-| 'QueryString' is used to wrap query text bodies, be they human written or not.
966+newtype QueryString = QueryString Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
968+{-| 'FieldName' is used all over the place wherever a specific field within
969+ a document needs to be specified, usually in 'Query's or 'Filter's.
971+newtype FieldName = FieldName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
974+{-| 'Script' is often used in place of 'FieldName' to specify more
975+complex ways of extracting a value from a document.
977+newtype Script = Script { scriptText :: Text } deriving (Eq, Read, Show, Generic, Typeable)
979+{-| 'CacheName' is used in 'RegexpFilter' for describing the
980+ 'CacheKey' keyed caching behavior.
982+newtype CacheName = CacheName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
984+{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
987+ CacheKey Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
989+ Existence Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
991+ NullValue Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
992+newtype CutoffFrequency =
993+ CutoffFrequency Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
995+ Analyzer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
996+newtype MaxExpansions =
997+ MaxExpansions Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
999+{-| 'Lenient', if set to true, will cause format based failures to be
1000+ ignored. I don't know what the bloody default is, Elasticsearch
1001+ documentation didn't say what it was. Let me know if you figure it out.
1004+ Lenient Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1005+newtype Tiebreaker =
1006+ Tiebreaker Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1008+ Boost Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1009+newtype BoostTerms =
1010+ BoostTerms Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1012+{-| 'MinimumMatch' controls how many should clauses in the bool query should
1013+ match. Can be an absolute value (2) or a percentage (30%) or a
1014+ combination of both.
1016+newtype MinimumMatch =
1017+ MinimumMatch Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1018+newtype DisableCoord =
1019+ DisableCoord Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1020+newtype IgnoreTermFrequency =
1021+ IgnoreTermFrequency Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1022+newtype MinimumTermFrequency =
1023+ MinimumTermFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1024+newtype MaxQueryTerms =
1025+ MaxQueryTerms Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1027+ Fuzziness Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1029+{-| 'PrefixLength' is the prefix length used in queries, defaults to 0. -}
1030+newtype PrefixLength =
1031+ PrefixLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1033+ TypeName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1034+newtype PercentMatch =
1035+ PercentMatch Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1037+ StopWord Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1039+ QueryPath Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1041+{-| Allowing a wildcard at the beginning of a word (eg "*ing") is particularly
1042+ heavy, because all terms in the index need to be examined, just in case
1043+ they match. Leading wildcards can be disabled by setting
1044+ 'AllowLeadingWildcard' to false. -}
1045+newtype AllowLeadingWildcard =
1046+ AllowLeadingWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1047+newtype LowercaseExpanded =
1048+ LowercaseExpanded Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1049+newtype EnablePositionIncrements =
1050+ EnablePositionIncrements Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1052+{-| By default, wildcard terms in a query are not analyzed.
1053+ Setting 'AnalyzeWildcard' to true enables best-effort analysis.
1055+newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1057+{-| 'GeneratePhraseQueries' defaults to false.
1059+newtype GeneratePhraseQueries =
1060+ GeneratePhraseQueries Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1062+{-| 'Locale' is used for string conversions - defaults to ROOT.
1064+newtype Locale = Locale Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1065+newtype MaxWordLength = MaxWordLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1066+newtype MinWordLength = MinWordLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1068+{-| 'PhraseSlop' sets the default slop for phrases, 0 means exact
1069+ phrase matches. Default is 0.
1071+newtype PhraseSlop = PhraseSlop Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1072+newtype MinDocFrequency = MinDocFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1073+newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1075+-- | Newtype wrapper to parse ES's concerning tendency to in some APIs return a floating point number of milliseconds since epoch ಠ_ಠ
1076+newtype POSIXMS = POSIXMS { posixMS :: UTCTime }
430{-| 'unpackId' is a silly convenience function that gets used once.
1078{-| 'unpackId' is a silly convenience function that gets used once.
@@ -433,6 +1081,8 @@ unpackId :: DocId -> Text
433unpackId (DocId docId) = docId
1081unpackId (DocId docId) = docId
435type TrackSortScores = Bool
1083type TrackSortScores = Bool
1084+newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
1085+newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON)
437data Search = Search { queryBody :: Maybe Query
1087data Search = Search { queryBody :: Maybe Query
438 , filterBody :: Maybe Filter
1088 , filterBody :: Maybe Filter
@@ -444,74 +1094,537 @@ data Search = Search { queryBody :: Maybe Query
444 , from :: From
1094 , from :: From
445 , size :: Size
1095 , size :: Size
446 , searchType :: SearchType
1096 , searchType :: SearchType
447− , searchAfterKey :: Maybe SearchAfterKey
448 , fields :: Maybe [FieldName]
1097 , fields :: Maybe [FieldName]
449− , scriptFields :: Maybe ScriptFields
450− , source :: Maybe Source
1098+ , source :: Maybe Source } deriving (Eq, Read, Show, Generic, Typeable)
451− , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
452− } deriving (Eq, Show)
455−instance ToJSON Search where
456− toJSON (Search mquery sFilter sort searchAggs
457− highlight sTrackSortScores sFrom sSize _ sAfter sFields
458− sScriptFields sSource sSuggest) =
459− omitNulls [ "query" .= query'
461− , "aggregations" .= searchAggs
462− , "highlight" .= highlight
465− , "track_scores" .= sTrackSortScores
466− , "search_after" .= sAfter
467− , "fields" .= sFields
468− , "script_fields" .= sScriptFields
469− , "_source" .= sSource
470− , "suggest" .= sSuggest]
472− where query' = case sFilter of
477− $ mkBoolQuery (maybeToList mquery)
480data SearchType = SearchTypeQueryThenFetch
1100data SearchType = SearchTypeQueryThenFetch
481 | SearchTypeDfsQueryThenFetch
1101 | SearchTypeDfsQueryThenFetch
1104+ | SearchTypeQueryAndFetch
1105+ | SearchTypeDfsQueryAndFetch
482− deriving (Eq, Show)
1106+ deriving (Eq, Read, Show, Generic, Typeable)
484data Source =
1108data Source =
485 NoSource
1109 NoSource
486 | SourcePatterns PatternOrPatterns
1110 | SourcePatterns PatternOrPatterns
487 | SourceIncludeExclude Include Exclude
1111 | SourceIncludeExclude Include Exclude
488− deriving (Eq, Show)
1112+ deriving (Read, Show, Eq, Generic, Typeable)
490−instance ToJSON Source where
491− toJSON NoSource = toJSON False
492− toJSON (SourcePatterns patterns) = toJSON patterns
493− toJSON (SourceIncludeExclude incl excl) = object [ "includes" .= incl, "excludes" .= excl ]
495data PatternOrPatterns = PopPattern Pattern
1114data PatternOrPatterns = PopPattern Pattern
496− | PopPatterns [Pattern] deriving (Eq, Read, Show)
1115+ | PopPatterns [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
498−instance ToJSON PatternOrPatterns where
1117+data Include = Include [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
499− toJSON (PopPattern pattern) = toJSON pattern
1118+data Exclude = Exclude [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
500− toJSON (PopPatterns patterns) = toJSON patterns
502−data Include = Include [Pattern] deriving (Eq, Read, Show)
1120+newtype Pattern = Pattern Text deriving (Eq, Read, Show, Generic, Typeable)
503−data Exclude = Exclude [Pattern] deriving (Eq, Read, Show)
505−instance ToJSON Include where
1122+data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
506− toJSON (Include patterns) = toJSON patterns
1123+ , highlightFields :: [FieldHighlight]
1124+ } deriving (Read, Show, Eq, Generic, Typeable)
508−instance ToJSON Exclude where
1126+data FieldHighlight = FieldHighlight FieldName (Maybe HighlightSettings)
509− toJSON (Exclude patterns) = toJSON patterns
1127+ deriving (Read, Show, Eq, Generic, Typeable)
511−newtype Pattern = Pattern Text deriving (Eq, Read, Show)
513−instance ToJSON Pattern where
1130+data HighlightSettings = Plain PlainHighlight
514− toJSON (Pattern pattern) = toJSON pattern
1131+ | Postings PostingsHighlight
1132+ | FastVector FastVectorHighlight
1133+ deriving (Read, Show, Eq, Generic, Typeable)
1134+data PlainHighlight =
1135+ PlainHighlight { plainCommon :: Maybe CommonHighlight
1136+ , plainNonPost :: Maybe NonPostings } deriving (Read, Show, Eq, Generic, Typeable)
1138+ -- This requires that index_options are set to 'offset' in the mapping.
1139+data PostingsHighlight = PostingsHighlight (Maybe CommonHighlight) deriving (Read, Show, Eq, Generic, Typeable)
1141+-- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
1142+data FastVectorHighlight =
1143+ FastVectorHighlight { fvCommon :: Maybe CommonHighlight
1144+ , fvNonPostSettings :: Maybe NonPostings
1145+ , boundaryChars :: Maybe Text
1146+ , boundaryMaxScan :: Maybe Int
1147+ , fragmentOffset :: Maybe Int
1148+ , matchedFields :: [Text]
1149+ , phraseLimit :: Maybe Int
1150+ } deriving (Read, Show, Eq, Generic, Typeable)
1152+data CommonHighlight =
1153+ CommonHighlight { order :: Maybe Text
1154+ , forceSource :: Maybe Bool
1155+ , tag :: Maybe HighlightTag
1156+ , encoder :: Maybe HighlightEncoder
1157+ , noMatchSize :: Maybe Int
1158+ , highlightQuery :: Maybe Query
1159+ , requireFieldMatch :: Maybe Bool
1160+ } deriving (Read, Show, Eq, Generic, Typeable)
1162+-- Settings that are only applicable to FastVector and Plain highlighters.
1164+ NonPostings { fragmentSize :: Maybe Int
1165+ , numberOfFragments :: Maybe Int} deriving (Read, Show, Eq, Generic, Typeable)
1167+data HighlightEncoder = DefaultEncoder
1169+ deriving (Read, Show, Eq, Generic, Typeable)
1171+-- NOTE: Should the tags use some kind of HTML type, rather than Text?
1172+data HighlightTag = TagSchema Text
1173+ | CustomTags ([Text], [Text]) -- Only uses more than the first value in the lists if fvh
1174+ deriving (Read, Show, Eq, Generic, Typeable)
1178+ TermQuery Term (Maybe Boost)
1179+ | TermsQuery Text (NonEmpty Text)
1180+ | QueryMatchQuery MatchQuery
1181+ | QueryMultiMatchQuery MultiMatchQuery
1182+ | QueryBoolQuery BoolQuery
1183+ | QueryBoostingQuery BoostingQuery
1184+ | QueryCommonTermsQuery CommonTermsQuery
1185+ | ConstantScoreFilter Filter Boost
1186+ | ConstantScoreQuery Query Boost
1187+ | QueryDisMaxQuery DisMaxQuery
1188+ | QueryFilteredQuery FilteredQuery
1189+ | QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
1190+ | QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
1191+ | QueryFuzzyQuery FuzzyQuery
1192+ | QueryHasChildQuery HasChildQuery
1193+ | QueryHasParentQuery HasParentQuery
1194+ | IdsQuery MappingName [DocId]
1195+ | QueryIndicesQuery IndicesQuery
1196+ | MatchAllQuery (Maybe Boost)
1197+ | QueryMoreLikeThisQuery MoreLikeThisQuery
1198+ | QueryMoreLikeThisFieldQuery MoreLikeThisFieldQuery
1199+ | QueryNestedQuery NestedQuery
1200+ | QueryPrefixQuery PrefixQuery
1201+ | QueryQueryStringQuery QueryStringQuery
1202+ | QuerySimpleQueryStringQuery SimpleQueryStringQuery
1203+ | QueryRangeQuery RangeQuery
1204+ | QueryRegexpQuery RegexpQuery
1205+ deriving (Eq, Read, Show, Generic, Typeable)
1208+ RegexpQuery { regexpQueryField :: FieldName
1209+ , regexpQuery :: Regexp
1210+ , regexpQueryFlags :: RegexpFlags
1211+ , regexpQueryBoost :: Maybe Boost
1212+ } deriving (Eq, Read, Show, Generic, Typeable)
1215+ RangeQuery { rangeQueryField :: FieldName
1216+ , rangeQueryRange :: RangeValue
1217+ , rangeQueryBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1219+mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
1220+mkRangeQuery f r = RangeQuery f r (Boost 1.0)
1222+data SimpleQueryStringQuery =
1223+ SimpleQueryStringQuery
1224+ { simpleQueryStringQuery :: QueryString
1225+ , simpleQueryStringField :: Maybe FieldOrFields
1226+ , simpleQueryStringOperator :: Maybe BooleanOperator
1227+ , simpleQueryStringAnalyzer :: Maybe Analyzer
1228+ , simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag)
1229+ , simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded
1230+ , simpleQueryStringLocale :: Maybe Locale
1231+ } deriving (Eq, Read, Show, Generic, Typeable)
1233+data SimpleQueryFlag =
1238+ | SimpleQueryPrefix
1239+ | SimpleQueryPhrase
1240+ | SimpleQueryPrecedence
1241+ | SimpleQueryEscape
1242+ | SimpleQueryWhitespace
1245+ | SimpleQuerySlop deriving (Eq, Read, Show, Generic, Typeable)
1247+-- use_dis_max and tie_breaker when fields are plural?
1248+data QueryStringQuery =
1250+ { queryStringQuery :: QueryString
1251+ , queryStringDefaultField :: Maybe FieldName
1252+ , queryStringOperator :: Maybe BooleanOperator
1253+ , queryStringAnalyzer :: Maybe Analyzer
1254+ , queryStringAllowLeadingWildcard :: Maybe AllowLeadingWildcard
1255+ , queryStringLowercaseExpanded :: Maybe LowercaseExpanded
1256+ , queryStringEnablePositionIncrements :: Maybe EnablePositionIncrements
1257+ , queryStringFuzzyMaxExpansions :: Maybe MaxExpansions
1258+ , queryStringFuzziness :: Maybe Fuzziness
1259+ , queryStringFuzzyPrefixLength :: Maybe PrefixLength
1260+ , queryStringPhraseSlop :: Maybe PhraseSlop
1261+ , queryStringBoost :: Maybe Boost
1262+ , queryStringAnalyzeWildcard :: Maybe AnalyzeWildcard
1263+ , queryStringGeneratePhraseQueries :: Maybe GeneratePhraseQueries
1264+ , queryStringMinimumShouldMatch :: Maybe MinimumMatch
1265+ , queryStringLenient :: Maybe Lenient
1266+ , queryStringLocale :: Maybe Locale
1267+ } deriving (Eq, Read, Show, Generic, Typeable)
1269+mkQueryStringQuery :: QueryString -> QueryStringQuery
1270+mkQueryStringQuery qs =
1271+ QueryStringQuery qs Nothing Nothing
1272+ Nothing Nothing Nothing Nothing
1273+ Nothing Nothing Nothing Nothing
1274+ Nothing Nothing Nothing Nothing
1277+data FieldOrFields = FofField FieldName
1278+ | FofFields (NonEmpty FieldName) deriving (Eq, Read, Show, Generic, Typeable)
1282+ { prefixQueryField :: FieldName
1283+ , prefixQueryPrefixValue :: Text
1284+ , prefixQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1288+ { nestedQueryPath :: QueryPath
1289+ , nestedQueryScoreType :: ScoreType
1290+ , nestedQuery :: Query } deriving (Eq, Read, Show, Generic, Typeable)
1292+data MoreLikeThisFieldQuery =
1293+ MoreLikeThisFieldQuery
1294+ { moreLikeThisFieldText :: Text
1295+ , moreLikeThisFieldFields :: FieldName
1296+ -- default 0.3 (30%)
1297+ , moreLikeThisFieldPercentMatch :: Maybe PercentMatch
1298+ , moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency
1299+ , moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms
1300+ , moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord)
1301+ , moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency
1302+ , moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency
1303+ , moreLikeThisFieldMinWordLength :: Maybe MinWordLength
1304+ , moreLikeThisFieldMaxWordLength :: Maybe MaxWordLength
1305+ , moreLikeThisFieldBoostTerms :: Maybe BoostTerms
1306+ , moreLikeThisFieldBoost :: Maybe Boost
1307+ , moreLikeThisFieldAnalyzer :: Maybe Analyzer
1308+ } deriving (Eq, Read, Show, Generic, Typeable)
1310+data MoreLikeThisQuery =
1312+ { moreLikeThisText :: Text
1313+ , moreLikeThisFields :: Maybe (NonEmpty FieldName)
1314+ -- default 0.3 (30%)
1315+ , moreLikeThisPercentMatch :: Maybe PercentMatch
1316+ , moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency
1317+ , moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms
1318+ , moreLikeThisStopWords :: Maybe (NonEmpty StopWord)
1319+ , moreLikeThisMinDocFrequency :: Maybe MinDocFrequency
1320+ , moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency
1321+ , moreLikeThisMinWordLength :: Maybe MinWordLength
1322+ , moreLikeThisMaxWordLength :: Maybe MaxWordLength
1323+ , moreLikeThisBoostTerms :: Maybe BoostTerms
1324+ , moreLikeThisBoost :: Maybe Boost
1325+ , moreLikeThisAnalyzer :: Maybe Analyzer
1326+ } deriving (Eq, Read, Show, Generic, Typeable)
1330+ { indicesQueryIndices :: [IndexName]
1331+ , indicesQuery :: Query
1333+ , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Read, Show, Generic, Typeable)
1335+data HasParentQuery =
1337+ { hasParentQueryType :: TypeName
1338+ , hasParentQuery :: Query
1339+ , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1341+data HasChildQuery =
1343+ { hasChildQueryType :: TypeName
1344+ , hasChildQuery :: Query
1345+ , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1351+ | ScoreTypeNone deriving (Eq, Read, Show, Generic, Typeable)
1354+ FuzzyQuery { fuzzyQueryField :: FieldName
1355+ , fuzzyQueryValue :: Text
1356+ , fuzzyQueryPrefixLength :: PrefixLength
1357+ , fuzzyQueryMaxExpansions :: MaxExpansions
1358+ , fuzzyQueryFuzziness :: Fuzziness
1359+ , fuzzyQueryBoost :: Maybe Boost
1360+ } deriving (Eq, Read, Show, Generic, Typeable)
1362+data FuzzyLikeFieldQuery =
1363+ FuzzyLikeFieldQuery
1364+ { fuzzyLikeField :: FieldName
1365+ -- anaphora is good for the soul.
1366+ , fuzzyLikeFieldText :: Text
1367+ , fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms
1368+ , fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency
1369+ , fuzzyLikeFieldFuzziness :: Fuzziness
1370+ , fuzzyLikeFieldPrefixLength :: PrefixLength
1371+ , fuzzyLikeFieldBoost :: Boost
1372+ , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
1373+ } deriving (Eq, Read, Show, Generic, Typeable)
1375+data FuzzyLikeThisQuery =
1377+ { fuzzyLikeFields :: [FieldName]
1378+ , fuzzyLikeText :: Text
1379+ , fuzzyLikeMaxQueryTerms :: MaxQueryTerms
1380+ , fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency
1381+ , fuzzyLikeFuzziness :: Fuzziness
1382+ , fuzzyLikePrefixLength :: PrefixLength
1383+ , fuzzyLikeBoost :: Boost
1384+ , fuzzyLikeAnalyzer :: Maybe Analyzer
1385+ } deriving (Eq, Read, Show, Generic, Typeable)
1387+data FilteredQuery =
1389+ { filteredQuery :: Query
1390+ , filteredFilter :: Filter } deriving (Eq, Read, Show, Generic, Typeable)
1393+ DisMaxQuery { disMaxQueries :: [Query]
1395+ , disMaxTiebreaker :: Tiebreaker
1396+ , disMaxBoost :: Maybe Boost
1397+ } deriving (Eq, Read, Show, Generic, Typeable)
1400+ MatchQuery { matchQueryField :: FieldName
1401+ , matchQueryQueryString :: QueryString
1402+ , matchQueryOperator :: BooleanOperator
1403+ , matchQueryZeroTerms :: ZeroTermsQuery
1404+ , matchQueryCutoffFrequency :: Maybe CutoffFrequency
1405+ , matchQueryMatchType :: Maybe MatchQueryType
1406+ , matchQueryAnalyzer :: Maybe Analyzer
1407+ , matchQueryMaxExpansions :: Maybe MaxExpansions
1408+ , matchQueryLenient :: Maybe Lenient
1409+ , matchQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1411+{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
1412+ enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
1414+mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1415+mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1417+data MatchQueryType =
1419+ | MatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
1421+data MultiMatchQuery =
1422+ MultiMatchQuery { multiMatchQueryFields :: [FieldName]
1423+ , multiMatchQueryString :: QueryString
1424+ , multiMatchQueryOperator :: BooleanOperator
1425+ , multiMatchQueryZeroTerms :: ZeroTermsQuery
1426+ , multiMatchQueryTiebreaker :: Maybe Tiebreaker
1427+ , multiMatchQueryType :: Maybe MultiMatchQueryType
1428+ , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
1429+ , multiMatchQueryAnalyzer :: Maybe Analyzer
1430+ , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
1431+ , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Read, Show, Generic, Typeable)
1433+{-| 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
1434+ enabling you to provide only the list of 'FieldName's and 'QueryString' to
1435+ make a 'MultiMatchQuery'.
1438+mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
1439+mkMultiMatchQuery matchFields query =
1440+ MultiMatchQuery matchFields query
1441+ Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1443+data MultiMatchQueryType =
1444+ MultiMatchBestFields
1445+ | MultiMatchMostFields
1446+ | MultiMatchCrossFields
1448+ | MultiMatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
1451+ BoolQuery { boolQueryMustMatch :: [Query]
1452+ , boolQueryMustNotMatch :: [Query]
1453+ , boolQueryShouldMatch :: [Query]
1454+ , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
1455+ , boolQueryBoost :: Maybe Boost
1456+ , boolQueryDisableCoord :: Maybe DisableCoord
1457+ } deriving (Eq, Read, Show, Generic, Typeable)
1459+mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
1460+mkBoolQuery must mustNot should =
1461+ BoolQuery must mustNot should Nothing Nothing Nothing
1463+data BoostingQuery =
1464+ BoostingQuery { positiveQuery :: Query
1465+ , negativeQuery :: Query
1466+ , negativeBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1468+data CommonTermsQuery =
1469+ CommonTermsQuery { commonField :: FieldName
1470+ , commonQuery :: QueryString
1471+ , commonCutoffFrequency :: CutoffFrequency
1472+ , commonLowFreqOperator :: BooleanOperator
1473+ , commonHighFreqOperator :: BooleanOperator
1474+ , commonMinimumShouldMatch :: Maybe CommonMinimumMatch
1475+ , commonBoost :: Maybe Boost
1476+ , commonAnalyzer :: Maybe Analyzer
1477+ , commonDisableCoord :: Maybe DisableCoord
1478+ } deriving (Eq, Read, Show, Generic, Typeable)
1480+data CommonMinimumMatch =
1481+ CommonMinimumMatchHighLow MinimumMatchHighLow
1482+ | CommonMinimumMatch MinimumMatch
1483+ deriving (Eq, Read, Show, Generic, Typeable)
1485+data MinimumMatchHighLow =
1486+ MinimumMatchHighLow { lowFreq :: MinimumMatch
1487+ , highFreq :: MinimumMatch } deriving (Eq, Read, Show, Generic, Typeable)
1489+data Filter = AndFilter [Filter] Cache
1490+ | OrFilter [Filter] Cache
1491+ | NotFilter Filter Cache
1493+ | BoolFilter BoolMatch
1494+ | ExistsFilter FieldName -- always cached
1495+ | GeoBoundingBoxFilter GeoBoundingBoxConstraint
1496+ | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
1497+ | GeoDistanceRangeFilter GeoPoint DistanceRange
1498+ | GeoPolygonFilter FieldName [LatLon]
1499+ | IdsFilter MappingName [DocId]
1501+ | MissingFilter FieldName Existence NullValue
1502+ | PrefixFilter FieldName PrefixValue Cache
1503+ | QueryFilter Query Cache
1504+ | RangeFilter FieldName RangeValue RangeExecution Cache
1505+ | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
1506+ | TermFilter Term Cache
1507+ deriving (Eq, Read, Show, Generic, Typeable)
1509+data ZeroTermsQuery = ZeroTermsNone
1510+ | ZeroTermsAll deriving (Eq, Read, Show, Generic, Typeable)
1512+data RangeExecution = RangeExecutionIndex
1513+ | RangeExecutionFielddata deriving (Eq, Read, Show, Generic, Typeable)
1515+newtype Regexp = Regexp Text deriving (Eq, Read, Show, Generic, Typeable, FromJSON)
1517+data RegexpFlags = AllRegexpFlags
1519+ | SomeRegexpFlags (NonEmpty RegexpFlag) deriving (Eq, Read, Show, Generic, Typeable)
1521+data RegexpFlag = AnyString
1526+ | Interval deriving (Eq, Read, Show, Generic, Typeable)
1528+newtype LessThan = LessThan Double deriving (Eq, Read, Show, Generic, Typeable)
1529+newtype LessThanEq = LessThanEq Double deriving (Eq, Read, Show, Generic, Typeable)
1530+newtype GreaterThan = GreaterThan Double deriving (Eq, Read, Show, Generic, Typeable)
1531+newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Read, Show, Generic, Typeable)
1533+newtype LessThanD = LessThanD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1534+newtype LessThanEqD = LessThanEqD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1535+newtype GreaterThanD = GreaterThanD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1536+newtype GreaterThanEqD = GreaterThanEqD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1538+data RangeValue = RangeDateLte LessThanEqD
1539+ | RangeDateLt LessThanD
1540+ | RangeDateGte GreaterThanEqD
1541+ | RangeDateGt GreaterThanD
1542+ | RangeDateGtLt GreaterThanD LessThanD
1543+ | RangeDateGteLte GreaterThanEqD LessThanEqD
1544+ | RangeDateGteLt GreaterThanEqD LessThanD
1545+ | RangeDateGtLte GreaterThanD LessThanEqD
1546+ | RangeDoubleLte LessThanEq
1547+ | RangeDoubleLt LessThan
1548+ | RangeDoubleGte GreaterThanEq
1549+ | RangeDoubleGt GreaterThan
1550+ | RangeDoubleGtLt GreaterThan LessThan
1551+ | RangeDoubleGteLte GreaterThanEq LessThanEq
1552+ | RangeDoubleGteLt GreaterThanEq LessThan
1553+ | RangeDoubleGtLte GreaterThan LessThanEq
1554+ deriving (Eq, Read, Show, Generic, Typeable)
1556+rangeValueToPair :: RangeValue -> [Pair]
1557+rangeValueToPair rv = case rv of
1558+ RangeDateLte (LessThanEqD t) -> ["lte" .= t]
1559+ RangeDateGte (GreaterThanEqD t) -> ["gte" .= t]
1560+ RangeDateLt (LessThanD t) -> ["lt" .= t]
1561+ RangeDateGt (GreaterThanD t) -> ["gt" .= t]
1562+ RangeDateGteLte (GreaterThanEqD l) (LessThanEqD g) -> ["gte" .= l, "lte" .= g]
1563+ RangeDateGtLte (GreaterThanD l) (LessThanEqD g) -> ["gt" .= l, "lte" .= g]
1564+ RangeDateGteLt (GreaterThanEqD l) (LessThanD g) -> ["gte" .= l, "lt" .= g]
1565+ RangeDateGtLt (GreaterThanD l) (LessThanD g) -> ["gt" .= l, "lt" .= g]
1566+ RangeDoubleLte (LessThanEq t) -> ["lte" .= t]
1567+ RangeDoubleGte (GreaterThanEq t) -> ["gte" .= t]
1568+ RangeDoubleLt (LessThan t) -> ["lt" .= t]
1569+ RangeDoubleGt (GreaterThan t) -> ["gt" .= t]
1570+ RangeDoubleGteLte (GreaterThanEq l) (LessThanEq g) -> ["gte" .= l, "lte" .= g]
1571+ RangeDoubleGtLte (GreaterThan l) (LessThanEq g) -> ["gt" .= l, "lte" .= g]
1572+ RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g]
1573+ RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
1575+data Term = Term { termField :: Text
1576+ , termValue :: Text } deriving (Eq, Read, Show, Generic, Typeable)
1578+data BoolMatch = MustMatch Term Cache
1579+ | MustNotMatch Term Cache
1580+ | ShouldMatch [Term] Cache deriving (Eq, Read, Show, Generic, Typeable)
1582+-- "memory" or "indexed"
1583+data GeoFilterType = GeoFilterMemory
1584+ | GeoFilterIndexed deriving (Eq, Read, Show, Generic, Typeable)
1586+data LatLon = LatLon { lat :: Double
1587+ , lon :: Double } deriving (Eq, Read, Show, Generic, Typeable)
1589+data GeoBoundingBox =
1590+ GeoBoundingBox { topLeft :: LatLon
1591+ , bottomRight :: LatLon } deriving (Eq, Read, Show, Generic, Typeable)
1593+data GeoBoundingBoxConstraint =
1594+ GeoBoundingBoxConstraint { geoBBField :: FieldName
1595+ , constraintBox :: GeoBoundingBox
1596+ , bbConstraintcache :: Cache
1597+ , geoType :: GeoFilterType
1598+ } deriving (Eq, Read, Show, Generic, Typeable)
1601+ GeoPoint { geoField :: FieldName
1602+ , latLon :: LatLon} deriving (Eq, Read, Show, Generic, Typeable)
1604+data DistanceUnit = Miles
1612+ | NauticalMiles deriving (Eq, Read, Show, Generic, Typeable)
1614+data DistanceType = Arc
1615+ | SloppyArc -- doesn't exist <1.0
1616+ | Plane deriving (Eq, Read, Show, Generic, Typeable)
1618+data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
1619+ | NoOptimizeBbox deriving (Eq, Read, Show, Generic, Typeable)
1622+ Distance { coefficient :: Double
1623+ , unit :: DistanceUnit } deriving (Eq, Read, Show, Generic, Typeable)
1625+data DistanceRange =
1626+ DistanceRange { distanceFrom :: Distance
1627+ , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
516data SearchResult a =
1629data SearchResult a =
517 SearchResult { took :: Int
1630 SearchResult { took :: Int
@@ -519,24 +1632,3583 @@ data SearchResult a =
519 , shards :: ShardResult
1632 , shards :: ShardResult
520 , searchHits :: SearchHits a
1633 , searchHits :: SearchHits a
521 , aggregations :: Maybe AggregationResults
1634 , aggregations :: Maybe AggregationResults
522− , scrollId :: Maybe ScrollId
1635+ , scrollId :: Maybe ScrollId } deriving (Eq, Read, Show, Generic, Typeable)
523− -- ^ Only one Suggestion request / response per
524− -- Search is supported.
525− , suggest :: Maybe NamedSuggestionResponse
529−instance (FromJSON a) => FromJSON (SearchResult a) where
1637+newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
530− parseJSON (Object v) = SearchResult <$>
1638+
531− v .: "took" <*>
1639+type Score = Maybe Double
532− v .: "timed_out" <*>
1640+
533− v .: "_shards" <*>
1641+data SearchHits a =
1642+ SearchHits { hitsTotal :: Int
1643+ , maxScore :: Score
1644+ , hits :: [Hit a] } deriving (Eq, Read, Show, Generic, Typeable)
1647+instance Monoid (SearchHits a) where
1648+ mempty = SearchHits 0 Nothing mempty
1649+ mappend (SearchHits ta ma ha) (SearchHits tb mb hb) =
1650+ SearchHits (ta + tb) (max ma mb) (ha <> hb)
1654+ Hit { hitIndex :: IndexName
1655+ , hitType :: MappingName
1656+ , hitDocId :: DocId
1657+ , hitScore :: Score
1658+ , hitSource :: Maybe a
1659+ , hitHighlight :: Maybe HitHighlight } deriving (Eq, Read, Show, Generic, Typeable)
1662+ ShardResult { shardTotal :: Int
1663+ , shardsSuccessful :: Int
1664+ , shardsFailed :: Int } deriving (Eq, Read, Show, Generic, Typeable)
1666+type HitHighlight = M.Map Text [Text]
1668+showText :: Show a => a -> Text
1669+showText = T.pack . show
1671+readMay :: Read a => String -> Maybe a
1672+readMay s = case reads s of
1673+ (a, ""):_ -> Just a
1676+parseReadText :: Read a => Text -> Parser a
1677+parseReadText = maybe mzero return . readMay . T.unpack
1679+type Aggregations = M.Map Text Aggregation
1681+emptyAggregations :: Aggregations
1682+emptyAggregations = M.empty
1684+mkAggregations :: Text -> Aggregation -> Aggregations
1685+mkAggregations name aggregation = M.insert name aggregation emptyAggregations
1687+data TermOrder = TermOrder{ termSortField :: Text
1688+ , termSortOrder :: SortOrder } deriving (Eq, Read, Show, Generic, Typeable)
1690+data TermInclusion = TermInclusion Text
1691+ | TermPattern Text Text deriving (Eq, Read, Show, Generic, Typeable)
1693+data CollectionMode = BreadthFirst
1694+ | DepthFirst deriving (Eq, Read, Show, Generic, Typeable)
1696+data ExecutionHint = Ordinals
1698+ | GlobalOrdinalsHash
1699+ | GlobalOrdinalsLowCardinality
1700+ | Map deriving (Eq, Read, Show, Generic, Typeable)
1702+data TimeInterval = Weeks
1706+ | Seconds deriving Eq
1708+data Interval = Year
1716+ | FractionalInterval Float TimeInterval deriving (Eq, Read, Show, Generic, Typeable)
1718+data Aggregation = TermsAgg TermsAggregation
1719+ | CardinalityAgg CardinalityAggregation
1720+ | DateHistogramAgg DateHistogramAggregation
1721+ | ValueCountAgg ValueCountAggregation
1722+ | FilterAgg FilterAggregation
1723+ | DateRangeAgg DateRangeAggregation
1724+ | MissingAgg MissingAggregation deriving (Eq, Read, Show, Generic, Typeable)
1726+data MissingAggregation = MissingAggregation
1728+ } deriving (Eq, Read, Show, Generic, Typeable)
1730+data TermsAggregation = TermsAggregation { term :: Either Text Text
1731+ , termInclude :: Maybe TermInclusion
1732+ , termExclude :: Maybe TermInclusion
1733+ , termOrder :: Maybe TermOrder
1734+ , termMinDocCount :: Maybe Int
1735+ , termSize :: Maybe Int
1736+ , termShardSize :: Maybe Int
1737+ , termCollectMode :: Maybe CollectionMode
1738+ , termExecutionHint :: Maybe ExecutionHint
1739+ , termAggs :: Maybe Aggregations
1740+ } deriving (Eq, Read, Show, Generic, Typeable)
1742+data CardinalityAggregation = CardinalityAggregation { cardinalityField :: FieldName,
1743+ precisionThreshold :: Maybe Int
1744+ } deriving (Eq, Read, Show, Generic, Typeable)
1746+data DateHistogramAggregation = DateHistogramAggregation { dateField :: FieldName
1747+ , dateInterval :: Interval
1748+ , dateFormat :: Maybe Text
1749+ -- pre and post deprecated in 1.5
1750+ , datePreZone :: Maybe Text
1751+ , datePostZone :: Maybe Text
1752+ , datePreOffset :: Maybe Text
1753+ , datePostOffset :: Maybe Text
1754+ , dateAggs :: Maybe Aggregations
1755+ } deriving (Eq, Read, Show, Generic, Typeable)
1758+data DateRangeAggregation = DateRangeAggregation { draField :: FieldName
1759+ , draFormat :: Maybe Text
1760+ , draRanges :: NonEmpty DateRangeAggRange
1761+ } deriving (Eq, Read, Show, Generic, Typeable)
1763+data DateRangeAggRange = DateRangeFrom DateMathExpr
1764+ | DateRangeTo DateMathExpr
1765+ | DateRangeFromAndTo DateMathExpr DateMathExpr deriving (Eq, Read, Show, Generic, Typeable)
1767+-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math> for more information.
1768+data DateMathExpr = DateMathExpr DateMathAnchor [DateMathModifier] deriving (Eq, Read, Show, Generic, Typeable)
1771+-- | Starting point for a date range. This along with the 'DateMathModifiers' gets you the date ES will start from.
1772+data DateMathAnchor = DMNow
1773+ | DMDate Day deriving (Eq, Read, Show, Generic, Typeable)
1775+data DateMathModifier = AddTime Int DateMathUnit
1776+ | SubtractTime Int DateMathUnit
1777+ | RoundDownTo DateMathUnit deriving (Eq, Read, Show, Generic, Typeable)
1779+data DateMathUnit = DMYear
1785+ | DMSecond deriving (Eq, Read, Show, Generic, Typeable)
1787+-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html> for more information.
1788+data ValueCountAggregation = FieldValueCount FieldName
1789+ | ScriptValueCount Script deriving (Eq, Read, Show, Generic, Typeable)
1791+-- | Single-bucket filter aggregations. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-filter-aggregation.html#search-aggregations-bucket-filter-aggregation> for more information.
1792+data FilterAggregation = FilterAggregation { faFilter :: Filter
1793+ , faAggs :: Maybe Aggregations} deriving (Eq, Read, Show, Generic, Typeable)
1795+mkTermsAggregation :: Text -> TermsAggregation
1796+mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1798+mkTermsScriptAggregation :: Text -> TermsAggregation
1799+mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1801+mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
1802+mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
1804+mkCardinalityAggregation :: FieldName -> CardinalityAggregation
1805+mkCardinalityAggregation t = CardinalityAggregation t Nothing
1807+instance ToJSON Version where
1808+ toJSON Version {..} = object ["number" .= number
1809+ ,"build_hash" .= build_hash
1810+ ,"build_timestamp" .= build_timestamp
1811+ ,"build_snapshot" .= build_snapshot
1812+ ,"lucene_version" .= lucene_version]
1814+instance FromJSON Version where
1815+ parseJSON = withObject "Version" parse
1816+ where parse o = Version
1818+ <*> o .: "build_hash"
1819+ <*> o .: "build_timestamp"
1820+ <*> o .: "build_snapshot"
1821+ <*> o .: "lucene_version"
1823+instance ToJSON VersionNumber where
1824+ toJSON = toJSON . Vers.showVersion . versionNumber
1826+instance FromJSON VersionNumber where
1827+ parseJSON = withText "VersionNumber" (parse . T.unpack)
1829+ parse s = case filter (null . snd)(RP.readP_to_S Vers.parseVersion s) of
1830+ [(v, _)] -> pure (VersionNumber v)
1831+ [] -> fail ("Invalid version string " ++ s)
1832+ xs -> fail ("Ambiguous version string " ++ s ++ " (" ++ intercalate ", " (Vers.showVersion . fst <$> xs) ++ ")")
1834+instance ToJSON TermOrder where
1835+ toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
1837+instance ToJSON TermInclusion where
1838+ toJSON (TermInclusion x) = toJSON x
1839+ toJSON (TermPattern pattern flags) = omitNulls [ "pattern" .= pattern,
1842+instance ToJSON CollectionMode where
1843+ toJSON BreadthFirst = "breadth_first"
1844+ toJSON DepthFirst = "depth_first"
1846+instance ToJSON ExecutionHint where
1847+ toJSON Ordinals = "ordinals"
1848+ toJSON GlobalOrdinals = "global_ordinals"
1849+ toJSON GlobalOrdinalsHash = "global_ordinals_hash"
1850+ toJSON GlobalOrdinalsLowCardinality = "global_ordinals_low_cardinality"
1853+instance ToJSON Interval where
1854+ toJSON Year = "year"
1855+ toJSON Quarter = "quarter"
1856+ toJSON Month = "month"
1857+ toJSON Week = "week"
1859+ toJSON Hour = "hour"
1860+ toJSON Minute = "minute"
1861+ toJSON Second = "second"
1862+ toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1864+instance Show TimeInterval where
1871+instance Read TimeInterval where
1872+ readPrec = f =<< TR.get
1874+ f 'w' = return Weeks
1875+ f 'd' = return Days
1876+ f 'h' = return Hours
1877+ f 'm' = return Minutes
1878+ f 's' = return Seconds
1879+ f _ = fail "TimeInterval expected one of w, d, h, m, s"
1881+instance ToJSON Aggregation where
1882+ toJSON (TermsAgg (TermsAggregation term include exclude order minDocCount size shardSize collectMode executionHint termAggs)) =
1883+ omitNulls ["terms" .= omitNulls [ toJSON' term,
1884+ "include" .= include,
1885+ "exclude" .= exclude,
1887+ "min_doc_count" .= minDocCount,
1889+ "shard_size" .= shardSize,
1890+ "collect_mode" .= collectMode,
1891+ "execution_hint" .= executionHint
1893+ "aggs" .= termAggs ]
1895+ toJSON' x = case x of { Left y -> "field" .= y; Right y -> "script" .= y }
1897+ toJSON (CardinalityAgg (CardinalityAggregation field precisionThreshold)) =
1898+ object ["cardinality" .= omitNulls [ "field" .= field,
1899+ "precisionThreshold" .= precisionThreshold
1903+ toJSON (DateHistogramAgg (DateHistogramAggregation field interval format preZone postZone preOffset postOffset dateHistoAggs)) =
1904+ omitNulls ["date_histogram" .= omitNulls [ "field" .= field,
1905+ "interval" .= interval,
1906+ "format" .= format,
1907+ "pre_zone" .= preZone,
1908+ "post_zone" .= postZone,
1909+ "pre_offset" .= preOffset,
1910+ "post_offset" .= postOffset
1912+ "aggs" .= dateHistoAggs ]
1913+ toJSON (ValueCountAgg a) = object ["value_count" .= v]
1914+ where v = case a of
1915+ (FieldValueCount (FieldName n)) -> object ["field" .= n]
1916+ (ScriptValueCount (Script s)) -> object ["script" .= s]
1917+ toJSON (FilterAgg (FilterAggregation filt ags)) =
1918+ omitNulls [ "filter" .= filt
1920+ toJSON (DateRangeAgg a) = object [ "date_range" .= a
1922+ toJSON (MissingAgg (MissingAggregation{..})) =
1923+ object ["missing" .= object ["field" .= maField]]
1925+instance ToJSON DateRangeAggregation where
1926+ toJSON DateRangeAggregation {..} =
1927+ omitNulls [ "field" .= draField
1928+ , "format" .= draFormat
1929+ , "ranges" .= toList draRanges
1932+instance ToJSON DateRangeAggRange where
1933+ toJSON (DateRangeFrom e) = object [ "from" .= e ]
1934+ toJSON (DateRangeTo e) = object [ "to" .= e ]
1935+ toJSON (DateRangeFromAndTo f t) = object [ "from" .= f, "to" .= t ]
1937+instance ToJSON DateMathExpr where
1938+ toJSON (DateMathExpr a mods) = String (fmtA a <> mconcat (fmtMod <$> mods))
1939+ where fmtA DMNow = "now"
1940+ fmtA (DMDate date) = (T.pack $ showGregorian date) <> "||"
1941+ fmtMod (AddTime n u) = "+" <> showText n <> fmtU u
1942+ fmtMod (SubtractTime n u) = "-" <> showText n <> fmtU u
1943+ fmtMod (RoundDownTo u) = "/" <> fmtU u
1949+ fmtU DMMinute = "m"
1950+ fmtU DMSecond = "s"
1953+type AggregationResults = M.Map Text Value
1955+class BucketAggregation a where
1956+ key :: a -> BucketValue
1957+ docCount :: a -> Int
1958+ aggs :: a -> Maybe AggregationResults
1961+data Bucket a = Bucket { buckets :: [a]} deriving (Read, Show)
1963+data BucketValue = TextValue Text
1964+ | ScientificValue Scientific
1965+ | BoolValue Bool deriving (Read, Show)
1967+data MissingResult = MissingResult { missingDocCount :: Int } deriving (Show)
1969+data TermsResult = TermsResult { termKey :: BucketValue
1970+ , termsDocCount :: Int
1971+ , termsAggs :: Maybe AggregationResults } deriving (Read, Show)
1973+data DateHistogramResult = DateHistogramResult { dateKey :: Int
1974+ , dateKeyStr :: Maybe Text
1975+ , dateDocCount :: Int
1976+ , dateHistogramAggs :: Maybe AggregationResults } deriving (Read, Show)
1978+data DateRangeResult = DateRangeResult { dateRangeKey :: Text
1979+ , dateRangeFrom :: Maybe UTCTime
1980+ , dateRangeFromAsString :: Maybe Text
1981+ , dateRangeTo :: Maybe UTCTime
1982+ , dateRangeToAsString :: Maybe Text
1983+ , dateRangeDocCount :: Int
1984+ , dateRangeAggs :: Maybe AggregationResults } deriving (Read, Show, Eq, Generic, Typeable)
1986+toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
1987+toTerms = toAggResult
1989+toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
1990+toDateHistogram = toAggResult
1992+toMissing :: Text -> AggregationResults -> Maybe MissingResult
1993+toMissing = toAggResult
1995+toAggResult :: (FromJSON a) => Text -> AggregationResults -> Maybe a
1996+toAggResult t a = M.lookup t a >>= deserialize
1997+ where deserialize = parseMaybe parseJSON
1999+instance BucketAggregation TermsResult where
2001+ docCount = termsDocCount
2004+instance BucketAggregation DateHistogramResult where
2005+ key = TextValue . showText . dateKey
2006+ docCount = dateDocCount
2007+ aggs = dateHistogramAggs
2009+instance BucketAggregation DateRangeResult where
2010+ key = TextValue . dateRangeKey
2011+ docCount = dateRangeDocCount
2012+ aggs = dateRangeAggs
2014+instance (FromJSON a, BucketAggregation a) => FromJSON (Bucket a) where
2015+ parseJSON (Object v) = Bucket <$>
2017+ parseJSON _ = mempty
2019+instance FromJSON BucketValue where
2020+ parseJSON (String t) = return $ TextValue t
2021+ parseJSON (Number s) = return $ ScientificValue s
2022+ parseJSON (Bool b) = return $ BoolValue b
2023+ parseJSON _ = mempty
2025+instance FromJSON MissingResult where
2026+ parseJSON = withObject "MissingResult" parse
2027+ where parse v = MissingResult <$> v .: "doc_count"
2029+instance FromJSON TermsResult where
2030+ parseJSON (Object v) = TermsResult <$>
2032+ v .: "doc_count" <*>
2033+ v .:? "aggregations"
2034+ parseJSON _ = mempty
2036+instance FromJSON DateHistogramResult where
2037+ parseJSON (Object v) = DateHistogramResult <$>
2039+ v .:? "key_as_string" <*>
2040+ v .: "doc_count" <*>
2041+ v .:? "aggregations"
2042+ parseJSON _ = mempty
2044+instance FromJSON DateRangeResult where
2045+ parseJSON = withObject "DateRangeResult" parse
2046+ where parse v = DateRangeResult <$>
2048+ (fmap posixMS <$> v .:? "from") <*>
2049+ v .:? "from_as_string" <*>
2050+ (fmap posixMS <$> v .:? "to") <*>
2051+ v .:? "to_as_string" <*>
2052+ v .: "doc_count" <*>
2053+ v .:? "aggregations"
2055+instance FromJSON POSIXMS where
2056+ parseJSON = withScientific "POSIXMS" (return . parse)
2057+ where parse n = let n' = truncate n :: Integer
2058+ in POSIXMS (posixSecondsToUTCTime (fromInteger (n' `div` 1000)))
2060+instance Monoid Filter where
2061+ mempty = IdentityFilter
2062+ mappend a b = AndFilter [a, b] defaultCache
2064+instance Seminearring Filter where
2065+ a <||> b = OrFilter [a, b] defaultCache
2067+instance ToJSON Filter where
2068+ toJSON (AndFilter filters cache) =
2070+ object [ "filters" .= fmap toJSON filters
2071+ , "_cache" .= cache]]
2073+ toJSON (OrFilter filters cache) =
2075+ object [ "filters" .= fmap toJSON filters
2076+ , "_cache" .= cache]]
2078+ toJSON (NotFilter notFilter cache) =
2080+ object ["filter" .= notFilter
2081+ , "_cache" .= cache]]
2083+ toJSON (IdentityFilter) =
2084+ object ["match_all" .= object []]
2086+ toJSON (TermFilter (Term termFilterField termFilterValue) cache) =
2087+ object ["term" .= object base]
2088+ where base = [termFilterField .= termFilterValue,
2091+ toJSON (ExistsFilter (FieldName fieldName)) =
2092+ object ["exists" .= object
2093+ ["field" .= fieldName]]
2095+ toJSON (BoolFilter boolMatch) =
2096+ object ["bool" .= boolMatch]
2098+ toJSON (GeoBoundingBoxFilter bbConstraint) =
2099+ object ["geo_bounding_box" .= bbConstraint]
2101+ toJSON (GeoDistanceFilter (GeoPoint (FieldName distanceGeoField) geoDistLatLon)
2102+ distance distanceType optimizeBbox cache) =
2103+ object ["geo_distance" .=
2104+ object ["distance" .= distance
2105+ , "distance_type" .= distanceType
2106+ , "optimize_bbox" .= optimizeBbox
2107+ , distanceGeoField .= geoDistLatLon
2108+ , "_cache" .= cache]]
2110+ toJSON (GeoDistanceRangeFilter (GeoPoint (FieldName gddrField) drLatLon)
2111+ (DistanceRange geoDistRangeDistFrom drDistanceTo)) =
2112+ object ["geo_distance_range" .=
2113+ object ["from" .= geoDistRangeDistFrom
2114+ , "to" .= drDistanceTo
2115+ , gddrField .= drLatLon]]
2117+ toJSON (GeoPolygonFilter (FieldName geoPolygonFilterField) latLons) =
2118+ object ["geo_polygon" .=
2119+ object [geoPolygonFilterField .=
2120+ object ["points" .= fmap toJSON latLons]]]
2122+ toJSON (IdsFilter (MappingName mappingName) values) =
2124+ object ["type" .= mappingName
2125+ , "values" .= fmap unpackId values]]
2127+ toJSON (LimitFilter limit) =
2128+ object ["limit" .= object ["value" .= limit]]
2130+ toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
2131+ object ["missing" .=
2132+ object ["field" .= fieldName
2133+ , "existence" .= existence
2134+ , "null_value" .= nullValue]]
2136+ toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
2137+ object ["prefix" .=
2138+ object [fieldName .= fieldValue
2139+ , "_cache" .= cache]]
2141+ toJSON (QueryFilter query False) =
2142+ object ["query" .= toJSON query ]
2143+ toJSON (QueryFilter query True) =
2144+ object ["fquery" .=
2145+ object [ "query" .= toJSON query
2146+ , "_cache" .= True ]]
2148+ toJSON (RangeFilter (FieldName fieldName) rangeValue rangeExecution cache) =
2150+ object [ fieldName .= object (rangeValueToPair rangeValue)
2151+ , "execution" .= rangeExecution
2152+ , "_cache" .= cache]]
2154+ toJSON (RegexpFilter (FieldName fieldName)
2155+ (Regexp regexText) flags (CacheName cacheName) cache (CacheKey cacheKey)) =
2156+ object ["regexp" .=
2157+ object [fieldName .=
2158+ object ["value" .= regexText
2159+ , "flags" .= flags]
2160+ , "_name" .= cacheName
2161+ , "_cache" .= cache
2162+ , "_cache_key" .= cacheKey]]
2164+instance FromJSON Filter where
2165+ parseJSON = withObject "Filter" parse
2166+ where parse o = andFilter `taggedWith` "and"
2167+ <|> orFilter `taggedWith` "or"
2168+ <|> notFilter `taggedWith` "not"
2169+ <|> identityFilter `taggedWith` "match_all"
2170+ <|> boolFilter `taggedWith` "bool"
2171+ <|> existsFilter `taggedWith` "exists"
2172+ <|> geoBoundingBoxFilter `taggedWith` "geo_bounding_box"
2173+ <|> geoDistanceFilter `taggedWith` "geo_distance"
2174+ <|> geoDistanceRangeFilter `taggedWith` "geo_distance_range"
2175+ <|> geoPolygonFilter `taggedWith` "geo_polygon"
2176+ <|> idsFilter `taggedWith` "ids"
2177+ <|> limitFilter `taggedWith` "limit"
2178+ <|> missingFilter `taggedWith` "missing"
2179+ <|> prefixFilter `taggedWith` "prefix"
2180+ <|> queryFilter `taggedWith` "query"
2181+ <|> fqueryFilter `taggedWith` "fquery"
2182+ <|> rangeFilter `taggedWith` "range"
2183+ <|> regexpFilter `taggedWith` "regexp"
2184+ <|> termFilter `taggedWith` "term"
2185+ where taggedWith parser k = parser =<< o .: k
2186+ andFilter o = AndFilter <$> o .: "filters"
2187+ <*> o .:? "_cache" .!= defaultCache
2188+ orFilter o = OrFilter <$> o .: "filters"
2189+ <*> o .:? "_cache" .!= defaultCache
2190+ notFilter o = NotFilter <$> o .: "filter"
2191+ <*> o .: "_cache" .!= defaultCache
2192+ identityFilter :: Object -> Parser Filter
2194+ | HM.null m = pure IdentityFilter
2195+ | otherwise = fail ("Identityfilter expected empty object but got " <> show m)
2196+ boolFilter = pure . BoolFilter
2197+ existsFilter o = ExistsFilter <$> o .: "field"
2198+ geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
2199+ geoDistanceFilter o = do
2200+ case HM.toList (deleteSeveral ["distance", "distance_type", "optimize_bbox", "_cache"] o) of
2202+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
2203+ GeoDistanceFilter gp <$> o .: "distance"
2204+ <*> o .: "distance_type"
2205+ <*> o .: "optimize_bbox"
2206+ <*> o .:? "_cache" .!= defaultCache
2207+ _ -> fail "Could not find GeoDistanceFilter field name"
2208+ geoDistanceRangeFilter o = do
2209+ case HM.toList (deleteSeveral ["from", "to"] o) of
2211+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
2212+ rng <- DistanceRange <$> o .: "from" <*> o .: "to"
2213+ return (GeoDistanceRangeFilter gp rng)
2214+ _ -> fail "Could not find GeoDistanceRangeFilter field name"
2215+ geoPolygonFilter = fieldTagged $ \fn o -> GeoPolygonFilter fn <$> o .: "points"
2216+ idsFilter o = IdsFilter <$> o .: "type"
2218+ limitFilter o = LimitFilter <$> o .: "value"
2219+ missingFilter o = MissingFilter <$> o .: "field"
2220+ <*> o .: "existence"
2221+ <*> o .: "null_value"
2222+ prefixFilter o = case HM.toList (HM.delete "_cache" o) of
2223+ [(fn, String v)] -> PrefixFilter (FieldName fn) v <$> o .:? "_cache" .!= defaultCache
2224+ _ -> fail "Could not parse PrefixFilter"
2226+ queryFilter q = pure (QueryFilter q False)
2227+ fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
2228+ rangeFilter o = case HM.toList (deleteSeveral ["execution", "_cache"] o) of
2229+ [(fn, v)] -> RangeFilter (FieldName fn)
2231+ <*> o .: "execution"
2232+ <*> o .:? "_cache" .!= defaultCache
2233+ _ -> fail "Could not find field name for RangeFilter"
2234+ regexpFilter o = case HM.toList (deleteSeveral ["_name", "_cache", "_cache_key"] o) of
2235+ [(fn, Object o')] -> RegexpFilter (FieldName fn)
2239+ <*> o .:? "_cache" .!= defaultCache
2240+ <*> o .: "_cache_key"
2241+ _ -> fail "Could not find field name for RegexpFilter"
2242+ termFilter o = case HM.toList (HM.delete "_cache" o) of
2243+ [(termField, String termVal)] -> TermFilter (Term termField termVal)
2244+ <$> o .:? "_cache" .!= defaultCache
2245+ _ -> fail "Could not find term field for TermFilter"
2247+fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
2248+fieldTagged f o = case HM.toList o of
2249+ [(k, Object o')] -> f (FieldName k) o'
2250+ _ -> fail "Expected object with 1 field-named key"
2252+instance ToJSON GeoPoint where
2253+ toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
2254+ object [ geoPointField .= geoPointLatLon ]
2257+instance ToJSON Query where
2258+ toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
2260+ object [termQueryField .= object merged]]
2262+ base = [ "value" .= termQueryValue ]
2263+ boosted = maybe [] (return . ("boost" .=)) boost
2264+ merged = mappend base boosted
2266+ toJSON (TermsQuery fieldName terms) =
2267+ object [ "terms" .= object conjoined ]
2268+ where conjoined = [fieldName .= terms]
2270+ toJSON (IdsQuery idsQueryMappingName docIds) =
2271+ object [ "ids" .= object conjoined ]
2272+ where conjoined = [ "type" .= idsQueryMappingName
2273+ , "values" .= fmap toJSON docIds ]
2275+ toJSON (QueryQueryStringQuery qQueryStringQuery) =
2276+ object [ "query_string" .= qQueryStringQuery ]
2278+ toJSON (QueryMatchQuery matchQuery) =
2279+ object [ "match" .= matchQuery ]
2281+ toJSON (QueryMultiMatchQuery multiMatchQuery) =
2282+ toJSON multiMatchQuery
2284+ toJSON (QueryBoolQuery boolQuery) =
2285+ object [ "bool" .= boolQuery ]
2287+ toJSON (QueryBoostingQuery boostingQuery) =
2288+ object [ "boosting" .= boostingQuery ]
2290+ toJSON (QueryCommonTermsQuery commonTermsQuery) =
2291+ object [ "common" .= commonTermsQuery ]
2293+ toJSON (ConstantScoreFilter csFilter boost) =
2294+ object ["constant_score" .= object ["filter" .= csFilter
2295+ , "boost" .= boost]]
2297+ toJSON (ConstantScoreQuery query boost) =
2298+ object ["constant_score" .= object ["query" .= query
2299+ , "boost" .= boost]]
2301+ toJSON (QueryDisMaxQuery disMaxQuery) =
2302+ object [ "dis_max" .= disMaxQuery ]
2304+ toJSON (QueryFilteredQuery qFilteredQuery) =
2305+ object [ "filtered" .= qFilteredQuery ]
2307+ toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
2308+ object [ "fuzzy_like_this" .= fuzzyQuery ]
2310+ toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
2311+ object [ "fuzzy_like_this_field" .= fuzzyFieldQuery ]
2313+ toJSON (QueryFuzzyQuery fuzzyQuery) =
2314+ object [ "fuzzy" .= fuzzyQuery ]
2316+ toJSON (QueryHasChildQuery childQuery) =
2317+ object [ "has_child" .= childQuery ]
2319+ toJSON (QueryHasParentQuery parentQuery) =
2320+ object [ "has_parent" .= parentQuery ]
2322+ toJSON (QueryIndicesQuery qIndicesQuery) =
2323+ object [ "indices" .= qIndicesQuery ]
2325+ toJSON (MatchAllQuery boost) =
2326+ object [ "match_all" .= omitNulls [ "boost" .= boost ] ]
2328+ toJSON (QueryMoreLikeThisQuery query) =
2329+ object [ "more_like_this" .= query ]
2331+ toJSON (QueryMoreLikeThisFieldQuery query) =
2332+ object [ "more_like_this_field" .= query ]
2334+ toJSON (QueryNestedQuery query) =
2335+ object [ "nested" .= query ]
2337+ toJSON (QueryPrefixQuery query) =
2338+ object [ "prefix" .= query ]
2340+ toJSON (QueryRangeQuery query) =
2341+ object [ "range" .= query ]
2343+ toJSON (QueryRegexpQuery query) =
2344+ object [ "regexp" .= query ]
2346+ toJSON (QuerySimpleQueryStringQuery query) =
2347+ object [ "simple_query_string" .= query ]
2349+instance FromJSON Query where
2350+ parseJSON v = withObject "Query" parse v
2351+ where parse o = termQuery `taggedWith` "term"
2352+ <|> termsQuery `taggedWith` "terms"
2353+ <|> idsQuery `taggedWith` "ids"
2354+ <|> queryQueryStringQuery `taggedWith` "query_string"
2355+ <|> queryMatchQuery `taggedWith` "match"
2356+ <|> queryMultiMatchQuery
2357+ <|> queryBoolQuery `taggedWith` "bool"
2358+ <|> queryBoostingQuery `taggedWith` "boosting"
2359+ <|> queryCommonTermsQuery `taggedWith` "common"
2360+ <|> constantScoreFilter `taggedWith` "constant_score"
2361+ <|> constantScoreQuery `taggedWith` "constant_score"
2362+ <|> queryDisMaxQuery `taggedWith` "dis_max"
2363+ <|> queryFilteredQuery `taggedWith` "filtered"
2364+ <|> queryFuzzyLikeThisQuery `taggedWith` "fuzzy_like_this"
2365+ <|> queryFuzzyLikeFieldQuery `taggedWith` "fuzzy_like_this_field"
2366+ <|> queryFuzzyQuery `taggedWith` "fuzzy"
2367+ <|> queryHasChildQuery `taggedWith` "has_child"
2368+ <|> queryHasParentQuery `taggedWith` "has_parent"
2369+ <|> queryIndicesQuery `taggedWith` "indices"
2370+ <|> matchAllQuery `taggedWith` "match_all"
2371+ <|> queryMoreLikeThisQuery `taggedWith` "more_like_this"
2372+ <|> queryMoreLikeThisFieldQuery `taggedWith` "more_like_this_field"
2373+ <|> queryNestedQuery `taggedWith` "nested"
2374+ <|> queryPrefixQuery `taggedWith` "prefix"
2375+ <|> queryRangeQuery `taggedWith` "range"
2376+ <|> queryRegexpQuery `taggedWith` "regexp"
2377+ <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2378+ where taggedWith parser k = parser =<< o .: k
2379+ termQuery = fieldTagged $ \(FieldName fn) o ->
2380+ TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
2381+ termsQuery o = case HM.toList o of
2382+ [(fn, vs)] -> do vals <- parseJSON vs
2384+ x:xs -> return (TermsQuery fn (x :| xs))
2385+ _ -> fail "Expected non empty list of values"
2386+ _ -> fail "Expected object with 1 field-named key"
2387+ idsQuery o = IdsQuery <$> o .: "type"
2389+ queryQueryStringQuery = pure . QueryQueryStringQuery
2390+ queryMatchQuery = pure . QueryMatchQuery
2391+ queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
2392+ queryBoolQuery = pure . QueryBoolQuery
2393+ queryBoostingQuery = pure . QueryBoostingQuery
2394+ queryCommonTermsQuery = pure . QueryCommonTermsQuery
2395+ constantScoreFilter o = case HM.lookup "filter" o of
2396+ Just x -> ConstantScoreFilter <$> parseJSON x
2398+ _ -> fail "Does not appear to be a ConstantScoreFilter"
2399+ constantScoreQuery o = case HM.lookup "query" o of
2400+ Just x -> ConstantScoreQuery <$> parseJSON x
2402+ _ -> fail "Does not appear to be a ConstantScoreQuery"
2403+ queryDisMaxQuery = pure . QueryDisMaxQuery
2404+ queryFilteredQuery = pure . QueryFilteredQuery
2405+ queryFuzzyLikeThisQuery = pure . QueryFuzzyLikeThisQuery
2406+ queryFuzzyLikeFieldQuery = pure . QueryFuzzyLikeFieldQuery
2407+ queryFuzzyQuery = pure . QueryFuzzyQuery
2408+ queryHasChildQuery = pure . QueryHasChildQuery
2409+ queryHasParentQuery = pure . QueryHasParentQuery
2410+ queryIndicesQuery = pure . QueryIndicesQuery
2411+ matchAllQuery o = MatchAllQuery <$> o .:? "boost"
2412+ queryMoreLikeThisQuery = pure . QueryMoreLikeThisQuery
2413+ queryMoreLikeThisFieldQuery = pure . QueryMoreLikeThisFieldQuery
2414+ queryNestedQuery = pure . QueryNestedQuery
2415+ queryPrefixQuery = pure . QueryPrefixQuery
2416+ queryRangeQuery = pure . QueryRangeQuery
2417+ queryRegexpQuery = pure . QueryRegexpQuery
2418+ querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2421+omitNulls :: [(Text, Value)] -> Value
2422+omitNulls = object . filter notNull where
2423+ notNull (_, Null) = False
2424+ notNull (_, Array a) = (not . V.null) a
2428+instance ToJSON SimpleQueryStringQuery where
2429+ toJSON SimpleQueryStringQuery {..} =
2430+ omitNulls (base ++ maybeAdd)
2431+ where base = [ "query" .= simpleQueryStringQuery ]
2432+ maybeAdd = [ "fields" .= simpleQueryStringField
2433+ , "default_operator" .= simpleQueryStringOperator
2434+ , "analyzer" .= simpleQueryStringAnalyzer
2435+ , "flags" .= simpleQueryStringFlags
2436+ , "lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded
2437+ , "locale" .= simpleQueryStringLocale ]
2439+instance FromJSON SimpleQueryStringQuery where
2440+ parseJSON = withObject "SimpleQueryStringQuery" parse
2441+ where parse o = SimpleQueryStringQuery <$> o .: "query"
2443+ <*> o .:? "default_operator"
2444+ <*> o .:? "analyzer"
2445+ <*> (parseFlags <$> o .:? "flags")
2446+ <*> o .:? "lowercase_expanded_terms"
2448+ parseFlags (Just (x:xs)) = Just (x :| xs)
2449+ parseFlags _ = Nothing
2451+instance ToJSON FieldOrFields where
2452+ toJSON (FofField fieldName) =
2454+ toJSON (FofFields fieldNames) =
2457+instance FromJSON FieldOrFields where
2458+ parseJSON v = FofField <$> parseJSON v
2459+ <|> FofFields <$> (parseNEJSON =<< parseJSON v)
2461+instance ToJSON SimpleQueryFlag where
2462+ toJSON SimpleQueryAll = "ALL"
2463+ toJSON SimpleQueryNone = "NONE"
2464+ toJSON SimpleQueryAnd = "AND"
2465+ toJSON SimpleQueryOr = "OR"
2466+ toJSON SimpleQueryPrefix = "PREFIX"
2467+ toJSON SimpleQueryPhrase = "PHRASE"
2468+ toJSON SimpleQueryPrecedence = "PRECEDENCE"
2469+ toJSON SimpleQueryEscape = "ESCAPE"
2470+ toJSON SimpleQueryWhitespace = "WHITESPACE"
2471+ toJSON SimpleQueryFuzzy = "FUZZY"
2472+ toJSON SimpleQueryNear = "NEAR"
2473+ toJSON SimpleQuerySlop = "SLOP"
2475+instance FromJSON SimpleQueryFlag where
2476+ parseJSON = withText "SimpleQueryFlag" parse
2477+ where parse "ALL" = pure SimpleQueryAll
2478+ parse "NONE" = pure SimpleQueryNone
2479+ parse "AND" = pure SimpleQueryAnd
2480+ parse "OR" = pure SimpleQueryOr
2481+ parse "PREFIX" = pure SimpleQueryPrefix
2482+ parse "PHRASE" = pure SimpleQueryPhrase
2483+ parse "PRECEDENCE" = pure SimpleQueryPrecedence
2484+ parse "ESCAPE" = pure SimpleQueryEscape
2485+ parse "WHITESPACE" = pure SimpleQueryWhitespace
2486+ parse "FUZZY" = pure SimpleQueryFuzzy
2487+ parse "NEAR" = pure SimpleQueryNear
2488+ parse "SLOP" = pure SimpleQuerySlop
2489+ parse f = fail ("Unexpected SimpleQueryFlag: " <> show f)
2491+instance ToJSON RegexpQuery where
2492+ toJSON (RegexpQuery (FieldName rqQueryField)
2493+ (Regexp regexpQueryQuery) rqQueryFlags
2495+ object [ rqQueryField .= omitNulls base ]
2496+ where base = [ "value" .= regexpQueryQuery
2497+ , "flags" .= rqQueryFlags
2498+ , "boost" .= rqQueryBoost ]
2500+instance FromJSON RegexpQuery where
2501+ parseJSON = withObject "RegexpQuery" parse
2502+ where parse = fieldTagged $ \fn o ->
2508+instance ToJSON QueryStringQuery where
2509+ toJSON (QueryStringQuery qsQueryString
2510+ qsDefaultField qsOperator
2511+ qsAnalyzer qsAllowWildcard
2512+ qsLowercaseExpanded qsEnablePositionIncrements
2513+ qsFuzzyMaxExpansions qsFuzziness
2514+ qsFuzzyPrefixLength qsPhraseSlop
2515+ qsBoost qsAnalyzeWildcard
2516+ qsGeneratePhraseQueries qsMinimumShouldMatch
2517+ qsLenient qsLocale) =
2520+ base = [ "query" .= qsQueryString
2521+ , "default_field" .= qsDefaultField
2522+ , "default_operator" .= qsOperator
2523+ , "analyzer" .= qsAnalyzer
2524+ , "allow_leading_wildcard" .= qsAllowWildcard
2525+ , "lowercase_expanded_terms" .= qsLowercaseExpanded
2526+ , "enable_position_increments" .= qsEnablePositionIncrements
2527+ , "fuzzy_max_expansions" .= qsFuzzyMaxExpansions
2528+ , "fuzziness" .= qsFuzziness
2529+ , "fuzzy_prefix_length" .= qsFuzzyPrefixLength
2530+ , "phrase_slop" .= qsPhraseSlop
2531+ , "boost" .= qsBoost
2532+ , "analyze_wildcard" .= qsAnalyzeWildcard
2533+ , "auto_generate_phrase_queries" .= qsGeneratePhraseQueries
2534+ , "minimum_should_match" .= qsMinimumShouldMatch
2535+ , "lenient" .= qsLenient
2536+ , "locale" .= qsLocale ]
2538+instance FromJSON QueryStringQuery where
2539+ parseJSON = withObject "QueryStringQuery" parse
2540+ where parse o = QueryStringQuery
2542+ <*> o .:? "default_field"
2543+ <*> o .:? "default_operator"
2544+ <*> o .:? "analyzer"
2545+ <*> o .:? "allow_leading_wildcard"
2546+ <*> o .:? "lowercase_expanded_terms"
2547+ <*> o .:? "enable_position_increments"
2548+ <*> o .:? "fuzzy_max_expansions"
2549+ <*> o .:? "fuzziness"
2550+ <*> o .:? "fuzzy_prefix_length"
2551+ <*> o .:? "phrase_slop"
2553+ <*> o .:? "analyze_wildcard"
2554+ <*> o .:? "auto_generate_phrase_queries"
2555+ <*> o .:? "minimum_should_match"
2556+ <*> o .:? "lenient"
2559+instance ToJSON RangeQuery where
2560+ toJSON (RangeQuery (FieldName fieldName) range boost) =
2561+ object [ fieldName .= object conjoined ]
2562+ where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2564+instance FromJSON RangeQuery where
2565+ parseJSON = withObject "RangeQuery" parse
2566+ where parse = fieldTagged $ \fn o ->
2568+ <$> parseJSON (Object o)
2571+instance FromJSON RangeValue where
2572+ parseJSON = withObject "RangeValue" parse
2573+ where parse o = parseDate o
2575+ parseDate o = do lt <- o .:? "lt"
2579+ case (lt, lte, gt, gte) of
2580+ (Just a, _, Just b, _) -> return (RangeDateGtLt (GreaterThanD b) (LessThanD a))
2581+ (Just a, _, _, Just b)-> return (RangeDateGteLt (GreaterThanEqD b) (LessThanD a))
2582+ (_, Just a, Just b, _)-> return (RangeDateGtLte (GreaterThanD b) (LessThanEqD a))
2583+ (_, Just a, _, Just b)-> return (RangeDateGteLte (GreaterThanEqD b) (LessThanEqD a))
2584+ (_, _, Just a, _)-> return (RangeDateGt (GreaterThanD a))
2585+ (Just a, _, _, _)-> return (RangeDateLt (LessThanD a))
2586+ (_, _, _, Just a)-> return (RangeDateGte (GreaterThanEqD a))
2587+ (_, Just a, _, _)-> return (RangeDateLte (LessThanEqD a))
2588+ (Nothing, Nothing, Nothing, Nothing) -> mzero
2589+ parseDouble o = do lt <- o .:? "lt"
2593+ case (lt, lte, gt, gte) of
2594+ (Just a, _, Just b, _) -> return (RangeDoubleGtLt (GreaterThan b) (LessThan a))
2595+ (Just a, _, _, Just b)-> return (RangeDoubleGteLt (GreaterThanEq b) (LessThan a))
2596+ (_, Just a, Just b, _)-> return (RangeDoubleGtLte (GreaterThan b) (LessThanEq a))
2597+ (_, Just a, _, Just b)-> return (RangeDoubleGteLte (GreaterThanEq b) (LessThanEq a))
2598+ (_, _, Just a, _)-> return (RangeDoubleGt (GreaterThan a))
2599+ (Just a, _, _, _)-> return (RangeDoubleLt (LessThan a))
2600+ (_, _, _, Just a)-> return (RangeDoubleGte (GreaterThanEq a))
2601+ (_, Just a, _, _)-> return (RangeDoubleLte (LessThanEq a))
2602+ (Nothing, Nothing, Nothing, Nothing) -> mzero
2604+instance ToJSON PrefixQuery where
2605+ toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
2606+ object [ fieldName .= omitNulls base ]
2607+ where base = [ "value" .= queryValue
2608+ , "boost" .= boost ]
2610+instance FromJSON PrefixQuery where
2611+ parseJSON = withObject "PrefixQuery" parse
2612+ where parse = fieldTagged $ \fn o ->
2617+instance ToJSON NestedQuery where
2618+ toJSON (NestedQuery nqPath nqScoreType nqQuery) =
2619+ object [ "path" .= nqPath
2620+ , "score_mode" .= nqScoreType
2621+ , "query" .= nqQuery ]
2623+instance FromJSON NestedQuery where
2624+ parseJSON = withObject "NestedQuery" parse
2625+ where parse o = NestedQuery
2627+ <*> o .: "score_mode"
2630+instance ToJSON MoreLikeThisFieldQuery where
2631+ toJSON (MoreLikeThisFieldQuery text (FieldName fieldName)
2632+ percent mtf mqt stopwords mindf maxdf
2633+ minwl maxwl boostTerms boost analyzer) =
2634+ object [ fieldName .= omitNulls base ]
2635+ where base = [ "like_text" .= text
2636+ , "percent_terms_to_match" .= percent
2637+ , "min_term_freq" .= mtf
2638+ , "max_query_terms" .= mqt
2639+ , "stop_words" .= stopwords
2640+ , "min_doc_freq" .= mindf
2641+ , "max_doc_freq" .= maxdf
2642+ , "min_word_length" .= minwl
2643+ , "max_word_length" .= maxwl
2644+ , "boost_terms" .= boostTerms
2646+ , "analyzer" .= analyzer ]
2648+instance FromJSON MoreLikeThisFieldQuery where
2649+ parseJSON = withObject "MoreLikeThisFieldQuery" parse
2650+ where parse = fieldTagged $ \fn o ->
2651+ MoreLikeThisFieldQuery
2652+ <$> o .: "like_text"
2654+ <*> o .:? "percent_terms_to_match"
2655+ <*> o .:? "min_term_freq"
2656+ <*> o .:? "max_query_terms"
2657+ -- <*> (optionalNE =<< o .:? "stop_words")
2658+ <*> o .:? "stop_words"
2659+ <*> o .:? "min_doc_freq"
2660+ <*> o .:? "max_doc_freq"
2661+ <*> o .:? "min_word_length"
2662+ <*> o .:? "max_word_length"
2663+ <*> o .:? "boost_terms"
2665+ <*> o .:? "analyzer"
2666+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2668+instance ToJSON MoreLikeThisQuery where
2669+ toJSON (MoreLikeThisQuery text fields percent
2670+ mtf mqt stopwords mindf maxdf
2671+ minwl maxwl boostTerms boost analyzer) =
2673+ where base = [ "like_text" .= text
2674+ , "fields" .= fields
2675+ , "percent_terms_to_match" .= percent
2676+ , "min_term_freq" .= mtf
2677+ , "max_query_terms" .= mqt
2678+ , "stop_words" .= stopwords
2679+ , "min_doc_freq" .= mindf
2680+ , "max_doc_freq" .= maxdf
2681+ , "min_word_length" .= minwl
2682+ , "max_word_length" .= maxwl
2683+ , "boost_terms" .= boostTerms
2685+ , "analyzer" .= analyzer ]
2687+instance FromJSON MoreLikeThisQuery where
2688+ parseJSON = withObject "MoreLikeThisQuery" parse
2689+ where parse o = MoreLikeThisQuery
2690+ <$> o .: "like_text"
2691+ -- <*> (optionalNE =<< o .:? "fields")
2693+ <*> o .:? "percent_terms_to_match"
2694+ <*> o .:? "min_term_freq"
2695+ <*> o .:? "max_query_terms"
2696+ -- <*> (optionalNE =<< o .:? "stop_words")
2697+ <*> o .:? "stop_words"
2698+ <*> o .:? "min_doc_freq"
2699+ <*> o .:? "max_doc_freq"
2700+ <*> o .:? "min_word_length"
2701+ <*> o .:? "max_word_length"
2702+ <*> o .:? "boost_terms"
2704+ <*> o .:? "analyzer"
2705+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2707+instance ToJSON IndicesQuery where
2708+ toJSON (IndicesQuery indices query noMatch) =
2709+ omitNulls [ "indices" .= indices
2710+ , "no_match_query" .= noMatch
2711+ , "query" .= query ]
2713+instance FromJSON IndicesQuery where
2714+ parseJSON = withObject "IndicesQuery" parse
2715+ where parse o = IndicesQuery
2716+ <$> o .:? "indices" .!= []
2718+ <*> o .:? "no_match_query"
2720+instance ToJSON HasParentQuery where
2721+ toJSON (HasParentQuery queryType query scoreType) =
2722+ omitNulls [ "parent_type" .= queryType
2723+ , "score_type" .= scoreType
2724+ , "query" .= query ]
2726+instance FromJSON HasParentQuery where
2727+ parseJSON = withObject "HasParentQuery" parse
2728+ where parse o = HasParentQuery
2729+ <$> o .: "parent_type"
2731+ <*> o .:? "score_type"
2733+instance ToJSON HasChildQuery where
2734+ toJSON (HasChildQuery queryType query scoreType) =
2735+ omitNulls [ "query" .= query
2736+ , "score_type" .= scoreType
2737+ , "type" .= queryType ]
2739+instance FromJSON HasChildQuery where
2740+ parseJSON = withObject "HasChildQuery" parse
2741+ where parse o = HasChildQuery
2744+ <*> o .:? "score_type"
2746+instance ToJSON FuzzyQuery where
2747+ toJSON (FuzzyQuery (FieldName fieldName) queryText
2748+ prefixLength maxEx fuzziness boost) =
2749+ object [ fieldName .= omitNulls base ]
2750+ where base = [ "value" .= queryText
2751+ , "fuzziness" .= fuzziness
2752+ , "prefix_length" .= prefixLength
2754+ , "max_expansions" .= maxEx ]
2756+instance FromJSON FuzzyQuery where
2757+ parseJSON = withObject "FuzzyQuery" parse
2758+ where parse = fieldTagged $ \fn o ->
2761+ <*> o .: "prefix_length"
2762+ <*> o .: "max_expansions"
2763+ <*> o .: "fuzziness"
2766+instance ToJSON FuzzyLikeFieldQuery where
2767+ toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
2768+ fieldText maxTerms ignoreFreq fuzziness prefixLength
2770+ object [ fieldName .=
2771+ omitNulls [ "like_text" .= fieldText
2772+ , "max_query_terms" .= maxTerms
2773+ , "ignore_tf" .= ignoreFreq
2774+ , "fuzziness" .= fuzziness
2775+ , "prefix_length" .= prefixLength
2776+ , "analyzer" .= analyzer
2777+ , "boost" .= boost ]]
2779+instance FromJSON FuzzyLikeFieldQuery where
2780+ parseJSON = withObject "FuzzyLikeFieldQuery" parse
2781+ where parse = fieldTagged $ \fn o ->
2782+ FuzzyLikeFieldQuery fn
2783+ <$> o .: "like_text"
2784+ <*> o .: "max_query_terms"
2785+ <*> o .: "ignore_tf"
2786+ <*> o .: "fuzziness"
2787+ <*> o .: "prefix_length"
2789+ <*> o .:? "analyzer"
2791+instance ToJSON FuzzyLikeThisQuery where
2792+ toJSON (FuzzyLikeThisQuery fields text maxTerms
2793+ ignoreFreq fuzziness prefixLength boost analyzer) =
2795+ where base = [ "fields" .= fields
2796+ , "like_text" .= text
2797+ , "max_query_terms" .= maxTerms
2798+ , "ignore_tf" .= ignoreFreq
2799+ , "fuzziness" .= fuzziness
2800+ , "prefix_length" .= prefixLength
2801+ , "analyzer" .= analyzer
2802+ , "boost" .= boost ]
2804+instance FromJSON FuzzyLikeThisQuery where
2805+ parseJSON = withObject "FuzzyLikeThisQuery" parse
2806+ where parse o = FuzzyLikeThisQuery
2807+ <$> o .:? "fields" .!= []
2808+ <*> o .: "like_text"
2809+ <*> o .: "max_query_terms"
2810+ <*> o .: "ignore_tf"
2811+ <*> o .: "fuzziness"
2812+ <*> o .: "prefix_length"
2814+ <*> o .:? "analyzer"
2816+instance ToJSON FilteredQuery where
2817+ toJSON (FilteredQuery query fFilter) =
2818+ object [ "query" .= query
2819+ , "filter" .= fFilter ]
2821+instance FromJSON FilteredQuery where
2822+ parseJSON = withObject "FilteredQuery" parse
2823+ where parse o = FilteredQuery
2827+instance ToJSON DisMaxQuery where
2828+ toJSON (DisMaxQuery queries tiebreaker boost) =
2830+ where base = [ "queries" .= queries
2832+ , "tie_breaker" .= tiebreaker ]
2834+instance FromJSON DisMaxQuery where
2835+ parseJSON = withObject "DisMaxQuery" parse
2836+ where parse o = DisMaxQuery
2837+ <$> o .:? "queries" .!= []
2838+ <*> o .: "tie_breaker"
2841+instance ToJSON CommonTermsQuery where
2842+ toJSON (CommonTermsQuery (FieldName fieldName)
2843+ (QueryString query) cf lfo hfo msm
2844+ boost analyzer disableCoord) =
2845+ object [fieldName .= omitNulls base ]
2846+ where base = [ "query" .= query
2847+ , "cutoff_frequency" .= cf
2848+ , "low_freq_operator" .= lfo
2849+ , "minimum_should_match" .= msm
2851+ , "analyzer" .= analyzer
2852+ , "disable_coord" .= disableCoord
2853+ , "high_freq_operator" .= hfo ]
2855+instance FromJSON CommonTermsQuery where
2856+ parseJSON = withObject "CommonTermsQuery" parse
2857+ where parse = fieldTagged $ \fn o ->
2858+ CommonTermsQuery fn
2860+ <*> o .: "cutoff_frequency"
2861+ <*> o .: "low_freq_operator"
2862+ <*> o .: "high_freq_operator"
2863+ <*> o .:? "minimum_should_match"
2865+ <*> o .:? "analyzer"
2866+ <*> o .:? "disable_coord"
2868+instance ToJSON CommonMinimumMatch where
2869+ toJSON (CommonMinimumMatch mm) = toJSON mm
2870+ toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
2871+ object [ "low_freq" .= lowF
2872+ , "high_freq" .= highF ]
2874+instance FromJSON CommonMinimumMatch where
2875+ parseJSON v = parseMinimum v
2876+ <|> parseMinimumHighLow v
2877+ where parseMinimum = fmap CommonMinimumMatch . parseJSON
2878+ parseMinimumHighLow = fmap CommonMinimumMatchHighLow . withObject "CommonMinimumMatchHighLow" (\o ->
2879+ MinimumMatchHighLow
2880+ <$> o .: "low_freq"
2881+ <*> o .: "high_freq")
2884+instance ToJSON BoostingQuery where
2885+ toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
2886+ object [ "positive" .= bqPositiveQuery
2887+ , "negative" .= bqNegativeQuery
2888+ , "negative_boost" .= bqNegativeBoost ]
2890+instance FromJSON BoostingQuery where
2891+ parseJSON = withObject "BoostingQuery" parse
2892+ where parse o = BoostingQuery
2893+ <$> o .: "positive"
2894+ <*> o .: "negative"
2895+ <*> o .: "negative_boost"
2897+instance ToJSON BoolQuery where
2898+ toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
2900+ where base = [ "must" .= mustM
2901+ , "must_not" .= notM
2902+ , "should" .= shouldM
2903+ , "minimum_should_match" .= bqMin
2905+ , "disable_coord" .= disableCoord ]
2907+instance FromJSON BoolQuery where
2908+ parseJSON = withObject "BoolQuery" parse
2909+ where parse o = BoolQuery
2910+ <$> o .:? "must" .!= []
2911+ <*> o .:? "must_not" .!= []
2912+ <*> o .:? "should" .!= []
2913+ <*> o .:? "minimum_should_match"
2915+ <*> o .:? "disable_coord"
2917+instance ToJSON MatchQuery where
2918+ toJSON (MatchQuery (FieldName fieldName)
2919+ (QueryString mqQueryString) booleanOperator
2920+ zeroTermsQuery cutoffFrequency matchQueryType
2921+ analyzer maxExpansions lenient boost) =
2922+ object [ fieldName .= omitNulls base ]
2923+ where base = [ "query" .= mqQueryString
2924+ , "operator" .= booleanOperator
2925+ , "zero_terms_query" .= zeroTermsQuery
2926+ , "cutoff_frequency" .= cutoffFrequency
2927+ , "type" .= matchQueryType
2928+ , "analyzer" .= analyzer
2929+ , "max_expansions" .= maxExpansions
2930+ , "lenient" .= lenient
2931+ , "boost" .= boost ]
2933+instance FromJSON MatchQuery where
2934+ parseJSON = withObject "MatchQuery" parse
2935+ where parse = fieldTagged $ \fn o ->
2938+ <*> o .: "operator"
2939+ <*> o .: "zero_terms_query"
2940+ <*> o .:? "cutoff_frequency"
2942+ <*> o .:? "analyzer"
2943+ <*> o .:? "max_expansions"
2944+ <*> o .:? "lenient"
2947+instance ToJSON MultiMatchQuery where
2948+ toJSON (MultiMatchQuery fields (QueryString query) boolOp
2949+ ztQ tb mmqt cf analyzer maxEx lenient) =
2950+ object ["multi_match" .= omitNulls base]
2951+ where base = [ "fields" .= fmap toJSON fields
2953+ , "operator" .= boolOp
2954+ , "zero_terms_query" .= ztQ
2955+ , "tiebreaker" .= tb
2957+ , "cutoff_frequency" .= cf
2958+ , "analyzer" .= analyzer
2959+ , "max_expansions" .= maxEx
2960+ , "lenient" .= lenient ]
2962+instance FromJSON MultiMatchQuery where
2963+ parseJSON = withObject "MultiMatchQuery" parse
2964+ where parse raw = do o <- raw .: "multi_match"
2966+ <$> o .:? "fields" .!= []
2968+ <*> o .: "operator"
2969+ <*> o .: "zero_terms_query"
2970+ <*> o .:? "tiebreaker"
2972+ <*> o .:? "cutoff_frequency"
2973+ <*> o .:? "analyzer"
2974+ <*> o .:? "max_expansions"
2975+ <*> o .:? "lenient"
2977+instance ToJSON MultiMatchQueryType where
2978+ toJSON MultiMatchBestFields = "best_fields"
2979+ toJSON MultiMatchMostFields = "most_fields"
2980+ toJSON MultiMatchCrossFields = "cross_fields"
2981+ toJSON MultiMatchPhrase = "phrase"
2982+ toJSON MultiMatchPhrasePrefix = "phrase_prefix"
2984+instance FromJSON MultiMatchQueryType where
2985+ parseJSON = withText "MultiMatchPhrasePrefix" parse
2986+ where parse "best_fields" = pure MultiMatchBestFields
2987+ parse "most_fields" = pure MultiMatchMostFields
2988+ parse "cross_fields" = pure MultiMatchCrossFields
2989+ parse "phrase" = pure MultiMatchPhrase
2990+ parse "phrase_prefix" = pure MultiMatchPhrasePrefix
2991+ parse t = fail ("Unexpected MultiMatchPhrasePrefix: " <> show t)
2993+instance ToJSON BooleanOperator where
2994+ toJSON And = String "and"
2995+ toJSON Or = String "or"
2997+instance FromJSON BooleanOperator where
2998+ parseJSON = withText "BooleanOperator" parse
2999+ where parse "and" = pure And
3000+ parse "or" = pure Or
3001+ parse o = fail ("Unexpected BooleanOperator: " <> show o)
3003+instance ToJSON ZeroTermsQuery where
3004+ toJSON ZeroTermsNone = String "none"
3005+ toJSON ZeroTermsAll = String "all"
3007+instance FromJSON ZeroTermsQuery where
3008+ parseJSON = withText "ZeroTermsQuery" parse
3009+ where parse "none" = pure ZeroTermsNone
3010+ parse "all" = pure ZeroTermsAll
3011+ parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
3013+instance ToJSON MatchQueryType where
3014+ toJSON MatchPhrase = "phrase"
3015+ toJSON MatchPhrasePrefix = "phrase_prefix"
3017+instance FromJSON MatchQueryType where
3018+ parseJSON = withText "MatchQueryType" parse
3019+ where parse "phrase" = pure MatchPhrase
3020+ parse "phrase_prefix" = pure MatchPhrasePrefix
3021+ parse t = fail ("Unexpected MatchQueryType: " <> show t)
3023+instance FromJSON Status where
3024+ parseJSON (Object v) = Status <$>
3026+ (v .:? "status" .!= 200) <*>
3030+ parseJSON _ = empty
3033+instance ToJSON IndexSettings where
3034+ toJSON (IndexSettings s r) = object ["settings" .=
3036+ object ["number_of_shards" .= s, "number_of_replicas" .= r]
3040+instance FromJSON IndexSettings where
3041+ parseJSON = withObject "IndexSettings" parse
3042+ where parse o = do s <- o .: "settings"
3044+ IndexSettings <$> i .: "number_of_shards"
3045+ <*> i .: "number_of_replicas"
3047+instance ToJSON UpdatableIndexSetting where
3048+ toJSON (NumberOfReplicas x) = oPath ("index" :| ["number_of_replicas"]) x
3049+ toJSON (AutoExpandReplicas x) = oPath ("index" :| ["auto_expand_replicas"]) x
3050+ toJSON (RefreshInterval x) = oPath ("index" :| ["refresh_interval"]) (NominalDiffTimeJSON x)
3051+ toJSON (IndexConcurrency x) = oPath ("index" :| ["concurrency"]) x
3052+ toJSON (FailOnMergeFailure x) = oPath ("index" :| ["fail_on_merge_failure"]) x
3053+ toJSON (TranslogFlushThresholdOps x) = oPath ("index" :| ["translog", "flush_threshold_ops"]) x
3054+ toJSON (TranslogFlushThresholdSize x) = oPath ("index" :| ["translog", "flush_threshold_size"]) x
3055+ toJSON (TranslogFlushThresholdPeriod x) = oPath ("index" :| ["translog", "flush_threshold_period"]) (NominalDiffTimeJSON x)
3056+ toJSON (TranslogDisableFlush x) = oPath ("index" :| ["translog", "disable_flush"]) x
3057+ toJSON (CacheFilterMaxSize x) = oPath ("index" :| ["cache", "filter", "max_size"]) x
3058+ toJSON (CacheFilterExpire x) = oPath ("index" :| ["cache", "filter", "expire"]) (NominalDiffTimeJSON <$> x)
3059+ toJSON (GatewaySnapshotInterval x) = oPath ("index" :| ["gateway", "snapshot_interval"]) (NominalDiffTimeJSON x)
3060+ toJSON (RoutingAllocationInclude fs) = oPath ("index" :| ["routing", "allocation", "include"]) (attrFilterJSON fs)
3061+ toJSON (RoutingAllocationExclude fs) = oPath ("index" :| ["routing", "allocation", "exclude"]) (attrFilterJSON fs)
3062+ toJSON (RoutingAllocationRequire fs) = oPath ("index" :| ["routing", "allocation", "require"]) (attrFilterJSON fs)
3063+ toJSON (RoutingAllocationEnable x) = oPath ("index" :| ["routing", "allocation", "enable"]) x
3064+ toJSON (RoutingAllocationShardsPerNode x) = oPath ("index" :| ["routing", "allocation", "total_shards_per_node"]) x
3065+ toJSON (RecoveryInitialShards x) = oPath ("index" :| ["recovery", "initial_shards"]) x
3066+ toJSON (GCDeletes x) = oPath ("index" :| ["gc_deletes"]) (NominalDiffTimeJSON x)
3067+ toJSON (TTLDisablePurge x) = oPath ("index" :| ["ttl", "disable_purge"]) x
3068+ toJSON (TranslogFSType x) = oPath ("index" :| ["translog", "fs", "type"]) x
3069+ toJSON (IndexCompoundFormat x) = oPath ("index" :| ["compound_format"]) x
3070+ toJSON (IndexCompoundOnFlush x) = oPath ("index" :| ["compound_on_flush"]) x
3071+ toJSON (WarmerEnabled x) = oPath ("index" :| ["warmer", "enabled"]) x
3072+ toJSON (BlocksReadOnly x) = oPath ("blocks" :| ["read_only"]) x
3073+ toJSON (BlocksRead x) = oPath ("blocks" :| ["read"]) x
3074+ toJSON (BlocksWrite x) = oPath ("blocks" :| ["write"]) x
3075+ toJSON (BlocksMetaData x) = oPath ("blocks" :| ["metadata"]) x
3077+instance FromJSON UpdatableIndexSetting where
3078+ parseJSON = withObject "UpdatableIndexSetting" parse
3079+ where parse o = numberOfReplicas `taggedAt` ["index", "number_of_replicas"]
3080+ <|> autoExpandReplicas `taggedAt` ["index", "auto_expand_replicas"]
3081+ <|> refreshInterval `taggedAt` ["index", "refresh_interval"]
3082+ <|> indexConcurrency `taggedAt` ["index", "concurrency"]
3083+ <|> failOnMergeFailure `taggedAt` ["index", "fail_on_merge_failure"]
3084+ <|> translogFlushThresholdOps `taggedAt` ["index", "translog", "flush_threshold_ops"]
3085+ <|> translogFlushThresholdSize `taggedAt` ["index", "translog", "flush_threshold_size"]
3086+ <|> translogFlushThresholdPeriod `taggedAt` ["index", "translog", "flush_threshold_period"]
3087+ <|> translogDisableFlush `taggedAt` ["index", "translog", "disable_flush"]
3088+ <|> cacheFilterMaxSize `taggedAt` ["index", "cache", "filter", "max_size"]
3089+ <|> cacheFilterExpire `taggedAt` ["index", "cache", "filter", "expire"]
3090+ <|> gatewaySnapshotInterval `taggedAt` ["index", "gateway", "snapshot_interval"]
3091+ <|> routingAllocationInclude `taggedAt` ["index", "routing", "allocation", "include"]
3092+ <|> routingAllocationExclude `taggedAt` ["index", "routing", "allocation", "exclude"]
3093+ <|> routingAllocationRequire `taggedAt` ["index", "routing", "allocation", "require"]
3094+ <|> routingAllocationEnable `taggedAt` ["index", "routing", "allocation", "enable"]
3095+ <|> routingAllocationShardsPerNode `taggedAt` ["index", "routing", "allocation", "total_shards_per_node"]
3096+ <|> recoveryInitialShards `taggedAt` ["index", "recovery", "initial_shards"]
3097+ <|> gcDeletes `taggedAt` ["index", "gc_deletes"]
3098+ <|> ttlDisablePurge `taggedAt` ["index", "ttl", "disable_purge"]
3099+ <|> translogFSType `taggedAt` ["index", "translog", "fs", "type"]
3100+ <|> compoundFormat `taggedAt` ["index", "compound_format"]
3101+ <|> compoundOnFlush `taggedAt` ["index", "compound_on_flush"]
3102+ <|> warmerEnabled `taggedAt` ["index", "warmer", "enabled"]
3103+ <|> blocksReadOnly `taggedAt` ["blocks", "read_only"]
3104+ <|> blocksRead `taggedAt` ["blocks", "read"]
3105+ <|> blocksWrite `taggedAt` ["blocks", "write"]
3106+ <|> blocksMetaData `taggedAt` ["blocks", "metadata"]
3107+ where taggedAt f ks = taggedAt' f (Object o) ks
3108+ taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON (unStringlyTypeJSON v)))
3109+ taggedAt' f v (k:ks) = withObject "Object" (\o -> do v' <- o .: k
3110+ taggedAt' f v' ks) v
3111+ numberOfReplicas = pure . NumberOfReplicas
3112+ autoExpandReplicas = pure . AutoExpandReplicas
3113+ refreshInterval = pure . RefreshInterval . ndtJSON
3114+ indexConcurrency = pure . IndexConcurrency
3115+ failOnMergeFailure = pure . FailOnMergeFailure
3116+ translogFlushThresholdOps = pure . TranslogFlushThresholdOps
3117+ translogFlushThresholdSize = pure . TranslogFlushThresholdSize
3118+ translogFlushThresholdPeriod = pure . TranslogFlushThresholdPeriod . ndtJSON
3119+ translogDisableFlush = pure . TranslogDisableFlush
3120+ cacheFilterMaxSize = pure . CacheFilterMaxSize
3121+ cacheFilterExpire = pure . CacheFilterExpire . fmap ndtJSON
3122+ gatewaySnapshotInterval = pure . GatewaySnapshotInterval . ndtJSON
3123+ routingAllocationInclude = fmap RoutingAllocationInclude . parseAttrFilter
3124+ routingAllocationExclude = fmap RoutingAllocationExclude . parseAttrFilter
3125+ routingAllocationRequire = fmap RoutingAllocationRequire . parseAttrFilter
3126+ routingAllocationEnable = pure . RoutingAllocationEnable
3127+ routingAllocationShardsPerNode = pure . RoutingAllocationShardsPerNode
3128+ recoveryInitialShards = pure . RecoveryInitialShards
3129+ gcDeletes = pure . GCDeletes . ndtJSON
3130+ ttlDisablePurge = pure . TTLDisablePurge
3131+ translogFSType = pure . TranslogFSType
3132+ compoundFormat = pure . IndexCompoundFormat
3133+ compoundOnFlush = pure . IndexCompoundOnFlush
3134+ warmerEnabled = pure . WarmerEnabled
3135+ blocksReadOnly = pure . BlocksReadOnly
3136+ blocksRead = pure . BlocksRead
3137+ blocksWrite = pure . BlocksWrite
3138+ blocksMetaData = pure . BlocksMetaData
3140+instance FromJSON IndexSettingsSummary where
3141+ parseJSON = withObject "IndexSettingsSummary" parse
3142+ where parse o = case HM.toList o of
3143+ [(ixn, v@(Object o'))] -> IndexSettingsSummary (IndexName ixn)
3145+ <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings")
3146+ _ -> fail "Expected single-key object with index name"
3147+ redundant (NumberOfReplicas _) = True
3148+ redundant _ = False
3150+-- | For some reason in several settings APIs, all leaf values get returned
3151+-- as strings. This function attepmts to recover from this for all
3152+-- non-recursive JSON types. If nothing can be done, the value is left alone.
3153+unStringlyTypeJSON :: Value -> Value
3154+unStringlyTypeJSON (String "true") = Bool True
3155+unStringlyTypeJSON (String "false") = Bool False
3156+unStringlyTypeJSON (String "null") = Null
3157+unStringlyTypeJSON v@(String t) = case readMay (T.unpack t) of
3160+unStringlyTypeJSON v = v
3163+parseSettings :: Object -> Parser [UpdatableIndexSetting]
3164+parseSettings o = do
3166+ -- slice the index object into singleton hashmaps and try to parse each
3167+ parses <- forM (HM.toList o') $ \(k, v) -> do
3168+ -- blocks are now nested into the "index" key, which is not how they're serialized
3169+ let atRoot = Object (HM.singleton k v)
3170+ let atIndex = Object (HM.singleton "index" atRoot)
3171+ optional (parseJSON atRoot <|> parseJSON atIndex)
3172+ return (catMaybes parses)
3174+oPath :: ToJSON a => NonEmpty Text -> a -> Value
3175+oPath (k :| []) v = object [k .= v]
3176+oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
3178+attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
3179+attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
3180+ | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
3182+parseAttrFilter :: Value -> Parser (NonEmpty NodeAttrFilter)
3183+parseAttrFilter = withObject "NonEmpty NodeAttrFilter" parse
3184+ where parse o = case HM.toList o of
3185+ [] -> fail "Expected non-empty list of NodeAttrFilters"
3186+ x:xs -> DT.mapM (uncurry parse') (x :| xs)
3187+ parse' n = withText "Text" $ \t ->
3188+ case T.splitOn "," t of
3189+ fv:fvs -> return (NodeAttrFilter (NodeAttrName n) (fv :| fvs))
3190+ [] -> fail "Expected non-empty list of filter values"
3192+instance ToJSON ReplicaBounds where
3193+ toJSON (ReplicasBounded a b) = String (showText a <> "-" <> showText b)
3194+ toJSON (ReplicasLowerBounded a) = String (showText a <> "-all")
3195+ toJSON ReplicasUnbounded = Bool False
3197+instance FromJSON ReplicaBounds where
3198+ parseJSON v = withText "ReplicaBounds" parseText v
3199+ <|> withBool "ReplicaBounds" parseBool v
3200+ where parseText t = case T.splitOn "-" t of
3201+ [a, "all"] -> ReplicasLowerBounded <$> parseReadText a
3202+ [a, b] -> ReplicasBounded <$> parseReadText a
3203+ <*> parseReadText b
3204+ _ -> fail ("Could not parse ReplicaBounds: " <> show t)
3205+ parseBool False = pure ReplicasUnbounded
3206+ parseBool _ = fail "ReplicasUnbounded cannot be represented with True"
3208+instance ToJSON AllocationPolicy where
3209+ toJSON AllocAll = String "all"
3210+ toJSON AllocPrimaries = String "primaries"
3211+ toJSON AllocNewPrimaries = String "new_primaries"
3212+ toJSON AllocNone = String "none"
3214+instance FromJSON AllocationPolicy where
3215+ parseJSON = withText "AllocationPolicy" parse
3216+ where parse "all" = pure AllocAll
3217+ parse "primaries" = pure AllocPrimaries
3218+ parse "new_primaries" = pure AllocNewPrimaries
3219+ parse "none" = pure AllocNone
3220+ parse t = fail ("Invlaid AllocationPolicy: " <> show t)
3222+instance ToJSON InitialShardCount where
3223+ toJSON QuorumShards = String "quorum"
3224+ toJSON QuorumMinus1Shards = String "quorum-1"
3225+ toJSON FullShards = String "full"
3226+ toJSON FullMinus1Shards = String "full-1"
3227+ toJSON (ExplicitShards x) = toJSON x
3229+instance FromJSON InitialShardCount where
3230+ parseJSON v = withText "InitialShardCount" parseText v
3231+ <|> ExplicitShards <$> parseJSON v
3232+ where parseText "quorum" = pure QuorumShards
3233+ parseText "quorum-1" = pure QuorumMinus1Shards
3234+ parseText "full" = pure FullShards
3235+ parseText "full-1" = pure FullMinus1Shards
3236+ parseText _ = mzero
3238+instance ToJSON FSType where
3239+ toJSON FSSimple = "simple"
3240+ toJSON FSBuffered = "buffered"
3242+instance FromJSON FSType where
3243+ parseJSON = withText "FSType" parse
3244+ where parse "simple" = pure FSSimple
3245+ parse "buffered" = pure FSBuffered
3246+ parse t = fail ("Invalid FSType: " <> show t)
3248+instance ToJSON CompoundFormat where
3249+ toJSON (CompoundFileFormat x) = Bool x
3250+ toJSON (MergeSegmentVsTotalIndex x) = toJSON x
3252+instance FromJSON CompoundFormat where
3253+ parseJSON v = CompoundFileFormat <$> parseJSON v
3254+ <|> MergeSegmentVsTotalIndex <$> parseJSON v
3256+instance ToJSON NominalDiffTimeJSON where
3257+ toJSON (NominalDiffTimeJSON t) = String (showText (round t :: Integer) <> "s")
3259+instance FromJSON NominalDiffTimeJSON where
3260+ parseJSON = withText "NominalDiffTime" parse
3261+ where parse t = case T.takeEnd 1 t of
3262+ "s" -> NominalDiffTimeJSON . fromInteger <$> parseReadText (T.dropEnd 1 t)
3263+ _ -> fail "Invalid or missing NominalDiffTime unit (expected s)"
3265+instance ToJSON IndexTemplate where
3266+ toJSON (IndexTemplate p s m) = merge
3267+ (object [ "template" .= p
3268+ , "mappings" .= foldl' merge (object []) m
3272+ merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
3274+ merge _ _ = undefined
3276+instance (FromJSON a) => FromJSON (EsResult a) where
3277+ parseJSON jsonVal@(Object v) = do
3278+ found <- v .:? "found" .!= False
3280+ then parseJSON jsonVal
3281+ else return Nothing
3282+ EsResult <$> v .: "_index" <*>
3286+ parseJSON _ = empty
3288+instance (FromJSON a) => FromJSON (EsResultFound a) where
3289+ parseJSON (Object v) = EsResultFound <$>
3290+ v .: "_version" <*>
3292+ parseJSON _ = empty
3294+instance FromJSON EsError where
3295+ parseJSON (Object v) = EsError <$>
3297+ (v .: "error" <|> (v .: "error" >>= (.: "reason")))
3298+ parseJSON _ = empty
3300+instance FromJSON IndexAliasesSummary where
3301+ parseJSON = withObject "IndexAliasesSummary" parse
3302+ where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)
3303+ go ixn = withObject "index aliases" $ \ia -> do
3304+ aliases <- ia .:? "aliases" .!= mempty
3305+ forM (HM.toList aliases) $ \(aName, v) -> do
3306+ let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))
3307+ IndexAliasSummary indexAlias <$> parseJSON v
3310+instance ToJSON IndexAliasAction where
3311+ toJSON (AddAlias ia opts) = object ["add" .= (iaObj <> optsObj)]
3312+ where Object iaObj = toJSON ia
3313+ Object optsObj = toJSON opts
3314+ toJSON (RemoveAlias ia) = object ["remove" .= iaObj]
3315+ where Object iaObj = toJSON ia
3317+instance ToJSON IndexAlias where
3318+ toJSON IndexAlias {..} = object ["index" .= srcIndex
3319+ , "alias" .= indexAlias
3322+instance ToJSON IndexAliasCreate where
3323+ toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)
3324+ where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter
3325+ Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting
3327+instance ToJSON AliasRouting where
3328+ toJSON (AllAliasRouting v) = object ["routing" .= v]
3329+ toJSON (GranularAliasRouting srch idx) = object (catMaybes prs)
3330+ where prs = [("search_routing" .=) <$> srch
3331+ ,("index_routing" .=) <$> idx]
3333+instance FromJSON AliasRouting where
3334+ parseJSON = withObject "AliasRouting" parse
3335+ where parse o = parseAll o <|> parseGranular o
3336+ parseAll o = AllAliasRouting <$> o .: "routing"
3337+ parseGranular o = do
3338+ sr <- o .:? "search_routing"
3339+ ir <- o .:? "index_routing"
3340+ if isNothing sr && isNothing ir
3341+ then fail "Both search_routing and index_routing can't be blank"
3342+ else return (GranularAliasRouting sr ir)
3344+instance FromJSON IndexAliasCreate where
3345+ parseJSON v = withObject "IndexAliasCreate" parse v
3346+ where parse o = IndexAliasCreate <$> optional (parseJSON v)
3349+instance ToJSON SearchAliasRouting where
3350+ toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
3352+instance FromJSON SearchAliasRouting where
3353+ parseJSON = withText "SearchAliasRouting" parse
3354+ where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3356+instance ToJSON Search where
3357+ toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
3358+ omitNulls [ "query" .= query
3359+ , "filter" .= sFilter
3361+ , "aggregations" .= searchAggs
3362+ , "highlight" .= highlight
3365+ , "track_scores" .= sTrackSortScores
3366+ , "fields" .= sFields
3367+ , "_source" .= sSource]
3370+instance ToJSON Source where
3371+ toJSON NoSource = toJSON False
3372+ toJSON (SourcePatterns patterns) = toJSON patterns
3373+ toJSON (SourceIncludeExclude incl excl) = object [ "include" .= incl, "exclude" .= excl ]
3375+instance ToJSON PatternOrPatterns where
3376+ toJSON (PopPattern pattern) = toJSON pattern
3377+ toJSON (PopPatterns patterns) = toJSON patterns
3379+instance ToJSON Include where
3380+ toJSON (Include patterns) = toJSON patterns
3382+instance ToJSON Exclude where
3383+ toJSON (Exclude patterns) = toJSON patterns
3385+instance ToJSON Pattern where
3386+ toJSON (Pattern pattern) = toJSON pattern
3389+instance ToJSON FieldHighlight where
3390+ toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
3391+ object [ fName .= fSettings ]
3392+ toJSON (FieldHighlight (FieldName fName) Nothing) =
3393+ object [ fName .= emptyObject ]
3395+instance ToJSON Highlights where
3396+ toJSON (Highlights global fields) =
3397+ omitNulls (("fields" .= fields)
3398+ : highlightSettingsPairs global)
3400+instance ToJSON HighlightSettings where
3401+ toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
3403+highlightSettingsPairs :: Maybe HighlightSettings -> [Pair]
3404+highlightSettingsPairs Nothing = []
3405+highlightSettingsPairs (Just (Plain plh)) = plainHighPairs (Just plh)
3406+highlightSettingsPairs (Just (Postings ph)) = postHighPairs (Just ph)
3407+highlightSettingsPairs (Just (FastVector fvh)) = fastVectorHighPairs (Just fvh)
3410+plainHighPairs :: Maybe PlainHighlight -> [Pair]
3411+plainHighPairs Nothing = []
3412+plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
3413+ [ "type" .= String "plain"]
3414+ ++ commonHighlightPairs plCom
3415+ ++ nonPostingsToPairs plNonPost
3417+postHighPairs :: Maybe PostingsHighlight -> [Pair]
3418+postHighPairs Nothing = []
3419+postHighPairs (Just (PostingsHighlight pCom)) =
3420+ ("type" .= String "postings")
3421+ : commonHighlightPairs pCom
3423+fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
3424+fastVectorHighPairs Nothing = []
3425+fastVectorHighPairs (Just
3426+ (FastVectorHighlight fvCom fvNonPostSettings fvBoundChars
3427+ fvBoundMaxScan fvFragOff fvMatchedFields
3429+ [ "type" .= String "fvh"
3430+ , "boundary_chars" .= fvBoundChars
3431+ , "boundary_max_scan" .= fvBoundMaxScan
3432+ , "fragment_offset" .= fvFragOff
3433+ , "matched_fields" .= fvMatchedFields
3434+ , "phraseLimit" .= fvPhraseLim]
3435+ ++ commonHighlightPairs fvCom
3436+ ++ nonPostingsToPairs fvNonPostSettings
3438+deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
3439+deleteSeveral ks hm = foldr HM.delete hm ks
3441+commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
3442+commonHighlightPairs Nothing = []
3443+commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
3444+ chNoMatchSize chHighlightQuery
3445+ chRequireFieldMatch)) =
3446+ [ "order" .= chScore
3447+ , "force_source" .= chForceSource
3448+ , "encoder" .= chEncoder
3449+ , "no_match_size" .= chNoMatchSize
3450+ , "highlight_query" .= chHighlightQuery
3451+ , "require_fieldMatch" .= chRequireFieldMatch]
3452+ ++ highlightTagToPairs chTag
3455+nonPostingsToPairs :: Maybe NonPostings -> [Pair]
3456+nonPostingsToPairs Nothing = []
3457+nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
3458+ [ "fragment_size" .= npFragSize
3459+ , "number_of_fragments" .= npNumOfFrags]
3461+parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
3462+parseNEJSON [] = fail "Expected non-empty list"
3463+parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
3466+instance ToJSON HighlightEncoder where
3467+ toJSON DefaultEncoder = String "default"
3468+ toJSON HTMLEncoder = String "html"
3470+highlightTagToPairs :: Maybe HighlightTag -> [Pair]
3471+highlightTagToPairs (Just (TagSchema _)) = [ "scheme" .= String "default"]
3472+highlightTagToPairs (Just (CustomTags (pre, post))) = [ "pre_tags" .= pre
3473+ , "post_tags" .= post]
3474+highlightTagToPairs Nothing = []
3476+instance ToJSON SortSpec where
3477+ toJSON (DefaultSortSpec
3478+ (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped
3479+ dsSortMode dsMissingSort dsNestedFilter)) =
3480+ object [dsSortFieldName .= omitNulls base] where
3481+ base = [ "order" .= dsSortOrder
3482+ , "ignore_unmapped" .= dsIgnoreUnmapped
3483+ , "mode" .= dsSortMode
3484+ , "missing" .= dsMissingSort
3485+ , "nested_filter" .= dsNestedFilter ]
3487+ toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
3488+ object [ "unit" .= units
3489+ , field .= gdsLatLon
3490+ , "order" .= gdsSortOrder ]
3493+instance ToJSON SortOrder where
3494+ toJSON Ascending = String "asc"
3495+ toJSON Descending = String "desc"
3498+instance ToJSON SortMode where
3499+ toJSON SortMin = String "min"
3500+ toJSON SortMax = String "max"
3501+ toJSON SortSum = String "sum"
3502+ toJSON SortAvg = String "avg"
3505+instance ToJSON Missing where
3506+ toJSON LastMissing = String "_last"
3507+ toJSON FirstMissing = String "_first"
3508+ toJSON (CustomMissing txt) = String txt
3511+instance ToJSON ScoreType where
3512+ toJSON ScoreTypeMax = "max"
3513+ toJSON ScoreTypeAvg = "avg"
3514+ toJSON ScoreTypeSum = "sum"
3515+ toJSON ScoreTypeNone = "none"
3517+instance FromJSON ScoreType where
3518+ parseJSON = withText "ScoreType" parse
3519+ where parse "max" = pure ScoreTypeMax
3520+ parse "avg" = pure ScoreTypeAvg
3521+ parse "sum" = pure ScoreTypeSum
3522+ parse "none" = pure ScoreTypeNone
3523+ parse t = fail ("Unexpected ScoreType: " <> show t)
3525+instance ToJSON Distance where
3526+ toJSON (Distance dCoefficient dUnit) =
3527+ String boltedTogether where
3528+ coefText = showText dCoefficient
3529+ (String unitText) = toJSON dUnit
3530+ boltedTogether = mappend coefText unitText
3532+instance FromJSON Distance where
3533+ parseJSON = withText "Distance" parse
3534+ where parse t = Distance <$> parseCoeff nT
3535+ <*> parseJSON (String unitT)
3536+ where (nT, unitT) = T.span validForNumber t
3537+ -- may be a better way to do this
3538+ validForNumber '-' = True
3539+ validForNumber '.' = True
3540+ validForNumber 'e' = True
3541+ validForNumber c = isNumber c
3542+ parseCoeff "" = fail "Empty string cannot be parsed as number"
3543+ parseCoeff s = return (read (T.unpack s))
3545+instance ToJSON DistanceUnit where
3546+ toJSON Miles = String "mi"
3547+ toJSON Yards = String "yd"
3548+ toJSON Feet = String "ft"
3549+ toJSON Inches = String "in"
3550+ toJSON Kilometers = String "km"
3551+ toJSON Meters = String "m"
3552+ toJSON Centimeters = String "cm"
3553+ toJSON Millimeters = String "mm"
3554+ toJSON NauticalMiles = String "nmi"
3557+instance FromJSON DistanceUnit where
3558+ parseJSON = withText "DistanceUnit" parse
3559+ where parse "mi" = pure Miles
3560+ parse "yd" = pure Yards
3561+ parse "ft" = pure Feet
3562+ parse "in" = pure Inches
3563+ parse "km" = pure Kilometers
3564+ parse "m" = pure Meters
3565+ parse "cm" = pure Centimeters
3566+ parse "mm" = pure Millimeters
3567+ parse "nmi" = pure NauticalMiles
3568+ parse u = fail ("Unrecognized DistanceUnit: " <> show u)
3570+instance ToJSON DistanceType where
3571+ toJSON Arc = String "arc"
3572+ toJSON SloppyArc = String "sloppy_arc"
3573+ toJSON Plane = String "plane"
3575+instance FromJSON DistanceType where
3576+ parseJSON = withText "DistanceType" parse
3577+ where parse "arc" = pure Arc
3578+ parse "sloppy_arc" = pure SloppyArc
3579+ parse "plane" = pure Plane
3580+ parse t = fail ("Unrecognized DistanceType: " <> show t)
3583+instance ToJSON OptimizeBbox where
3584+ toJSON NoOptimizeBbox = String "none"
3585+ toJSON (OptimizeGeoFilterType gft) = toJSON gft
3587+instance FromJSON OptimizeBbox where
3588+ parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
3589+ <|> parseOptimize v
3590+ where parseNoOptimize "none" = pure NoOptimizeBbox
3591+ parseNoOptimize _ = mzero
3592+ parseOptimize = fmap OptimizeGeoFilterType . parseJSON
3594+instance ToJSON GeoBoundingBoxConstraint where
3595+ toJSON (GeoBoundingBoxConstraint
3596+ (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =
3597+ object [gbbcGeoBBField .= gbbcConstraintBox
3598+ , "_cache" .= cache
3601+instance FromJSON GeoBoundingBoxConstraint where
3602+ parseJSON = withObject "GeoBoundingBoxConstraint" parse
3603+ where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of
3604+ [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)
3606+ <*> o .:? "_cache" .!= defaultCache
3608+ _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
3610+instance ToJSON GeoFilterType where
3611+ toJSON GeoFilterMemory = String "memory"
3612+ toJSON GeoFilterIndexed = String "indexed"
3614+instance FromJSON GeoFilterType where
3615+ parseJSON = withText "GeoFilterType" parse
3616+ where parse "memory" = pure GeoFilterMemory
3617+ parse "indexed" = pure GeoFilterIndexed
3618+ parse t = fail ("Unrecognized GeoFilterType: " <> show t)
3620+instance ToJSON GeoBoundingBox where
3621+ toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
3622+ object ["top_left" .= gbbTopLeft
3623+ , "bottom_right" .= gbbBottomRight]
3625+instance FromJSON GeoBoundingBox where
3626+ parseJSON = withObject "GeoBoundingBox" parse
3627+ where parse o = GeoBoundingBox
3628+ <$> o .: "top_left"
3629+ <*> o .: "bottom_right"
3631+instance ToJSON LatLon where
3632+ toJSON (LatLon lLat lLon) =
3633+ object ["lat" .= lLat
3636+instance FromJSON LatLon where
3637+ parseJSON = withObject "LatLon" parse
3638+ where parse o = LatLon <$> o .: "lat"
3641+-- index for smaller ranges, fielddata for longer ranges
3642+instance ToJSON RangeExecution where
3643+ toJSON RangeExecutionIndex = "index"
3644+ toJSON RangeExecutionFielddata = "fielddata"
3647+instance FromJSON RangeExecution where
3648+ parseJSON = withText "RangeExecution" parse
3649+ where parse "index" = pure RangeExecutionIndex
3650+ parse "fielddata" = pure RangeExecutionFielddata
3651+ parse t = error ("Unrecognized RangeExecution " <> show t)
3653+instance ToJSON RegexpFlags where
3654+ toJSON AllRegexpFlags = String "ALL"
3655+ toJSON NoRegexpFlags = String "NONE"
3656+ toJSON (SomeRegexpFlags (h :| fs)) = String $ T.intercalate "|" flagStrs
3657+ where flagStrs = map flagStr . nub $ h:fs
3658+ flagStr AnyString = "ANYSTRING"
3659+ flagStr Automaton = "AUTOMATON"
3660+ flagStr Complement = "COMPLEMENT"
3661+ flagStr Empty = "EMPTY"
3662+ flagStr Intersection = "INTERSECTION"
3663+ flagStr Interval = "INTERVAL"
3665+instance FromJSON RegexpFlags where
3666+ parseJSON = withText "RegexpFlags" parse
3667+ where parse "ALL" = pure AllRegexpFlags
3668+ parse "NONE" = pure NoRegexpFlags
3669+ parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
3671+instance FromJSON RegexpFlag where
3672+ parseJSON = withText "RegexpFlag" parse
3673+ where parse "ANYSTRING" = pure AnyString
3674+ parse "AUTOMATON" = pure Automaton
3675+ parse "COMPLEMENT" = pure Complement
3676+ parse "EMPTY" = pure Empty
3677+ parse "INTERSECTION" = pure Intersection
3678+ parse "INTERVAL" = pure Interval
3679+ parse f = fail ("Unknown RegexpFlag: " <> show f)
3681+instance ToJSON Term where
3682+ toJSON (Term field value) = object ["term" .= object
3685+instance FromJSON Term where
3686+ parseJSON = withObject "Term" parse
3687+ where parse o = do termObj <- o .: "term"
3688+ case HM.toList termObj of
3689+ [(fn, v)] -> Term fn <$> parseJSON v
3690+ _ -> fail "Expected object with 1 field-named key"
3692+instance ToJSON BoolMatch where
3693+ toJSON (MustMatch term cache) = object ["must" .= term,
3695+ toJSON (MustNotMatch term cache) = object ["must_not" .= term,
3697+ toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
3700+instance FromJSON BoolMatch where
3701+ parseJSON = withObject "BoolMatch" parse
3702+ where parse o = mustMatch `taggedWith` "must"
3703+ <|> mustNotMatch `taggedWith` "must_not"
3704+ <|> shouldMatch `taggedWith` "should"
3705+ where taggedWith parser k = parser =<< o .: k
3706+ mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
3707+ mustNotMatch t = MustNotMatch t <$> o .:? "_cache" .!= defaultCache
3708+ shouldMatch t = ShouldMatch t <$> o .:? "_cache" .!= defaultCache
3710+instance (FromJSON a) => FromJSON (SearchResult a) where
3711+ parseJSON (Object v) = SearchResult <$>
3713+ v .: "timed_out" <*>
534 v .: "hits" <*>
3715 v .: "hits" <*>
535 v .:? "aggregations" <*>
3716 v .:? "aggregations" <*>
536− v .:? "_scroll_id" <*>
3717+ v .:? "_scroll_id"
538 parseJSON _ = empty
3718 parseJSON _ = empty
540−newtype ScrollId =
3720+instance (FromJSON a) => FromJSON (SearchHits a) where
541− ScrollId Text
3721+ parseJSON (Object v) = SearchHits <$>
542− deriving (Eq, Show, Ord, ToJSON, FromJSON)
3722+ v .: "total" <*>
3723+ v .: "max_score" <*>
3725+ parseJSON _ = empty
3727+instance (FromJSON a) => FromJSON (Hit a) where
3728+ parseJSON (Object v) = Hit <$>
3733+ v .:? "_source" <*>
3735+ parseJSON _ = empty
3737+instance FromJSON ShardResult where
3738+ parseJSON (Object v) = ShardResult <$>
3740+ v .: "successful" <*>
3742+ parseJSON _ = empty
3745+instance FromJSON DocVersion where
3748+ maybe (fail "DocVersion out of range") return $ mkDocVersion i
3750+-- This insanity is because ES *sometimes* returns Replica/Shard counts as strings
3751+instance FromJSON ReplicaCount where
3752+ parseJSON v = parseAsInt v
3753+ <|> parseAsString v
3754+ where parseAsInt = fmap ReplicaCount . parseJSON
3755+ parseAsString = withText "ReplicaCount" (fmap ReplicaCount . parseReadText)
3757+instance FromJSON ShardCount where
3758+ parseJSON v = parseAsInt v
3759+ <|> parseAsString v
3760+ where parseAsInt = fmap ShardCount . parseJSON
3761+ parseAsString = withText "ShardCount" (fmap ShardCount . parseReadText)
3763+instance Bounded DocVersion where
3764+ minBound = DocVersion 1
3765+ maxBound = DocVersion 9200000000000000000 -- 9.2e+18
3767+instance Enum DocVersion where
3769+ | x /= maxBound = DocVersion (succ $ docVersionNumber x)
3770+ | otherwise = succError "DocVersion"
3772+ | x /= minBound = DocVersion (pred $ docVersionNumber x)
3773+ | otherwise = predError "DocVersion"
3775+ fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
3776+ fromEnum = docVersionNumber
3777+ enumFrom = boundedEnumFrom
3778+ enumFromThen = boundedEnumFromThen
3780+-- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
3781+newtype EsUsername = EsUsername { esUsername :: Text } deriving (Read, Show, Eq)
3783+-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
3784+newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3787+data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
3788+ | AllSnapshotRepos deriving (Eq, Generic, Show, Typeable)
3791+-- | Either specifies an exact repo name or one with globs in it,
3792+-- e.g. @RepoPattern "foo*"@ __NOTE__: Patterns are not supported on ES < 1.7
3793+data SnapshotRepoPattern = ExactRepo SnapshotRepoName
3795+ deriving (Eq, Generic, Show, Typeable)
3797+-- | The unique name of a snapshot repository.
3798+newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3799+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
3802+-- | A generic representation of a snapshot repo. This is what gets
3803+-- sent to and parsed from the server. For repo types enabled by
3804+-- plugins that aren't exported by this library, consider making a
3805+-- custom type which implements 'SnapshotRepo'. If it is a common repo
3806+-- type, consider submitting a pull request to have it included in the
3808+data GenericSnapshotRepo = GenericSnapshotRepo {
3809+ gSnapshotRepoName :: SnapshotRepoName
3810+ , gSnapshotRepoType :: SnapshotRepoType
3811+ , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
3812+ } deriving (Eq, Generic, Show, Typeable)
3815+instance SnapshotRepo GenericSnapshotRepo where
3816+ toGSnapshotRepo = id
3817+ fromGSnapshotRepo = Right
3820+newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3821+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
3824+-- | Opaque representation of snapshot repo settings. Instances of
3825+-- 'SnapshotRepo' will produce this.
3826+newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
3827+ deriving (Eq, Generic, Show, Typeable, ToJSON)
3830+ -- Regardless of whether you send strongly typed json, my version of
3831+ -- ES sends back stringly typed json in the settings, e.g. booleans
3832+ -- as strings, so we'll try to convert them.
3833+instance FromJSON GenericSnapshotRepoSettings where
3834+ parseJSON = fmap (GenericSnapshotRepoSettings . fmap unStringlyTypeJSON). parseJSON
3836+-- | The result of running 'verifySnapshotRepo'.
3837+newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
3838+ deriving (Eq, Generic, Show, Typeable)
3841+instance FromJSON SnapshotVerification where
3842+ parseJSON = withObject "SnapshotVerification" parse
3846+ SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
3847+ parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
3848+ SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
3851+-- | A node that has verified a snapshot
3852+data SnapshotNodeVerification = SnapshotNodeVerification {
3853+ snvFullId :: FullNodeId
3854+ , snvNodeName :: NodeName
3855+ } deriving (Eq, Generic, Show, Typeable)
3858+-- | Unique, automatically-generated name assigned to nodes that are
3859+-- usually returned in node-oriented APIs.
3860+newtype FullNodeId = FullNodeId { fullNodeId :: Text }
3861+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3864+-- | A human-readable node name that is supplied by the user in the
3865+-- node config or automatically generated by ElasticSearch.
3866+newtype NodeName = NodeName { nodeName :: Text }
3867+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3869+newtype ClusterName = ClusterName { clusterName :: Text }
3870+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3872+data NodesInfo = NodesInfo {
3873+ nodesInfo :: [NodeInfo]
3874+ , nodesClusterName :: ClusterName
3875+ } deriving (Eq, Show, Generic, Typeable)
3877+data NodesStats = NodesStats {
3878+ nodesStats :: [NodeStats]
3879+ , nodesStatsClusterName :: ClusterName
3880+ } deriving (Eq, Show, Generic, Typeable)
3882+data NodeStats = NodeStats {
3883+ nodeStatsName :: NodeName
3884+ , nodeStatsFullId :: FullNodeId
3885+ , nodeStatsBreakersStats :: Maybe NodeBreakersStats
3886+ , nodeStatsHTTP :: NodeHTTPStats
3887+ , nodeStatsTransport :: NodeTransportStats
3888+ , nodeStatsFS :: NodeFSStats
3889+ , nodeStatsNetwork :: NodeNetworkStats
3890+ , nodeStatsThreadPool :: NodeThreadPoolsStats
3891+ , nodeStatsJVM :: NodeJVMStats
3892+ , nodeStatsProcess :: NodeProcessStats
3893+ , nodeStatsOS :: NodeOSStats
3894+ , nodeStatsIndices :: NodeIndicesStats
3895+ } deriving (Eq, Show, Generic, Typeable)
3897+data NodeBreakersStats = NodeBreakersStats {
3898+ nodeStatsParentBreaker :: NodeBreakerStats
3899+ , nodeStatsRequestBreaker :: NodeBreakerStats
3900+ , nodeStatsFieldDataBreaker :: NodeBreakerStats
3901+ } deriving (Eq, Show, Generic, Typeable)
3903+data NodeBreakerStats = NodeBreakerStats {
3904+ nodeBreakersTripped :: Int
3905+ , nodeBreakersOverhead :: Double
3906+ , nodeBreakersEstSize :: Bytes
3907+ , nodeBreakersLimitSize :: Bytes
3908+ } deriving (Eq, Show, Generic, Typeable)
3910+data NodeHTTPStats = NodeHTTPStats {
3911+ nodeHTTPTotalOpened :: Int
3912+ , nodeHTTPCurrentOpen :: Int
3913+ } deriving (Eq, Show, Generic, Typeable)
3915+data NodeTransportStats = NodeTransportStats {
3916+ nodeTransportTXSize :: Bytes
3917+ , nodeTransportCount :: Int
3918+ , nodeTransportRXSize :: Bytes
3919+ , nodeTransportRXCount :: Int
3920+ , nodeTransportServerOpen :: Int
3921+ } deriving (Eq, Show, Generic, Typeable)
3923+data NodeFSStats = NodeFSStats {
3924+ nodeFSDataPaths :: [NodeDataPathStats]
3925+ , nodeFSTotal :: NodeFSTotalStats
3926+ , nodeFSTimestamp :: UTCTime
3927+ } deriving (Eq, Show, Generic, Typeable)
3929+data NodeDataPathStats = NodeDataPathStats {
3930+ nodeDataPathDiskServiceTime :: Maybe Double
3931+ , nodeDataPathDiskQueue :: Maybe Double
3932+ , nodeDataPathIOSize :: Maybe Bytes
3933+ , nodeDataPathWriteSize :: Maybe Bytes
3934+ , nodeDataPathReadSize :: Maybe Bytes
3935+ , nodeDataPathIOOps :: Maybe Int
3936+ , nodeDataPathWrites :: Maybe Int
3937+ , nodeDataPathReads :: Maybe Int
3938+ , nodeDataPathAvailable :: Bytes
3939+ , nodeDataPathFree :: Bytes
3940+ , nodeDataPathTotal :: Bytes
3941+ , nodeDataPathType :: Maybe Text
3942+ , nodeDataPathDevice :: Text
3943+ , nodeDataPathMount :: Text
3944+ , nodeDataPathPath :: Text
3945+ } deriving (Eq, Show, Generic, Typeable)
3947+data NodeFSTotalStats = NodeFSTotalStats {
3948+ nodeFSTotalDiskServiceTime :: Maybe Double
3949+ , nodeFSTotalDiskQueue :: Maybe Double
3950+ , nodeFSTotalIOSize :: Maybe Bytes
3951+ , nodeFSTotalWriteSize :: Maybe Bytes
3952+ , nodeFSTotalReadSize :: Maybe Bytes
3953+ , nodeFSTotalIOOps :: Maybe Int
3954+ , nodeFSTotalWrites :: Maybe Int
3955+ , nodeFSTotalReads :: Maybe Int
3956+ , nodeFSTotalAvailable :: Bytes
3957+ , nodeFSTotalFree :: Bytes
3958+ , nodeFSTotalTotal :: Bytes
3959+ } deriving (Eq, Show, Generic, Typeable)
3961+data NodeNetworkStats = NodeNetworkStats {
3962+ nodeNetTCPOutRSTs :: Int
3963+ , nodeNetTCPInErrs :: Int
3964+ , nodeNetTCPAttemptFails :: Int
3965+ , nodeNetTCPEstabResets :: Int
3966+ , nodeNetTCPRetransSegs :: Int
3967+ , nodeNetTCPOutSegs :: Int
3968+ , nodeNetTCPInSegs :: Int
3969+ , nodeNetTCPCurrEstab :: Int
3970+ , nodeNetTCPPassiveOpens :: Int
3971+ , nodeNetTCPActiveOpens :: Int
3972+ } deriving (Eq, Show, Generic, Typeable)
3974+data NodeThreadPoolsStats = NodeThreadPoolsStats {
3975+ nodeThreadPoolsStatsSnapshot :: NodeThreadPoolStats
3976+ , nodeThreadPoolsStatsBulk :: NodeThreadPoolStats
3977+ , nodeThreadPoolsStatsMerge :: NodeThreadPoolStats
3978+ , nodeThreadPoolsStatsGet :: NodeThreadPoolStats
3979+ , nodeThreadPoolsStatsManagement :: NodeThreadPoolStats
3980+ , nodeThreadPoolsStatsFetchShardStore :: Maybe NodeThreadPoolStats
3981+ , nodeThreadPoolsStatsOptimize :: NodeThreadPoolStats
3982+ , nodeThreadPoolsStatsFlush :: NodeThreadPoolStats
3983+ , nodeThreadPoolsStatsSearch :: NodeThreadPoolStats
3984+ , nodeThreadPoolsStatsWarmer :: NodeThreadPoolStats
3985+ , nodeThreadPoolsStatsGeneric :: NodeThreadPoolStats
3986+ , nodeThreadPoolsStatsSuggest :: NodeThreadPoolStats
3987+ , nodeThreadPoolsStatsRefresh :: NodeThreadPoolStats
3988+ , nodeThreadPoolsStatsIndex :: NodeThreadPoolStats
3989+ , nodeThreadPoolsStatsListener :: Maybe NodeThreadPoolStats
3990+ , nodeThreadPoolsStatsFetchShardStarted :: Maybe NodeThreadPoolStats
3991+ , nodeThreadPoolsStatsPercolate :: NodeThreadPoolStats
3992+ } deriving (Eq, Show, Generic, Typeable)
3994+data NodeThreadPoolStats = NodeThreadPoolStats {
3995+ nodeThreadPoolCompleted :: Int
3996+ , nodeThreadPoolLargest :: Int
3997+ , nodeThreadPoolRejected :: Int
3998+ , nodeThreadPoolActive :: Int
3999+ , nodeThreadPoolQueue :: Int
4000+ , nodeThreadPoolThreads :: Int
4001+ } deriving (Eq, Show, Generic, Typeable)
4003+data NodeJVMStats = NodeJVMStats {
4004+ nodeJVMStatsMappedBufferPool :: JVMBufferPoolStats
4005+ , nodeJVMStatsDirectBufferPool :: JVMBufferPoolStats
4006+ , nodeJVMStatsGCOldCollector :: JVMGCStats
4007+ , nodeJVMStatsGCYoungCollector :: JVMGCStats
4008+ , nodeJVMStatsPeakThreadsCount :: Int
4009+ , nodeJVMStatsThreadsCount :: Int
4010+ , nodeJVMStatsOldPool :: JVMPoolStats
4011+ , nodeJVMStatsSurvivorPool :: JVMPoolStats
4012+ , nodeJVMStatsYoungPool :: JVMPoolStats
4013+ , nodeJVMStatsNonHeapCommitted :: Bytes
4014+ , nodeJVMStatsNonHeapUsed :: Bytes
4015+ , nodeJVMStatsHeapMax :: Bytes
4016+ , nodeJVMStatsHeapCommitted :: Bytes
4017+ , nodeJVMStatsHeapUsedPercent :: Int
4018+ , nodeJVMStatsHeapUsed :: Bytes
4019+ , nodeJVMStatsUptime :: NominalDiffTime
4020+ , nodeJVMStatsTimestamp :: UTCTime
4021+ } deriving (Eq, Show, Generic, Typeable)
4023+data JVMBufferPoolStats = JVMBufferPoolStats {
4024+ jvmBufferPoolStatsTotalCapacity :: Bytes
4025+ , jvmBufferPoolStatsUsed :: Bytes
4026+ , jvmBufferPoolStatsCount :: Int
4027+ } deriving (Eq, Show, Generic, Typeable)
4029+data JVMGCStats = JVMGCStats {
4030+ jvmGCStatsCollectionTime :: NominalDiffTime
4031+ , jvmGCStatsCollectionCount :: Int
4032+ } deriving (Eq, Show, Generic, Typeable)
4034+data JVMPoolStats = JVMPoolStats {
4035+ jvmPoolStatsPeakMax :: Bytes
4036+ , jvmPoolStatsPeakUsed :: Bytes
4037+ , jvmPoolStatsMax :: Bytes
4038+ , jvmPoolStatsUsed :: Bytes
4039+ } deriving (Eq, Show, Generic, Typeable)
4041+data NodeProcessStats = NodeProcessStats {
4042+ nodeProcessMemTotalVirtual :: Bytes
4043+ , nodeProcessMemShare :: Bytes
4044+ , nodeProcessMemResident :: Bytes
4045+ , nodeProcessCPUTotal :: NominalDiffTime
4046+ , nodeProcessCPUUser :: NominalDiffTime
4047+ , nodeProcessCPUSys :: NominalDiffTime
4048+ , nodeProcessCPUPercent :: Int
4049+ , nodeProcessOpenFDs :: Int
4050+ , nodeProcessTimestamp :: UTCTime
4051+ } deriving (Eq, Show, Generic, Typeable)
4053+data NodeOSStats = NodeOSStats {
4054+ nodeOSSwapFree :: Bytes
4055+ , nodeOSSwapUsed :: Bytes
4056+ , nodeOSMemActualUsed :: Bytes
4057+ , nodeOSMemActualFree :: Bytes
4058+ , nodeOSMemUsedPercent :: Int
4059+ , nodeOSMemFreePercent :: Int
4060+ , nodeOSMemUsed :: Bytes
4061+ , nodeOSMemFree :: Bytes
4062+ , nodeOSCPUStolen :: Int
4063+ , nodeOSCPUUsage :: Int
4064+ , nodeOSCPUIdle :: Int
4065+ , nodeOSCPUUser :: Int
4066+ , nodeOSCPUSys :: Int
4067+ , nodeOSLoad :: LoadAvgs
4068+ , nodeOSUptime :: NominalDiffTime
4069+ , nodeOSTimestamp :: UTCTime
4070+ } deriving (Eq, Show, Generic, Typeable)
4072+data LoadAvgs = LoadAvgs {
4073+ loadAvg1Min :: Double
4074+ , loadAvg5Min :: Double
4075+ , loadAvg15Min :: Double
4076+ } deriving (Eq, Show, Generic, Typeable)
4078+data NodeIndicesStats = NodeIndicesStats {
4079+ nodeIndicesStatsRecoveryThrottleTime :: Maybe NominalDiffTime
4080+ , nodeIndicesStatsRecoveryCurrentAsTarget :: Maybe Int
4081+ , nodeIndicesStatsRecoveryCurrentAsSource :: Maybe Int
4082+ , nodeIndicesStatsQueryCacheMisses :: Maybe Int
4083+ , nodeIndicesStatsQueryCacheHits :: Maybe Int
4084+ , nodeIndicesStatsQueryCacheEvictions :: Maybe Int
4085+ , nodeIndicesStatsQueryCacheSize :: Maybe Bytes
4086+ , nodeIndicesStatsSuggestCurrent :: Int
4087+ , nodeIndicesStatsSuggestTime :: NominalDiffTime
4088+ , nodeIndicesStatsSuggestTotal :: Int
4089+ , nodeIndicesStatsTranslogSize :: Bytes
4090+ , nodeIndicesStatsTranslogOps :: Int
4091+ , nodeIndicesStatsSegFixedBitSetMemory :: Maybe Bytes
4092+ , nodeIndicesStatsSegVersionMapMemory :: Bytes
4093+ , nodeIndicesStatsSegIndexWriterMaxMemory :: Maybe Bytes
4094+ , nodeIndicesStatsSegIndexWriterMemory :: Bytes
4095+ , nodeIndicesStatsSegMemory :: Bytes
4096+ , nodeIndicesStatsSegCount :: Int
4097+ , nodeIndicesStatsCompletionSize :: Bytes
4098+ , nodeIndicesStatsPercolateQueries :: Int
4099+ , nodeIndicesStatsPercolateMemory :: Bytes
4100+ , nodeIndicesStatsPercolateCurrent :: Int
4101+ , nodeIndicesStatsPercolateTime :: NominalDiffTime
4102+ , nodeIndicesStatsPercolateTotal :: Int
4103+ , nodeIndicesStatsFieldDataEvictions :: Int
4104+ , nodeIndicesStatsFieldDataMemory :: Bytes
4105+ , nodeIndicesStatsIDCacheMemory :: Bytes
4106+ , nodeIndicesStatsFilterCacheEvictions :: Int
4107+ , nodeIndicesStatsFilterCacheMemory :: Bytes
4108+ , nodeIndicesStatsWarmerTotalTime :: NominalDiffTime
4109+ , nodeIndicesStatsWarmerTotal :: Int
4110+ , nodeIndicesStatsWarmerCurrent :: Int
4111+ , nodeIndicesStatsFlushTotalTime :: NominalDiffTime
4112+ , nodeIndicesStatsFlushTotal :: Int
4113+ , nodeIndicesStatsRefreshTotalTime :: NominalDiffTime
4114+ , nodeIndicesStatsRefreshTotal :: Int
4115+ , nodeIndicesStatsMergesTotalSize :: Bytes
4116+ , nodeIndicesStatsMergesTotalDocs :: Int
4117+ , nodeIndicesStatsMergesTotalTime :: NominalDiffTime
4118+ , nodeIndicesStatsMergesTotal :: Int
4119+ , nodeIndicesStatsMergesCurrentSize :: Bytes
4120+ , nodeIndicesStatsMergesCurrentDocs :: Int
4121+ , nodeIndicesStatsMergesCurrent :: Int
4122+ , nodeIndicesStatsSearchFetchCurrent :: Int
4123+ , nodeIndicesStatsSearchFetchTime :: NominalDiffTime
4124+ , nodeIndicesStatsSearchFetchTotal :: Int
4125+ , nodeIndicesStatsSearchQueryCurrent :: Int
4126+ , nodeIndicesStatsSearchQueryTime :: NominalDiffTime
4127+ , nodeIndicesStatsSearchQueryTotal :: Int
4128+ , nodeIndicesStatsSearchOpenContexts :: Int
4129+ , nodeIndicesStatsGetCurrent :: Int
4130+ , nodeIndicesStatsGetMissingTime :: NominalDiffTime
4131+ , nodeIndicesStatsGetMissingTotal :: Int
4132+ , nodeIndicesStatsGetExistsTime :: NominalDiffTime
4133+ , nodeIndicesStatsGetExistsTotal :: Int
4134+ , nodeIndicesStatsGetTime :: NominalDiffTime
4135+ , nodeIndicesStatsGetTotal :: Int
4136+ , nodeIndicesStatsIndexingThrottleTime :: Maybe NominalDiffTime
4137+ , nodeIndicesStatsIndexingIsThrottled :: Maybe Bool
4138+ , nodeIndicesStatsIndexingNoopUpdateTotal :: Maybe Int
4139+ , nodeIndicesStatsIndexingDeleteCurrent :: Int
4140+ , nodeIndicesStatsIndexingDeleteTime :: NominalDiffTime
4141+ , nodeIndicesStatsIndexingDeleteTotal :: Int
4142+ , nodeIndicesStatsIndexingIndexCurrent :: Int
4143+ , nodeIndicesStatsIndexingIndexTime :: NominalDiffTime
4144+ , nodeIndicesStatsIndexingTotal :: Int
4145+ , nodeIndicesStatsStoreThrottleTime :: NominalDiffTime
4146+ , nodeIndicesStatsStoreSize :: Bytes
4147+ , nodeIndicesStatsDocsDeleted :: Int
4148+ , nodeIndicesStatsDocsCount :: Int
4149+ } deriving (Eq, Show, Generic, Typeable)
4151+-- | A quirky address format used throughout ElasticSearch. An example
4152+-- would be inet[/1.1.1.1:9200]. inet may be a placeholder for a
4153+-- <https://en.wikipedia.org/wiki/Fully_qualified_domain_name FQDN>.
4154+newtype EsAddress = EsAddress { esAddress :: Text }
4155+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4157+-- | Typically a 7 character hex string.
4158+newtype BuildHash = BuildHash { buildHash :: Text }
4159+ deriving (Eq, Ord, Generic, Read, Show, Typeable, FromJSON, ToJSON)
4161+newtype PluginName = PluginName { pluginName :: Text }
4162+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4164+data NodeInfo = NodeInfo {
4165+ nodeInfoHTTPAddress :: EsAddress
4166+ , nodeInfoBuild :: BuildHash
4167+ , nodeInfoESVersion :: VersionNumber
4168+ , nodeInfoIP :: Server
4169+ , nodeInfoHost :: Server
4170+ , nodeInfoTransportAddress :: EsAddress
4171+ , nodeInfoName :: NodeName
4172+ , nodeInfoFullId :: FullNodeId
4173+ , nodeInfoPlugins :: [NodePluginInfo]
4174+ , nodeInfoHTTP :: NodeHTTPInfo
4175+ , nodeInfoTransport :: NodeTransportInfo
4176+ , nodeInfoNetwork :: NodeNetworkInfo
4177+ , nodeInfoThreadPool :: NodeThreadPoolsInfo
4178+ , nodeInfoJVM :: NodeJVMInfo
4179+ , nodeInfoProcess :: NodeProcessInfo
4180+ , nodeInfoOS :: NodeOSInfo
4181+ , nodeInfoSettings :: Object
4182+ -- ^ The members of the settings objects are not consistent,
4183+ -- dependent on plugins, etc.
4184+ } deriving (Eq, Show, Generic, Typeable)
4186+data NodePluginInfo = NodePluginInfo {
4187+ nodePluginSite :: Bool
4188+ -- ^ Is this a site plugin?
4189+ , nodePluginJVM :: Bool
4190+ -- ^ Is this plugin running on the JVM
4191+ , nodePluginDescription :: Text
4192+ , nodePluginVersion :: VersionNumber
4193+ , nodePluginName :: PluginName
4194+ } deriving (Eq, Show, Generic, Typeable)
4196+data NodeHTTPInfo = NodeHTTPInfo {
4197+ nodeHTTPMaxContentLength :: Bytes
4198+ , nodeHTTPTransportAddress :: BoundTransportAddress
4199+ } deriving (Eq, Show, Generic, Typeable)
4201+data NodeTransportInfo = NodeTransportInfo {
4202+ nodeTransportProfiles :: [BoundTransportAddress]
4203+ , nodeTransportAddress :: BoundTransportAddress
4204+ } deriving (Eq, Show, Generic, Typeable)
4206+data BoundTransportAddress = BoundTransportAddress {
4207+ publishAddress :: EsAddress
4208+ , boundAddress :: EsAddress
4209+ } deriving (Eq, Show, Generic, Typeable)
4211+data NodeNetworkInfo = NodeNetworkInfo {
4212+ nodeNetworkPrimaryInterface :: NodeNetworkInterface
4213+ , nodeNetworkRefreshInterval :: NominalDiffTime
4214+ } deriving (Eq, Show, Generic, Typeable)
4216+newtype MacAddress = MacAddress { macAddress :: Text }
4217+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4219+newtype NetworkInterfaceName = NetworkInterfaceName { networkInterfaceName :: Text }
4220+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4222+data NodeNetworkInterface = NodeNetworkInterface {
4223+ nodeNetIfaceMacAddress :: MacAddress
4224+ , nodeNetIfaceName :: NetworkInterfaceName
4225+ , nodeNetIfaceAddress :: Server
4226+ } deriving (Eq, Show, Generic, Typeable)
4228+data NodeThreadPoolsInfo = NodeThreadPoolsInfo {
4229+ nodeThreadPoolsRefresh :: NodeThreadPoolInfo
4230+ , nodeThreadPoolsManagement :: NodeThreadPoolInfo
4231+ , nodeThreadPoolsPercolate :: NodeThreadPoolInfo
4232+ , nodeThreadPoolsListener :: Maybe NodeThreadPoolInfo
4233+ , nodeThreadPoolsFetchShardStarted :: Maybe NodeThreadPoolInfo
4234+ , nodeThreadPoolsSearch :: NodeThreadPoolInfo
4235+ , nodeThreadPoolsFlush :: NodeThreadPoolInfo
4236+ , nodeThreadPoolsWarmer :: NodeThreadPoolInfo
4237+ , nodeThreadPoolsOptimize :: NodeThreadPoolInfo
4238+ , nodeThreadPoolsBulk :: NodeThreadPoolInfo
4239+ , nodeThreadPoolsSuggest :: NodeThreadPoolInfo
4240+ , nodeThreadPoolsMerge :: NodeThreadPoolInfo
4241+ , nodeThreadPoolsSnapshot :: NodeThreadPoolInfo
4242+ , nodeThreadPoolsGet :: NodeThreadPoolInfo
4243+ , nodeThreadPoolsFetchShardStore :: Maybe NodeThreadPoolInfo
4244+ , nodeThreadPoolsIndex :: NodeThreadPoolInfo
4245+ , nodeThreadPoolsGeneric :: NodeThreadPoolInfo
4246+ } deriving (Eq, Show, Generic, Typeable)
4248+data NodeThreadPoolInfo = NodeThreadPoolInfo {
4249+ nodeThreadPoolQueueSize :: ThreadPoolSize
4250+ , nodeThreadPoolKeepalive :: Maybe NominalDiffTime
4251+ , nodeThreadPoolMin :: Maybe Int
4252+ , nodeThreadPoolMax :: Maybe Int
4253+ , nodeThreadPoolType :: ThreadPoolType
4254+ } deriving (Eq, Show, Generic, Typeable)
4256+data ThreadPoolSize = ThreadPoolBounded Int
4257+ | ThreadPoolUnbounded
4258+ deriving (Eq, Show, Generic, Typeable)
4260+data ThreadPoolType = ThreadPoolScaling
4263+ deriving (Eq, Show, Generic, Typeable)
4265+data NodeJVMInfo = NodeJVMInfo {
4266+ nodeJVMInfoMemoryPools :: [JVMMemoryPool]
4267+ , nodeJVMInfoMemoryPoolsGCCollectors :: [JVMGCCollector]
4268+ , nodeJVMInfoMemoryInfo :: JVMMemoryInfo
4269+ , nodeJVMInfoStartTime :: UTCTime
4270+ , nodeJVMInfoVMVendor :: Text
4271+ , nodeJVMVMVersion :: VersionNumber
4272+ -- ^ JVM doesn't seme to follow normal version conventions
4273+ , nodeJVMVMName :: Text
4274+ , nodeJVMVersion :: VersionNumber
4275+ , nodeJVMPID :: PID
4276+ } deriving (Eq, Show, Generic, Typeable)
4278+-- | Handles quirks in the way JVM versions are rendered (1.7.0_101 -> 1.7.0.101)
4279+newtype JVMVersion = JVMVersion { unJVMVersion :: VersionNumber }
4281+data JVMMemoryInfo = JVMMemoryInfo {
4282+ jvmMemoryInfoDirectMax :: Bytes
4283+ , jvmMemoryInfoNonHeapMax :: Bytes
4284+ , jvmMemoryInfoNonHeapInit :: Bytes
4285+ , jvmMemoryInfoHeapMax :: Bytes
4286+ , jvmMemoryInfoHeapInit :: Bytes
4287+ } deriving (Eq, Show, Generic, Typeable)
4289+newtype JVMMemoryPool = JVMMemoryPool {
4290+ jvmMemoryPool :: Text
4291+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
4293+newtype JVMGCCollector = JVMGCCollector {
4294+ jvmGCCollector :: Text
4295+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
4299+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
4301+data NodeOSInfo = NodeOSInfo {
4302+ nodeOSSwap :: Bytes
4303+ , nodeOSMem :: Bytes
4304+ , nodeOSCPUInfo :: CPUInfo
4305+ , nodeOSAvailableProcessors :: Int
4306+ , nodeOSRefreshInterval :: NominalDiffTime
4307+ } deriving (Eq, Show, Generic, Typeable)
4309+data CPUInfo = CPUInfo {
4310+ cpuCacheSize :: Bytes
4311+ , cpuCoresPerSocket :: Int
4312+ , cpuTotalSockets :: Int
4313+ , cpuTotalCores :: Int
4316+ , cpuVendor :: Text
4317+ } deriving (Eq, Show, Generic, Typeable)
4319+data NodeProcessInfo = NodeProcessInfo {
4320+ nodeProcessMLockAll :: Bool
4321+ -- ^ See <https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html>
4322+ , nodeProcessMaxFileDescriptors :: Int
4323+ , nodeProcessId :: PID
4324+ , nodeProcessRefreshInterval :: NominalDiffTime
4325+ } deriving (Eq, Show, Generic, Typeable)
4327+data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
4328+ repoUpdateVerify :: Bool
4329+ -- ^ After creation/update, synchronously check that nodes can
4330+ -- write to this repo. Defaults to True. You may use False if you
4331+ -- need a faster response and plan on verifying manually later
4332+ -- with 'verifySnapshotRepo'.
4333+ } deriving (Eq, Show, Generic, Typeable)
4336+-- | Reasonable defaults for repo creation/update
4338+-- * repoUpdateVerify True
4339+defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
4340+defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
4343+-- | A filesystem-based snapshot repo that ships with
4344+-- ElasticSearch. This is an instance of 'SnapshotRepo' so it can be
4345+-- used with 'updateSnapshotRepo'
4346+data FsSnapshotRepo = FsSnapshotRepo {
4347+ fsrName :: SnapshotRepoName
4348+ , fsrLocation :: FilePath
4349+ , fsrCompressMetadata :: Bool
4350+ , fsrChunkSize :: Maybe Bytes
4351+ -- ^ Size by which to split large files during snapshotting.
4352+ , fsrMaxRestoreBytesPerSec :: Maybe Bytes
4353+ -- ^ Throttle node restore rate. If not supplied, defaults to 40mb/sec
4354+ , fsrMaxSnapshotBytesPerSec :: Maybe Bytes
4355+ -- ^ Throttle node snapshot rate. If not supplied, defaults to 40mb/sec
4356+ } deriving (Eq, Generic, Show, Typeable)
4359+instance SnapshotRepo FsSnapshotRepo where
4360+ toGSnapshotRepo FsSnapshotRepo {..} =
4361+ GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
4363+ Object settings = object $ [ "location" .= fsrLocation
4364+ , "compress" .= fsrCompressMetadata
4366+ optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
4367+ , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
4368+ , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
4370+ fromGSnapshotRepo GenericSnapshotRepo {..}
4371+ | gSnapshotRepoType == fsRepoType = do
4372+ let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
4374+ FsSnapshotRepo gSnapshotRepoName <$> o .: "location"
4375+ <*> o .:? "compress" .!= False
4376+ <*> o .:? "chunk_size"
4377+ <*> o .:? "max_restore_bytes_per_sec"
4378+ <*> o .:? "max_snapshot_bytes_per_sec"
4379+ | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
4382+parseRepo :: Parser a -> Either SnapshotRepoConversionError a
4383+parseRepo parser = case parseEither (const parser) () of
4384+ Left e -> Left (OtherRepoConversionError (T.pack e))
4388+fsRepoType :: SnapshotRepoType
4389+fsRepoType = SnapshotRepoType "fs"
4391+-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
4392+class SnapshotRepo r where
4393+ toGSnapshotRepo :: r -> GenericSnapshotRepo
4394+ fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
4397+data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType SnapshotRepoType
4398+ -- ^ Expected type and actual type
4399+ | OtherRepoConversionError Text
4400+ deriving (Show, Eq, Generic, Typeable)
4403+instance Exception SnapshotRepoConversionError
4406+data SnapshotCreateSettings = SnapshotCreateSettings {
4407+ snapWaitForCompletion :: Bool
4408+ -- ^ Should the API call return immediately after initializing
4409+ -- the snapshot or wait until completed? Note that if this is
4410+ -- enabled it could wait a long time, so you should adjust your
4411+ -- 'ManagerSettings' accordingly to set long timeouts or
4412+ -- explicitly handle timeouts.
4413+ , snapIndices :: Maybe IndexSelection
4414+ -- ^ Nothing will snapshot all indices. Just [] is permissable and
4415+ -- will essentially be a no-op snapshot.
4416+ , snapIgnoreUnavailable :: Bool
4417+ -- ^ If set to True, any matched indices that don't exist will be
4418+ -- ignored. Otherwise it will be an error and fail.
4419+ , snapIncludeGlobalState :: Bool
4420+ , snapPartial :: Bool
4421+ -- ^ If some indices failed to snapshot (e.g. if not all primary
4422+ -- shards are available), should the process proceed?
4423+ } deriving (Eq, Generic, Show, Typeable)
4426+-- | Reasonable defaults for snapshot creation
4428+-- * snapWaitForCompletion False
4429+-- * snapIndices Nothing
4430+-- * snapIgnoreUnavailable False
4431+-- * snapIncludeGlobalState True
4432+-- * snapPartial False
4433+defaultSnapshotCreateSettings :: SnapshotCreateSettings
4434+defaultSnapshotCreateSettings = SnapshotCreateSettings {
4435+ snapWaitForCompletion = False
4436+ , snapIndices = Nothing
4437+ , snapIgnoreUnavailable = False
4438+ , snapIncludeGlobalState = True
4439+ , snapPartial = False
4443+data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
4444+ | AllSnapshots deriving (Eq, Generic, Show, Typeable)
4447+-- | Either specifies an exact snapshot name or one with globs in it,
4448+-- e.g. @SnapPattern "foo*"@ __NOTE__: Patterns are not supported on
4450+data SnapshotPattern = ExactSnap SnapshotName
4452+ deriving (Eq, Generic, Show, Typeable)
4455+-- | General information about the state of a snapshot. Has some
4456+-- redundancies with 'SnapshotStatus'
4457+data SnapshotInfo = SnapshotInfo {
4458+ snapInfoShards :: ShardResult
4459+ , snapInfoFailures :: [SnapshotShardFailure]
4460+ , snapInfoDuration :: NominalDiffTime
4461+ , snapInfoEndTime :: UTCTime
4462+ , snapInfoStartTime :: UTCTime
4463+ , snapInfoState :: SnapshotState
4464+ , snapInfoIndices :: [IndexName]
4465+ , snapInfoName :: SnapshotName
4466+ } deriving (Eq, Generic, Show, Typeable)
4469+instance FromJSON SnapshotInfo where
4470+ parseJSON = withObject "SnapshotInfo" parse
4472+ parse o = SnapshotInfo <$> o .: "shards"
4473+ <*> o .: "failures"
4474+ <*> (unMS <$> o .: "duration_in_millis")
4475+ <*> (posixMS <$> o .: "end_time_in_millis")
4476+ <*> (posixMS <$> o .: "start_time_in_millis")
4479+ <*> o .: "snapshot"
4481+data SnapshotShardFailure = SnapshotShardFailure {
4482+ snapShardFailureIndex :: IndexName
4483+ , snapShardFailureNodeId :: Maybe NodeName -- I'm not 100% sure this isn't actually 'FullNodeId'
4484+ , snapShardFailureReason :: Text
4485+ , snapShardFailureShardId :: ShardId
4486+ } deriving (Eq, Show, Generic, Typeable)
4489+instance FromJSON SnapshotShardFailure where
4490+ parseJSON = withObject "SnapshotShardFailure" parse
4492+ parse o = SnapshotShardFailure <$> o .: "index"
4493+ <*> o .:? "node_id"
4495+ <*> o .: "shard_id"
4498+newtype ShardId = ShardId { shardId :: Int }
4499+ deriving (Eq, Show, Generic, Typeable, FromJSON)
4502+newtype MS = MS NominalDiffTime
4505+-- keeps the unexported constructor warnings at bay
4506+unMS :: MS -> NominalDiffTime
4510+instance FromJSON MS where
4511+ parseJSON = withScientific "MS" (return . MS . parse)
4513+ parse n = fromInteger ((truncate n) * 1000)
4516+data SnapshotState = SnapshotInit
4523+ deriving (Show, Eq, Generic, Typeable)
4525+instance FromJSON SnapshotState where
4526+ parseJSON = withText "SnapshotState" parse
4528+ parse "INIT" = return SnapshotInit
4529+ parse "STARTED" = return SnapshotStarted
4530+ parse "SUCCESS" = return SnapshotSuccess
4531+ parse "FAILED" = return SnapshotFailed
4532+ parse "ABORTED" = return SnapshotAborted
4533+ parse "MISSING" = return SnapshotMissing
4534+ parse "WAITING" = return SnapshotWaiting
4535+ parse t = fail ("Invalid snapshot state " <> T.unpack t)
4538+newtype SnapshotName = SnapshotName { snapshotName :: Text }
4539+ deriving (Show, Eq, Ord, Generic, Typeable, ToJSON, FromJSON)
4542+data SnapshotRestoreSettings = SnapshotRestoreSettings {
4543+ snapRestoreWaitForCompletion :: Bool
4544+ -- ^ Should the API call return immediately after initializing
4545+ -- the restore or wait until completed? Note that if this is
4546+ -- enabled, it could wait a long time, so you should adjust your
4547+ -- 'ManagerSettings' accordingly to set long timeouts or
4548+ -- explicitly handle timeouts.
4549+ , snapRestoreIndices :: Maybe IndexSelection
4550+ -- ^ Nothing will restore all indices in the snapshot. Just [] is
4551+ -- permissable and will essentially be a no-op restore.
4552+ , snapRestoreIgnoreUnavailable :: Bool
4553+ -- ^ If set to True, any indices that do not exist will be ignored
4554+ -- during snapshot rather than failing the restore.
4555+ , snapRestoreIncludeGlobalState :: Bool
4556+ -- ^ If set to false, will ignore any global state in the snapshot
4557+ -- and will not restore it.
4558+ , snapRestoreRenamePattern :: Maybe RestoreRenamePattern
4559+ -- ^ A regex pattern for matching indices. Used with
4560+ -- 'snapRestoreRenameReplacement', the restore can reference the
4561+ -- matched index and create a new index name upon restore.
4562+ , snapRestoreRenameReplacement :: Maybe (NonEmpty RestoreRenameToken)
4563+ -- ^ Expression of how index renames should be constructed.
4564+ , snapRestorePartial :: Bool
4565+ -- ^ If some indices fail to restore, should the process proceed?
4566+ , snapRestoreIncludeAliases :: Bool
4567+ -- ^ Should the restore also restore the aliases captured in the
4569+ , snapRestoreIndexSettingsOverrides :: Maybe RestoreIndexSettings
4570+ -- ^ Settings to apply during the restore process. __NOTE:__ This
4571+ -- option is not supported in ES < 1.5 and should be set to
4572+ -- Nothing in that case.
4573+ , snapRestoreIgnoreIndexSettings :: Maybe (NonEmpty Text)
4574+ -- ^ This type could be more rich but it isn't clear which
4575+ -- settings are allowed to be ignored during restore, so we're
4576+ -- going with including this feature in a basic form rather than
4577+ -- omitting it. One example here would be
4578+ -- "index.refresh_interval". Any setting specified here will
4579+ -- revert back to the server default during the restore process.
4580+ } deriving (Eq, Generic, Show, Typeable)
4582+-- | Regex-stype pattern, e.g. "index_(.+)" to match index names
4583+newtype RestoreRenamePattern = RestoreRenamePattern { rrPattern :: Text }
4584+ deriving (Show, Eq, Generic, Typeable, Ord, ToJSON)
4587+-- | A single token in a index renaming scheme for a restore. These
4588+-- are concatenated into a string before being sent to
4589+-- ElasticSearch. Check out these Java
4590+-- <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.
4591+data RestoreRenameToken = RRTLit Text
4592+ -- ^ Just a literal string of characters
4594+ -- ^ Equivalent to $0. The entire matched pattern, not any subgroup
4595+ | RRSubGroup RRGroupRefNum
4596+ -- ^ A specific reference to a group number
4597+ deriving (Show, Eq, Generic, Typeable)
4600+-- | A group number for regex matching. Only values from 1-9 are
4601+-- supported. Construct with 'mkRRGroupRefNum'
4602+newtype RRGroupRefNum = RRGroupRefNum { rrGroupRefNum :: Int }
4603+ deriving (Show, Eq, Generic, Typeable, Ord)
4605+instance Bounded RRGroupRefNum where
4606+ minBound = RRGroupRefNum 1
4607+ maxBound = RRGroupRefNum 9
4610+-- | Only allows valid group number references (1-9).
4611+mkRRGroupRefNum :: Int -> Maybe RRGroupRefNum
4613+ | i >= (rrGroupRefNum minBound) && i <= (rrGroupRefNum maxBound) =
4614+ Just $ RRGroupRefNum i
4615+ | otherwise = Nothing
4618+-- | Reasonable defaults for snapshot restores
4620+-- * snapRestoreWaitForCompletion False
4621+-- * snapRestoreIndices Nothing
4622+-- * snapRestoreIgnoreUnavailable False
4623+-- * snapRestoreIncludeGlobalState True
4624+-- * snapRestoreRenamePattern Nothing
4625+-- * snapRestoreRenameReplacement Nothing
4626+-- * snapRestorePartial False
4627+-- * snapRestoreIncludeAliases True
4628+-- * snapRestoreIndexSettingsOverrides Nothing
4629+-- * snapRestoreIgnoreIndexSettings Nothing
4630+defaultSnapshotRestoreSettings :: SnapshotRestoreSettings
4631+defaultSnapshotRestoreSettings = SnapshotRestoreSettings {
4632+ snapRestoreWaitForCompletion = False
4633+ , snapRestoreIndices = Nothing
4634+ , snapRestoreIgnoreUnavailable = False
4635+ , snapRestoreIncludeGlobalState = True
4636+ , snapRestoreRenamePattern = Nothing
4637+ , snapRestoreRenameReplacement = Nothing
4638+ , snapRestorePartial = False
4639+ , snapRestoreIncludeAliases = True
4640+ , snapRestoreIndexSettingsOverrides = Nothing
4641+ , snapRestoreIgnoreIndexSettings = Nothing
4645+-- | Index settings that can be overridden. The docs only mention you
4646+-- can update number of replicas, but there may be more. You
4647+-- definitely cannot override shard count.
4648+data RestoreIndexSettings = RestoreIndexSettings {
4649+ restoreOverrideReplicas :: Maybe ReplicaCount
4650+ } deriving (Show, Eq, Generic, Typeable)
4653+instance ToJSON RestoreIndexSettings where
4654+ toJSON RestoreIndexSettings {..} = object prs
4656+ prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]
4659+instance FromJSON NodesInfo where
4660+ parseJSON = withObject "NodesInfo" parse
4663+ nodes <- o .: "nodes"
4664+ infos <- forM (HM.toList nodes) $ \(fullNID, v) -> do
4665+ node <- parseJSON v
4666+ parseNodeInfo (FullNodeId fullNID) node
4667+ cn <- o .: "cluster_name"
4668+ return (NodesInfo infos cn)
4670+instance FromJSON NodesStats where
4671+ parseJSON = withObject "NodesStats" parse
4674+ nodes <- o .: "nodes"
4675+ stats <- forM (HM.toList nodes) $ \(fullNID, v) -> do
4676+ node <- parseJSON v
4677+ parseNodeStats (FullNodeId fullNID) node
4678+ cn <- o .: "cluster_name"
4679+ return (NodesStats stats cn)
4681+instance FromJSON NodeBreakerStats where
4682+ parseJSON = withObject "NodeBreakerStats" parse
4684+ parse o = NodeBreakerStats <$> o .: "tripped"
4685+ <*> o .: "overhead"
4686+ <*> o .: "estimated_size_in_bytes"
4687+ <*> o .: "limit_size_in_bytes"
4689+instance FromJSON NodeHTTPStats where
4690+ parseJSON = withObject "NodeHTTPStats" parse
4692+ parse o = NodeHTTPStats <$> o .: "total_opened"
4693+ <*> o .: "current_open"
4695+instance FromJSON NodeTransportStats where
4696+ parseJSON = withObject "NodeTransportStats" parse
4698+ parse o = NodeTransportStats <$> o .: "tx_size_in_bytes"
4699+ <*> o .: "tx_count"
4700+ <*> o .: "rx_size_in_bytes"
4701+ <*> o .: "rx_count"
4702+ <*> o .: "server_open"
4704+instance FromJSON NodeFSStats where
4705+ parseJSON = withObject "NodeFSStats" parse
4707+ parse o = NodeFSStats <$> o .: "data"
4709+ <*> (posixMS <$> o .: "timestamp")
4711+instance FromJSON NodeDataPathStats where
4712+ parseJSON = withObject "NodeDataPathStats" parse
4715+ NodeDataPathStats <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
4716+ <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
4717+ <*> o .:? "disk_io_size_in_bytes"
4718+ <*> o .:? "disk_write_size_in_bytes"
4719+ <*> o .:? "disk_read_size_in_bytes"
4720+ <*> o .:? "disk_io_op"
4721+ <*> o .:? "disk_writes"
4722+ <*> o .:? "disk_reads"
4723+ <*> o .: "available_in_bytes"
4724+ <*> o .: "free_in_bytes"
4725+ <*> o .: "total_in_bytes"
4731+newtype StringlyTypedDouble = StringlyTypedDouble { unStringlyTypedDouble :: Double }
4734+instance FromJSON StringlyTypedDouble where
4735+ parseJSON = fmap StringlyTypedDouble . parseJSON . unStringlyTypeJSON
4738+instance FromJSON NodeFSTotalStats where
4739+ parseJSON = withObject "NodeFSTotalStats" parse
4741+ parse o = NodeFSTotalStats <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
4742+ <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
4743+ <*> o .:? "disk_io_size_in_bytes"
4744+ <*> o .:? "disk_write_size_in_bytes"
4745+ <*> o .:? "disk_read_size_in_bytes"
4746+ <*> o .:? "disk_io_op"
4747+ <*> o .:? "disk_writes"
4748+ <*> o .:? "disk_reads"
4749+ <*> o .: "available_in_bytes"
4750+ <*> o .: "free_in_bytes"
4751+ <*> o .: "total_in_bytes"
4753+instance FromJSON NodeNetworkStats where
4754+ parseJSON = withObject "NodeNetworkStats" parse
4758+ NodeNetworkStats <$> tcp .: "out_rsts"
4759+ <*> tcp .: "in_errs"
4760+ <*> tcp .: "attempt_fails"
4761+ <*> tcp .: "estab_resets"
4762+ <*> tcp .: "retrans_segs"
4763+ <*> tcp .: "out_segs"
4764+ <*> tcp .: "in_segs"
4765+ <*> tcp .: "curr_estab"
4766+ <*> tcp .: "passive_opens"
4767+ <*> tcp .: "active_opens"
4769+instance FromJSON NodeThreadPoolsStats where
4770+ parseJSON = withObject "NodeThreadPoolsStats" parse
4772+ parse o = NodeThreadPoolsStats <$> o .: "snapshot"
4776+ <*> o .: "management"
4777+ <*> o .:? "fetch_shard_store"
4778+ <*> o .: "optimize"
4786+ <*> o .:? "listener"
4787+ <*> o .:? "fetch_shard_started"
4788+ <*> o .: "percolate"
4789+instance FromJSON NodeThreadPoolStats where
4790+ parseJSON = withObject "NodeThreadPoolStats" parse
4792+ parse o = NodeThreadPoolStats <$> o .: "completed"
4794+ <*> o .: "rejected"
4799+instance FromJSON NodeJVMStats where
4800+ parseJSON = withObject "NodeJVMStats" parse
4803+ bufferPools <- o .: "buffer_pools"
4804+ mapped <- bufferPools .: "mapped"
4805+ direct <- bufferPools .: "direct"
4807+ collectors <- gc .: "collectors"
4808+ oldC <- collectors .: "old"
4809+ youngC <- collectors .: "young"
4810+ threads <- o .: "threads"
4812+ pools <- mem .: "pools"
4813+ oldM <- pools .: "old"
4814+ survivorM <- pools .: "survivor"
4815+ youngM <- pools .: "young"
4816+ NodeJVMStats <$> pure mapped
4820+ <*> threads .: "peak_count"
4821+ <*> threads .: "count"
4825+ <*> mem .: "non_heap_committed_in_bytes"
4826+ <*> mem .: "non_heap_used_in_bytes"
4827+ <*> mem .: "heap_max_in_bytes"
4828+ <*> mem .: "heap_committed_in_bytes"
4829+ <*> mem .: "heap_used_percent"
4830+ <*> mem .: "heap_used_in_bytes"
4831+ <*> (unMS <$> o .: "uptime_in_millis")
4832+ <*> (posixMS <$> o .: "timestamp")
4834+instance FromJSON JVMBufferPoolStats where
4835+ parseJSON = withObject "JVMBufferPoolStats" parse
4837+ parse o = JVMBufferPoolStats <$> o .: "total_capacity_in_bytes"
4838+ <*> o .: "used_in_bytes"
4841+instance FromJSON JVMGCStats where
4842+ parseJSON = withObject "JVMGCStats" parse
4844+ parse o = JVMGCStats <$> (unMS <$> o .: "collection_time_in_millis")
4845+ <*> o .: "collection_count"
4847+instance FromJSON JVMPoolStats where
4848+ parseJSON = withObject "JVMPoolStats" parse
4850+ parse o = JVMPoolStats <$> o .: "peak_max_in_bytes"
4851+ <*> o .: "peak_used_in_bytes"
4852+ <*> o .: "max_in_bytes"
4853+ <*> o .: "used_in_bytes"
4855+instance FromJSON NodeProcessStats where
4856+ parseJSON = withObject "NodeProcessStats" parse
4861+ NodeProcessStats <$> mem .: "total_virtual_in_bytes"
4862+ <*> mem .: "share_in_bytes"
4863+ <*> mem .: "resident_in_bytes"
4864+ <*> (unMS <$> cpu .: "total_in_millis")
4865+ <*> (unMS <$> cpu .: "user_in_millis")
4866+ <*> (unMS <$> cpu .: "sys_in_millis")
4867+ <*> cpu .: "percent"
4868+ <*> o .: "open_file_descriptors"
4869+ <*> (posixMS <$> o .: "timestamp")
4871+instance FromJSON NodeOSStats where
4872+ parseJSON = withObject "NodeOSStats" parse
4875+ swap <- o .: "swap"
4878+ load <- o .: "load_average"
4879+ NodeOSStats <$> swap .: "free_in_bytes"
4880+ <*> swap .: "used_in_bytes"
4881+ <*> mem .: "actual_used_in_bytes"
4882+ <*> mem .: "actual_free_in_bytes"
4883+ <*> mem .: "used_percent"
4884+ <*> mem .: "free_percent"
4885+ <*> mem .: "used_in_bytes"
4886+ <*> mem .: "free_in_bytes"
4887+ <*> cpu .: "stolen"
4893+ <*> (unMS <$> o .: "uptime_in_millis")
4894+ <*> (posixMS <$> o .: "timestamp")
4896+instance FromJSON LoadAvgs where
4897+ parseJSON = withArray "LoadAvgs" parse
4899+ parse v = case V.toList v of
4900+ [one, five, fifteen] -> LoadAvgs <$> parseJSON one
4902+ <*> parseJSON fifteen
4903+ _ -> fail "Expecting a triple of Doubles"
4905+instance FromJSON NodeIndicesStats where
4906+ parseJSON = withObject "NodeIndicesStats" parse
4909+ let (.::) mv k = case mv of
4910+ Just v -> Just <$> v .: k
4911+ Nothing -> pure Nothing
4912+ mRecovery <- o .:? "recovery"
4913+ mQueryCache <- o .:? "query_cache"
4914+ suggest <- o .: "suggest"
4915+ translog <- o .: "translog"
4916+ segments <- o .: "segments"
4917+ completion <- o .: "completion"
4918+ percolate <- o .: "percolate"
4919+ fielddata <- o .: "fielddata"
4920+ idCache <- o .: "id_cache"
4921+ filterCache <- o .: "filter_cache"
4922+ warmer <- o .: "warmer"
4923+ flush <- o .: "flush"
4924+ refresh <- o .: "refresh"
4925+ merges <- o .: "merges"
4926+ search <- o .: "search"
4927+ getStats <- o .: "get"
4928+ indexing <- o .: "indexing"
4929+ store <- o .: "store"
4930+ docs <- o .: "docs"
4931+ NodeIndicesStats <$> (fmap unMS <$> mRecovery .:: "throttle_time_in_millis")
4932+ <*> mRecovery .:: "current_as_target"
4933+ <*> mRecovery .:: "current_as_source"
4934+ <*> mQueryCache .:: "miss_count"
4935+ <*> mQueryCache .:: "hit_count"
4936+ <*> mQueryCache .:: "evictions"
4937+ <*> mQueryCache .:: "memory_size_in_bytes"
4938+ <*> suggest .: "current"
4939+ <*> (unMS <$> suggest .: "time_in_millis")
4940+ <*> suggest .: "total"
4941+ <*> translog .: "size_in_bytes"
4942+ <*> translog .: "operations"
4943+ <*> segments .:? "fixed_bit_set_memory_in_bytes"
4944+ <*> segments .: "version_map_memory_in_bytes"
4945+ <*> segments .:? "index_writer_max_memory_in_bytes"
4946+ <*> segments .: "index_writer_memory_in_bytes"
4947+ <*> segments .: "memory_in_bytes"
4948+ <*> segments .: "count"
4949+ <*> completion .: "size_in_bytes"
4950+ <*> percolate .: "queries"
4951+ <*> percolate .: "memory_size_in_bytes"
4952+ <*> percolate .: "current"
4953+ <*> (unMS <$> percolate .: "time_in_millis")
4954+ <*> percolate .: "total"
4955+ <*> fielddata .: "evictions"
4956+ <*> fielddata .: "memory_size_in_bytes"
4957+ <*> idCache .: "memory_size_in_bytes"
4958+ <*> filterCache .: "evictions"
4959+ <*> filterCache .: "memory_size_in_bytes"
4960+ <*> (unMS <$> warmer .: "total_time_in_millis")
4961+ <*> warmer .: "total"
4962+ <*> warmer .: "current"
4963+ <*> (unMS <$> flush .: "total_time_in_millis")
4964+ <*> flush .: "total"
4965+ <*> (unMS <$> refresh .: "total_time_in_millis")
4966+ <*> refresh .: "total"
4967+ <*> merges .: "total_size_in_bytes"
4968+ <*> merges .: "total_docs"
4969+ <*> (unMS <$> merges .: "total_time_in_millis")
4970+ <*> merges .: "total"
4971+ <*> merges .: "current_size_in_bytes"
4972+ <*> merges .: "current_docs"
4973+ <*> merges .: "current"
4974+ <*> search .: "fetch_current"
4975+ <*> (unMS <$> search .: "fetch_time_in_millis")
4976+ <*> search .: "fetch_total"
4977+ <*> search .: "query_current"
4978+ <*> (unMS <$> search .: "query_time_in_millis")
4979+ <*> search .: "query_total"
4980+ <*> search .: "open_contexts"
4981+ <*> getStats .: "current"
4982+ <*> (unMS <$> getStats .: "missing_time_in_millis")
4983+ <*> getStats .: "missing_total"
4984+ <*> (unMS <$> getStats .: "exists_time_in_millis")
4985+ <*> getStats .: "exists_total"
4986+ <*> (unMS <$> getStats .: "time_in_millis")
4987+ <*> getStats .: "total"
4988+ <*> (fmap unMS <$> indexing .:? "throttle_time_in_millis")
4989+ <*> indexing .:? "is_throttled"
4990+ <*> indexing .:? "noop_update_total"
4991+ <*> indexing .: "delete_current"
4992+ <*> (unMS <$> indexing .: "delete_time_in_millis")
4993+ <*> indexing .: "delete_total"
4994+ <*> indexing .: "index_current"
4995+ <*> (unMS <$> indexing .: "index_time_in_millis")
4996+ <*> indexing .: "index_total"
4997+ <*> (unMS <$> store .: "throttle_time_in_millis")
4998+ <*> store .: "size_in_bytes"
4999+ <*> docs .: "deleted"
5000+ <*> docs .: "count"
5002+instance FromJSON NodeBreakersStats where
5003+ parseJSON = withObject "NodeBreakersStats" parse
5005+ parse o = NodeBreakersStats <$> o .: "parent"
5007+ <*> o .: "fielddata"
5009+parseNodeStats :: FullNodeId -> Object -> Parser NodeStats
5010+parseNodeStats fnid o = do
5011+ NodeStats <$> o .: "name"
5013+ <*> o .:? "breakers"
5015+ <*> o .: "transport"
5018+ <*> o .: "thread_pool"
5024+parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
5025+parseNodeInfo nid o =
5026+ NodeInfo <$> o .: "http_address"
5031+ <*> o .: "transport_address"
5036+ <*> o .: "transport"
5038+ <*> o .: "thread_pool"
5042+ <*> o .: "settings"
5044+instance FromJSON NodePluginInfo where
5045+ parseJSON = withObject "NodePluginInfo" parse
5047+ parse o = NodePluginInfo <$> o .: "site"
5049+ <*> o .: "description"
5053+instance FromJSON NodeHTTPInfo where
5054+ parseJSON = withObject "NodeHTTPInfo" parse
5056+ parse o = NodeHTTPInfo <$> o .: "max_content_length_in_bytes"
5057+ <*> parseJSON (Object o)
5059+instance FromJSON BoundTransportAddress where
5060+ parseJSON = withObject "BoundTransportAddress" parse
5062+ parse o = BoundTransportAddress <$> o .: "publish_address"
5063+ <*> o .: "bound_address"
5065+instance FromJSON NodeOSInfo where
5066+ parseJSON = withObject "NodeOSInfo" parse
5069+ swap <- o .: "swap"
5071+ NodeOSInfo <$> swap .: "total_in_bytes"
5072+ <*> mem .: "total_in_bytes"
5074+ <*> o .: "available_processors"
5075+ <*> (unMS <$> o .: "refresh_interval_in_millis")
5078+instance FromJSON CPUInfo where
5079+ parseJSON = withObject "CPUInfo" parse
5081+ parse o = CPUInfo <$> o .: "cache_size_in_bytes"
5082+ <*> o .: "cores_per_socket"
5083+ <*> o .: "total_sockets"
5084+ <*> o .: "total_cores"
5089+instance FromJSON NodeProcessInfo where
5090+ parseJSON = withObject "NodeProcessInfo" parse
5092+ parse o = NodeProcessInfo <$> o .: "mlockall"
5093+ <*> o .: "max_file_descriptors"
5095+ <*> (unMS <$> o .: "refresh_interval_in_millis")
5097+instance FromJSON NodeJVMInfo where
5098+ parseJSON = withObject "NodeJVMInfo" parse
5100+ parse o = NodeJVMInfo <$> o .: "memory_pools"
5101+ <*> o .: "gc_collectors"
5103+ <*> (posixMS <$> o .: "start_time_in_millis")
5104+ <*> o .: "vm_vendor"
5105+ <*> o .: "vm_version"
5107+ <*> (unJVMVersion <$> o .: "version")
5110+instance FromJSON JVMVersion where
5111+ parseJSON (String t) =
5112+ JVMVersion <$> parseJSON (String (T.replace "_" "." t))
5113+ parseJSON v = JVMVersion <$> parseJSON v
5115+instance FromJSON JVMMemoryInfo where
5116+ parseJSON = withObject "JVMMemoryInfo" parse
5118+ parse o = JVMMemoryInfo <$> o .: "direct_max_in_bytes"
5119+ <*> o .: "non_heap_max_in_bytes"
5120+ <*> o .: "non_heap_init_in_bytes"
5121+ <*> o .: "heap_max_in_bytes"
5122+ <*> o .: "heap_init_in_bytes"
5124+instance FromJSON NodeThreadPoolsInfo where
5125+ parseJSON = withObject "NodeThreadPoolsInfo" parse
5127+ parse o = NodeThreadPoolsInfo <$> o .: "refresh"
5128+ <*> o .: "management"
5129+ <*> o .: "percolate"
5130+ <*> o .:? "listener"
5131+ <*> o .:? "fetch_shard_started"
5135+ <*> o .: "optimize"
5139+ <*> o .: "snapshot"
5141+ <*> o .:? "fetch_shard_store"
5145+instance FromJSON NodeThreadPoolInfo where
5146+ parseJSON = withObject "NodeThreadPoolInfo" parse
5149+ ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
5150+ NodeThreadPoolInfo <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
5156+parseStringInterval :: (Monad m) => String -> m NominalDiffTime
5157+parseStringInterval s = case span isNumber s of
5158+ ("", _) -> fail "Invalid interval"
5159+ (nS, unitS) -> case (readMay nS, readMay unitS) of
5160+ (Just n, Just unit) -> return (fromInteger (n * unitNDT unit))
5161+ (Nothing, _) -> fail "Invalid interval number"
5162+ (_, Nothing) -> fail "Invalid interval unit"
5164+ unitNDT Seconds = 1
5165+ unitNDT Minutes = 60
5166+ unitNDT Hours = 60 * 60
5167+ unitNDT Days = 24 * 60 * 60
5168+ unitNDT Weeks = 7 * 24 * 60 * 60
5170+instance FromJSON ThreadPoolSize where
5171+ parseJSON v = parseAsNumber v <|> parseAsString v
5173+ parseAsNumber = parseAsInt <=< parseJSON
5174+ parseAsInt (-1) = return ThreadPoolUnbounded
5176+ | n >= 0 = return (ThreadPoolBounded n)
5177+ | otherwise = fail "Thread pool size must be >= -1."
5178+ parseAsString = withText "ThreadPoolSize" $ \t ->
5179+ case first (readMay . T.unpack) (T.span isNumber t) of
5180+ (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
5181+ (Just n, "") -> return (ThreadPoolBounded n)
5182+ _ -> fail ("Invalid thread pool size " <> T.unpack t)
5184+instance FromJSON ThreadPoolType where
5185+ parseJSON = withText "ThreadPoolType" parse
5187+ parse "scaling" = return ThreadPoolScaling
5188+ parse "fixed" = return ThreadPoolFixed
5189+ parse "cached" = return ThreadPoolCached
5190+ parse e = fail ("Unexpected thread pool type" <> T.unpack e)
5192+instance FromJSON NodeTransportInfo where
5193+ parseJSON = withObject "NodeTransportInfo" parse
5195+ parse o = NodeTransportInfo <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
5196+ <*> parseJSON (Object o)
5197+ parseProfiles (Object o) | HM.null o = return []
5198+ parseProfiles v@(Array _) = parseJSON v
5199+ parseProfiles Null = return []
5200+ parseProfiles _ = fail "Could not parse profiles"
5202+instance FromJSON NodeNetworkInfo where
5203+ parseJSON = withObject "NodeNetworkInfo" parse
5205+ parse o = NodeNetworkInfo <$> o .: "primary_interface"
5206+ <*> (unMS <$> o .: "refresh_interval_in_millis")
5209+instance FromJSON NodeNetworkInterface where
5210+ parseJSON = withObject "NodeNetworkInterface" parse
5212+ parse o = NodeNetworkInterface <$> o .: "mac_address"