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