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