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